From e6ceea35534100f54eebfbbf8167ebcdf557bdb8 Mon Sep 17 00:00:00 2001 From: ilja Date: Sun, 23 Oct 2022 12:33:31 +0200 Subject: [PATCH 001/631] fix flaky participation_test.exs It was tested if the updated_at after marking as "read" was equal as the updated_at at insertion, but that seems wrong. Firstly, if a record is updated, you expect the updated_at to also update. Secondly, the insert and update happen almost at the same time, so it's flaky regardless. Here I make sure it has a much older updated_at during insert so we can clealy see the effect after update. I also check that the updated_at is actually updated because I expect that this is the expected behaviour and it's also the current behaviour. --- test/pleroma/conversation/participation_test.exs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/pleroma/conversation/participation_test.exs b/test/pleroma/conversation/participation_test.exs index a25e17c95..2bf57f539 100644 --- a/test/pleroma/conversation/participation_test.exs +++ b/test/pleroma/conversation/participation_test.exs @@ -122,11 +122,11 @@ test "recreating an existing participations sets it to unread" do end test "it marks a participation as read" do - participation = insert(:participation, %{read: false}) + participation = insert(:participation, %{updated_at: ~N[2017-07-17 17:09:58], read: false}) {:ok, updated_participation} = Participation.mark_as_read(participation) assert updated_participation.read - assert updated_participation.updated_at == participation.updated_at + assert :gt = NaiveDateTime.compare(updated_participation.updated_at, participation.updated_at) end test "it marks a participation as unread" do From a59d3109829e37057fb84eef7580605c74983bbd Mon Sep 17 00:00:00 2001 From: Ilja <672-ilja@users.noreply.git.pleroma.social> Date: Wed, 24 Aug 2022 15:24:57 +0000 Subject: [PATCH 002/631] fix flaky test filter_controller_test.exs:200 --- .../controllers/filter_controller_test.exs | 59 ++++++++----------- 1 file changed, 25 insertions(+), 34 deletions(-) diff --git a/test/pleroma/web/mastodon_api/controllers/filter_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/filter_controller_test.exs index 66f7ed579..99f037483 100644 --- a/test/pleroma/web/mastodon_api/controllers/filter_controller_test.exs +++ b/test/pleroma/web/mastodon_api/controllers/filter_controller_test.exs @@ -3,9 +3,10 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.MastodonAPI.FilterControllerTest do - use Pleroma.Web.ConnCase, async: true + use Pleroma.Web.ConnCase, async: false use Oban.Testing, repo: Pleroma.Repo + import Mock import Pleroma.Factory alias Pleroma.Filter @@ -53,25 +54,20 @@ test "a filter with expires_in", %{conn: conn, user: user} do in_seconds = 600 response = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/filters", %{ - "phrase" => "knights", - context: ["home"], - expires_in: in_seconds - }) - |> json_response_and_validate_schema(200) + with_mock NaiveDateTime, [:passthrough], utc_now: fn -> ~N[2017-03-17 17:09:58] end do + conn + |> put_req_header("content-type", "application/json") + |> post("/api/v1/filters", %{ + "phrase" => "knights", + context: ["home"], + expires_in: in_seconds + }) + |> json_response_and_validate_schema(200) + end assert response["irreversible"] == false - expires_at = - NaiveDateTime.utc_now() - |> NaiveDateTime.add(in_seconds) - - assert NaiveDateTime.diff( - NaiveDateTime.from_iso8601!(response["expires_at"]), - expires_at - ) < 5 + assert response["expires_at"] == "2017-03-17T17:19:58.000Z" filter = Filter.get(response["id"], user) @@ -183,26 +179,21 @@ test "with adding expires_at", %{conn: conn, user: user} do in_seconds = 600 response = - conn - |> put_req_header("content-type", "application/json") - |> put("/api/v1/filters/#{filter.filter_id}", %{ - phrase: "nii", - context: ["public"], - expires_in: in_seconds, - irreversible: true - }) - |> json_response_and_validate_schema(200) + with_mock NaiveDateTime, [:passthrough], utc_now: fn -> ~N[2017-03-17 17:09:58] end do + conn + |> put_req_header("content-type", "application/json") + |> put("/api/v1/filters/#{filter.filter_id}", %{ + phrase: "nii", + context: ["public"], + expires_in: in_seconds, + irreversible: true + }) + |> json_response_and_validate_schema(200) + end assert response["irreversible"] == true - expected_time = - NaiveDateTime.utc_now() - |> NaiveDateTime.add(in_seconds) - - assert NaiveDateTime.diff( - NaiveDateTime.from_iso8601!(response["expires_at"]), - expected_time - ) < 5 + assert response["expires_at"] == "2017-03-17T17:19:58.000Z" filter = Filter.get(response["id"], user) From 3562eaeedc14d6b410da86651c0fce0e3032ff66 Mon Sep 17 00:00:00 2001 From: ilja Date: Sun, 23 Oct 2022 13:31:01 +0200 Subject: [PATCH 003/631] fix flaky test_user_relationship_test.exs:81 The problem was double. On the one hand, the function didn't actually return what was in the DB. On the other hand the test was flaky because it used NaiveDateTime.utc_now() so test could fail or pass depending on a difference of microseconds. Both are fixed now. --- lib/pleroma/user_relationship.ex | 5 +++-- test/pleroma/user_relationship_test.exs | 10 ++++++++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/lib/pleroma/user_relationship.ex b/lib/pleroma/user_relationship.ex index a467e9b65..2f77697d4 100644 --- a/lib/pleroma/user_relationship.ex +++ b/lib/pleroma/user_relationship.ex @@ -67,8 +67,9 @@ def create(relationship_type, %User{} = source, %User{} = target) do target_id: target.id }) |> Repo.insert( - on_conflict: {:replace_all_except, [:id]}, - conflict_target: [:source_id, :relationship_type, :target_id] + on_conflict: {:replace_all_except, [:id, :inserted_at]}, + conflict_target: [:source_id, :relationship_type, :target_id], + returning: true ) end diff --git a/test/pleroma/user_relationship_test.exs b/test/pleroma/user_relationship_test.exs index b2b074607..b3a0dbe37 100644 --- a/test/pleroma/user_relationship_test.exs +++ b/test/pleroma/user_relationship_test.exs @@ -5,8 +5,9 @@ defmodule Pleroma.UserRelationshipTest do alias Pleroma.UserRelationship - use Pleroma.DataCase, async: true + use Pleroma.DataCase, async: false + import Mock import Pleroma.Factory describe "*_exists?/2" do @@ -79,7 +80,12 @@ test "creates user relationship record if it doesn't exist", %{users: [user1, us end test "if record already exists, returns it", %{users: [user1, user2]} do - user_block = UserRelationship.create_block(user1, user2) + user_block = + with_mock NaiveDateTime, [:passthrough], utc_now: fn -> ~N[2017-03-17 17:09:58] end do + {:ok, %{inserted_at: ~N[2017-03-17 17:09:58]}} = + UserRelationship.create_block(user1, user2) + end + assert user_block == UserRelationship.create_block(user1, user2) end end From 6486211064027179a89478bf2b520ad144947a0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= Date: Sat, 1 Oct 2022 23:28:02 +0200 Subject: [PATCH 004/631] Push.Impl: support edits MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: marcin mikołajczak --- lib/pleroma/web/push/impl.ex | 12 +++++++++++- test/pleroma/web/push/impl_test.exs | 15 +++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/lib/pleroma/web/push/impl.ex b/lib/pleroma/web/push/impl.ex index c30a39e94..e103cafc2 100644 --- a/lib/pleroma/web/push/impl.ex +++ b/lib/pleroma/web/push/impl.ex @@ -16,7 +16,7 @@ defmodule Pleroma.Web.Push.Impl do require Logger import Ecto.Query - @types ["Create", "Follow", "Announce", "Like", "Move", "EmojiReact"] + @types ["Create", "Follow", "Announce", "Like", "Move", "EmojiReact", "Update"] @doc "Performs sending notifications for user subscriptions" @spec perform(Notification.t()) :: list(any) | :error | {:error, :unknown_type} @@ -167,6 +167,15 @@ def format_body( end end + def format_body( + %{activity: %{data: %{"type" => "Update"}}}, + actor, + _object, + _mastodon_type + ) do + "@#{actor.nickname} edited a status" + end + def format_title(activity, mastodon_type \\ nil) def format_title(%{activity: %{data: %{"directMessage" => true}}}, _mastodon_type) do @@ -180,6 +189,7 @@ def format_title(%{type: type}, mastodon_type) do "follow_request" -> "New Follow Request" "reblog" -> "New Repeat" "favourite" -> "New Favorite" + "update" -> "New Update" "pleroma:emoji_reaction" -> "New Reaction" type -> "New #{String.capitalize(type || "event")}" end diff --git a/test/pleroma/web/push/impl_test.exs b/test/pleroma/web/push/impl_test.exs index 9100433ae..326872ccd 100644 --- a/test/pleroma/web/push/impl_test.exs +++ b/test/pleroma/web/push/impl_test.exs @@ -200,6 +200,21 @@ test "renders title and body for pleroma:emoji_reaction activity" do "New Reaction" end + test "renders title and body for update activity" do + user = insert(:user) + + {:ok, activity} = CommonAPI.post(user, %{status: "lorem ipsum"}) + + {:ok, activity} = CommonAPI.update(user, activity, %{status: "edited status"}) + object = Object.normalize(activity, fetch: false) + + assert Impl.format_body(%{activity: activity, type: "update"}, user, object) == + "@#{user.nickname} edited a status" + + assert Impl.format_title(%{activity: activity, type: "update"}) == + "New Update" + end + test "renders title for create activity with direct visibility" do user = insert(:user, nickname: "Bob") From 4d9ca8909d75cf7e3b2d361b23fc0ef30bb25829 Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Sat, 29 Oct 2022 21:57:50 +0100 Subject: [PATCH 005/631] Add StopGifs to description --- config/description.exs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/config/description.exs b/config/description.exs index a17897b98..d7bece75b 100644 --- a/config/description.exs +++ b/config/description.exs @@ -1389,6 +1389,12 @@ label: "Render misskey markdown", type: :boolean, description: "Whether to render Misskey-flavoured markdown" + }, + %{ + key: :stopGifs, + label: "Pause animated images until you hover on them", + type: :boolean, + description: "Whether to play gifs by default" } ] }, From d782140e2b1a7cedaaafa6c55713928d7117bddc Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Sat, 29 Oct 2022 22:08:18 +0100 Subject: [PATCH 006/631] Reword stop gifs --- config/description.exs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/description.exs b/config/description.exs index d7bece75b..1ff0a582b 100644 --- a/config/description.exs +++ b/config/description.exs @@ -1392,9 +1392,9 @@ }, %{ key: :stopGifs, - label: "Pause animated images until you hover on them", + label: "Stop Gifs", type: :boolean, - description: "Whether to play gifs by default" + description: "Whether to pause animated images until they're hovered on" } ] }, From cbc693f83213b389b4fb7c7d892deff8edc2da7d Mon Sep 17 00:00:00 2001 From: nullobsi Date: Tue, 1 Nov 2022 14:17:55 +0000 Subject: [PATCH 007/631] Fix LDAP user registration (#229) Simple fix for LDAP user registration. I'm not sure what changed but I managed to get Akkoma running in a debug session and figured out it was missing a match for an extra value at the end. I don't know Elixir all that well so I'm not sure if this was the correct way to do it... but it works. :) Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma/pulls/229 Co-authored-by: nullobsi Co-committed-by: nullobsi --- lib/pleroma/web/auth/ldap_authenticator.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pleroma/web/auth/ldap_authenticator.ex b/lib/pleroma/web/auth/ldap_authenticator.ex index f77e8d203..ccf4b4104 100644 --- a/lib/pleroma/web/auth/ldap_authenticator.ex +++ b/lib/pleroma/web/auth/ldap_authenticator.ex @@ -102,7 +102,7 @@ defp register_user(connection, base, uid, name) do {:scope, :eldap.wholeSubtree()}, {:timeout, @search_timeout} ]) do - {:ok, {:eldap_search_result, [{:eldap_entry, _, attributes}], _}} -> + {:ok, {:eldap_search_result, [{:eldap_entry, _, attributes}], _, _}} -> params = %{ name: name, nickname: name, From 1bb8b763118c4aff169cebf75b1eb628143d3ab7 Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Tue, 1 Nov 2022 14:21:35 +0000 Subject: [PATCH 008/631] Fix tests in ldap registration --- CHANGELOG.md | 3 +++ test/pleroma/web/o_auth/ldap_authorization_test.exs | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b3e4f371f..34c09cd65 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Follows no longer override domain blocks, a domain block is final - Deletes are now the lowest priority to publish and will be handled after creates +## Fixed +- Registrations via ldap are now compatible with the latest OTP24 + ## 2022.10 ### Added diff --git a/test/pleroma/web/o_auth/ldap_authorization_test.exs b/test/pleroma/web/o_auth/ldap_authorization_test.exs index 61b9ce6b7..c8a1d65ab 100644 --- a/test/pleroma/web/o_auth/ldap_authorization_test.exs +++ b/test/pleroma/web/o_auth/ldap_authorization_test.exs @@ -71,7 +71,7 @@ test "creates a new user after successful LDAP authorization" do equalityMatch: fn _type, _value -> :ok end, wholeSubtree: fn -> :ok end, search: fn _connection, _options -> - {:ok, {:eldap_search_result, [{:eldap_entry, '', []}], []}} + {:ok, {:eldap_search_result, [{:eldap_entry, '', []}], [], []}} end, close: fn _connection -> send(self(), :close_connection) From f1dfd76b988eeba78404a267a96ae3ad31e25040 Mon Sep 17 00:00:00 2001 From: ilja Date: Tue, 1 Nov 2022 14:25:54 +0000 Subject: [PATCH 009/631] Fix rate_limiter_test.exs test "it restricts based on config values" (#233) Fixes one of the 'erratic' tests It used a timer to sleep. But time also goes on when doing other things, so depending on hardware, the timings could be off. I slightly changed the tests so we still test what we functionally want. Instead of waiting until the cache expires I now have a function to expire the test and use that. That means we're not testing any more if the cache really expires after a certain amount of time, but that's the responsability of the dependency imo, so shouldn't be a problem. I also changed `Pleroma.Web.Endpoint, :http, :ip` in the tests to `127.0.0.1` Currently it was set to 8.8.8.8, but I see no reason for that and, while I assume that no calls are made to it, it may come over as weird or suspicious to people. Co-authored-by: Ilja Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma/pulls/233 Co-authored-by: ilja Co-committed-by: ilja --- test/pleroma/web/plugs/rate_limiter_test.exs | 44 +++++++++++++------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/test/pleroma/web/plugs/rate_limiter_test.exs b/test/pleroma/web/plugs/rate_limiter_test.exs index b7cfde1f7..83a47ea30 100644 --- a/test/pleroma/web/plugs/rate_limiter_test.exs +++ b/test/pleroma/web/plugs/rate_limiter_test.exs @@ -48,38 +48,42 @@ test "it is enabled if remote_ip_found flag doesn't exist" do refute RateLimiter.disabled?(build_conn()) end - @tag :erratic test "it restricts based on config values" do limiter_name = :test_plug_opts scale = 80 limit = 5 - clear_config([Pleroma.Web.Endpoint, :http, :ip], {8, 8, 8, 8}) + clear_config([Pleroma.Web.Endpoint, :http, :ip], {127, 0, 0, 1}) clear_config([:rate_limit, limiter_name], {scale, limit}) plug_opts = RateLimiter.init(name: limiter_name) conn = build_conn(:get, "/") - for i <- 1..5 do - conn = RateLimiter.call(conn, plug_opts) - assert {^i, _} = RateLimiter.inspect_bucket(conn, limiter_name, plug_opts) - Process.sleep(10) + for _ <- 1..5 do + conn_limited = RateLimiter.call(conn, plug_opts) + + refute conn_limited.status == Conn.Status.code(:too_many_requests) + refute conn_limited.resp_body + refute conn_limited.halted end - conn = RateLimiter.call(conn, plug_opts) - assert %{"error" => "Throttled"} = ConnTest.json_response(conn, :too_many_requests) - assert conn.halted + conn_limited = RateLimiter.call(conn, plug_opts) + assert %{"error" => "Throttled"} = ConnTest.json_response(conn_limited, :too_many_requests) + assert conn_limited.halted - Process.sleep(50) + expire_ttl(conn, limiter_name) - conn = build_conn(:get, "/") + for _ <- 1..5 do + conn_limited = RateLimiter.call(conn, plug_opts) - conn = RateLimiter.call(conn, plug_opts) - assert {1, 4} = RateLimiter.inspect_bucket(conn, limiter_name, plug_opts) + refute conn_limited.status == Conn.Status.code(:too_many_requests) + refute conn_limited.resp_body + refute conn_limited.halted + end - refute conn.status == Conn.Status.code(:too_many_requests) - refute conn.resp_body - refute conn.halted + conn_limited = RateLimiter.call(conn, plug_opts) + assert %{"error" => "Throttled"} = ConnTest.json_response(conn_limited, :too_many_requests) + assert conn_limited.halted end describe "options" do @@ -263,4 +267,12 @@ test "doesn't crash due to a race condition when multiple requests are made at t refute {:err, :not_found} == RateLimiter.inspect_bucket(conn, limiter_name, opts) end + + def expire_ttl(%{remote_ip: remote_ip} = _conn, bucket_name_root) do + bucket_name = "anon:#{bucket_name_root}" |> String.to_atom() + key_name = "ip::#{remote_ip |> Tuple.to_list() |> Enum.join(".")}" + + {:ok, bucket_value} = Cachex.get(bucket_name, key_name) + Cachex.put(bucket_name, key_name, bucket_value, ttl: -1) + end end From be5044f785e562c4978121b74bce03f131b827e3 Mon Sep 17 00:00:00 2001 From: ilja Date: Tue, 1 Nov 2022 14:31:29 +0000 Subject: [PATCH 010/631] fix_flaky_transfer_task_test.exs (#237) There were async calls happening, so they weren't always finished when assert happened. I also fixed some bugs in the erratic tests that were introduced when removing :shout.:shout is a key where restart is needed, and was changed in the test to use :rate_limit (which also requires a restart). But there was a bug in the syntax that didn't get caught because the test was tagged as erratic and therefor didn't fail. Here I fixed it. During compilation, we had a warning `:logger is used by the current application but the current application does not depend on :logger` which is now fixed as well (see commit message for complete stacktrace). Co-authored-by: Ilja Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma/pulls/237 Co-authored-by: ilja Co-committed-by: ilja --- restarter/lib/pleroma.ex | 12 ++++ restarter/mix.exs | 3 +- test/pleroma/config/transfer_task_test.exs | 69 ++++++++++++++++++---- 3 files changed, 70 insertions(+), 14 deletions(-) diff --git a/restarter/lib/pleroma.ex b/restarter/lib/pleroma.ex index 149a569ce..a7186cec4 100644 --- a/restarter/lib/pleroma.ex +++ b/restarter/lib/pleroma.ex @@ -61,6 +61,12 @@ def handle_cast(:refresh, _state) do {:noreply, @init_state} end + # Don't actually restart during tests. + # We just check if the correct call has been done. + # If we actually restart, we get errors during the tests like + # (RuntimeError) could not lookup Ecto repo Pleroma.Repo because it was not started or + # it does not exist + # See tests in Pleroma.Config.TransferTaskTest def handle_cast({:restart, :test, _}, state) do Logger.debug("pleroma manually restarted") {:noreply, Map.put(state, :need_reboot, false)} @@ -74,6 +80,12 @@ def handle_cast({:restart, _, delay}, state) do def handle_cast({:after_boot, _}, %{after_boot: true} = state), do: {:noreply, state} + # Don't actually restart during tests. + # We just check if the correct call has been done. + # If we actually restart, we get errors during the tests like + # (RuntimeError) could not lookup Ecto repo Pleroma.Repo because it was not started or + # it does not exist + # See tests in Pleroma.Config.TransferTaskTest def handle_cast({:after_boot, :test}, state) do Logger.debug("pleroma restarted after boot") state = %{state | after_boot: true, rebooted: true} diff --git a/restarter/mix.exs b/restarter/mix.exs index b0908aece..9f26f5f64 100644 --- a/restarter/mix.exs +++ b/restarter/mix.exs @@ -13,7 +13,8 @@ def project do def application do [ - mod: {Restarter, []} + mod: {Restarter, []}, + extra_applications: [:logger] ] end diff --git a/test/pleroma/config/transfer_task_test.exs b/test/pleroma/config/transfer_task_test.exs index 30cb92fa7..988214eb1 100644 --- a/test/pleroma/config/transfer_task_test.exs +++ b/test/pleroma/config/transfer_task_test.exs @@ -119,44 +119,87 @@ test "transfer config values with full subkey update" do describe "pleroma restart" do setup do - on_exit(fn -> Restarter.Pleroma.refresh() end) + on_exit(fn -> + Restarter.Pleroma.refresh() + + # Restarter.Pleroma.refresh/0 is an asynchronous call. + # A GenServer will first finish the previous call before starting a new one. + # Here we do a synchronous call. + # That way we are sure that the previous call has finished before we continue. + # See https://stackoverflow.com/questions/51361856/how-to-use-task-await-with-genserver + Restarter.Pleroma.rebooted?() + end) end - @tag :erratic test "don't restart if no reboot time settings were changed" do clear_config(:emoji) insert(:config, key: :emoji, value: [groups: [a: 1, b: 2]]) refute String.contains?( - capture_log(fn -> TransferTask.start_link([]) end), + capture_log(fn -> + TransferTask.start_link([]) + + # TransferTask.start_link/1 is an asynchronous call. + # A GenServer will first finish the previous call before starting a new one. + # Here we do a synchronous call. + # That way we are sure that the previous call has finished before we continue. + Restarter.Pleroma.rebooted?() + end), "pleroma restarted" ) end - @tag :erratic test "on reboot time key" do - clear_config([:pleroma, :rate_limit]) - insert(:config, key: {:pleroma, :rate_limit}, value: [enabled: false]) - assert capture_log(fn -> TransferTask.start_link([]) end) =~ "pleroma restarted" + clear_config(:rate_limit) + insert(:config, key: :rate_limit, value: [enabled: false]) + + # Note that we don't actually restart Pleroma. + # See module Restarter.Pleroma + assert capture_log(fn -> + TransferTask.start_link([]) + + # TransferTask.start_link/1 is an asynchronous call. + # A GenServer will first finish the previous call before starting a new one. + # Here we do a synchronous call. + # That way we are sure that the previous call has finished before we continue. + Restarter.Pleroma.rebooted?() + end) =~ "pleroma restarted" end - @tag :erratic test "on reboot time subkey" do clear_config(Pleroma.Captcha) insert(:config, key: Pleroma.Captcha, value: [seconds_valid: 60]) - assert capture_log(fn -> TransferTask.start_link([]) end) =~ "pleroma restarted" + + # Note that we don't actually restart Pleroma. + # See module Restarter.Pleroma + assert capture_log(fn -> + TransferTask.start_link([]) + + # TransferTask.start_link/1 is an asynchronous call. + # A GenServer will first finish the previous call before starting a new one. + # Here we do a synchronous call. + # That way we are sure that the previous call has finished before we continue. + Restarter.Pleroma.rebooted?() + end) =~ "pleroma restarted" end - @tag :erratic test "don't restart pleroma on reboot time key and subkey if there is false flag" do - clear_config([:pleroma, :rate_limit]) + clear_config(:rate_limit) clear_config(Pleroma.Captcha) - insert(:config, key: {:pleroma, :rate_limit}, value: [enabled: false]) + insert(:config, key: :rate_limit, value: [enabled: false]) insert(:config, key: Pleroma.Captcha, value: [seconds_valid: 60]) refute String.contains?( - capture_log(fn -> TransferTask.load_and_update_env([], false) end), + capture_log(fn -> + TransferTask.load_and_update_env([], false) + + # TransferTask.start_link/1 is an asynchronous call. + # A GenServer will first finish the previous call before starting a new one. + # Here we do a synchronous call. + # That way we are sure that the previous call has finished before we continue. + Restarter.Pleroma.rebooted?() + end), "pleroma restarted" ) end From 9682ec4c5f7e29e937c7d23ae11e274b46b8e80e Mon Sep 17 00:00:00 2001 From: Norm Date: Tue, 1 Nov 2022 20:52:17 +0000 Subject: [PATCH 011/631] Change default instance name to "Akkoma" This was left at "Pleroma" for some reason. --- config/config.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/config.exs b/config/config.exs index 5eb82cd33..1af037051 100644 --- a/config/config.exs +++ b/config/config.exs @@ -185,7 +185,7 @@ adapter: [] config :pleroma, :instance, - name: "Pleroma", + name: "Akkoma", email: "example@example.com", notify_email: "noreply@example.com", description: "Akkoma: The cooler fediverse server", From 7cfce562a9b43562bdc59effcc44d0396f618aee Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Wed, 2 Nov 2022 22:38:02 +0000 Subject: [PATCH 012/631] Add default favicon Fixes pleroma-fe#185 --- priv/static/favicon.png | Bin 0 -> 7132 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 priv/static/favicon.png diff --git a/priv/static/favicon.png b/priv/static/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..287c75bfafa195f66b769066d3b13a9dba88e40e GIT binary patch literal 7132 zcmV<28zbb2P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D02p*dSaefwW^{L9 za%BK;VQFr3E^cLXAT%y8E;VI^GGzb&8%;?>K~#8N?c5ElWmRBsRe8UX^l}EQ>~g%O;c!1X=_t!f%G(sH_g>z;MqzUQ6$HS-<_c#}2vzH|54XYc>|um4(mpL1tvjb1M) zc4o0p7rXBTFL+_YcG+dOX3tk1+#GuFDb1#h7dKnacyF`q><={;ocrPCP1}C6dCP@2 zjoDk@{M(&rxA}y($GLm$c|`NFm;6HWiaic$_I~w-=D__=Z`L1iQFH8ucZ3~(>{ZPh zj(b;U{$`stUOBf7^`URq*>|6l;`%@PGdne9e(b(tA1=18*wglUaj^vX`^92F1_q=P zkAGWp)|u~b-hBQ?n~N^Eu`_?a>AV}73(xyV7~mau?2J?1-5kCC+yHp@m+u#5vWFjf zK}@~|BtaPg`_5IhKKQRc`qFUnZoBRkL@INAqS%*;omgy5UoR}Sq1dg(I*>6BP-mWY zZGeca0b&8O2DcBg&!_(4RRz#9q7Tjj_Q4086_czdJ^~gShe28ktFM3b`b#3ZcHU{1 zWcfFXA>5k0URmtwV)qv7KtASm=Z~@2dmr31z}HL`1sDuu6X~;fEttDKmZ1BLB^NQk8!=Wr5`Ne{U&@MjaqwI$#Zcw4E6_+KlwQ?Z3#WaIW? zPwH&l-bV#sDFs8o)|T4LF*H3TgWjbkKN~@=%^b`{LT{@SW#K{<3Vq&IjPOU8s1(lL z@_~ie3}^{3*=#_vxdF1F!9N?#Tu34PZUI*cD~o5oguuncLZ5X&V=YAH(PozIjz8{~ zLz|y#Z0_5DoG6E9Rwsadd$FjUfn;HVrECb;+EO;o-TE6*X*eI)y#8DSxi<3?wIUdH z#pJn(FSJ*2JX9?7_2iST7_oE?*+`(3bO#>rhOW}ED0!{}&63^b+)4>$7<^%L2Q)TH zgmVL3+Gy(>Ni=1{AOPJT*mKp)RfW}-f~vO_uau65cm&Xr+PsNS8xmvF$hjiI1)mRW z?wdKwOE4&Svay${Loy7F9s_!gM3`DG5xRid`T3yFlWnvxlPFs$8GFf?QFQ>Tla4un z#%N~ilx&PPp+;rh^Al(`0^6#x-Kgqb*74T!k<7@zBGOR;Py@pKsss;VSj z*6-HwQAd-3d6Oa8_$knn4Gwf$qyt)scT=$^QQa~ccyra!Z9C3c3H0#ApKq2D3L9Xn zJRY{vIrz1kW8Y$4pt0W~CzIh%fnI4Nu&<1I8`$^Cl;~o}(0%7tm(alKEbpEkjUL^MWv)5RvK@Qo^2c&T5@2Jt zRgUCHd+o}R2b)cOzyWQyFL&;8!LpW<=>zLpk`CDtQJifYY5sQH_xcA z__ZWRZLY=n1=rZvPTN+@^AGl|qdIXH2FPjtHc1lz#_9t-3OfcIASJl_yynnm!}=qe z3(kIH^VSQuHS1ozceC4zUes(pI^k zTzkc@G`D@`6V2cM?O!zi@h^YZ{P6yNiocIK^pF7c>MdtC*PVNQyaOEgK3{R#8O>#z zPmaHjf9*ldfv?)L+2f^q#5`OB2zlMLV)`_&^JS0Zaas;!a-w1}NGFa4H{AK6wmjL< zBLP4@V88vFw_SWu^SMvl(tPKeUu*vNzrNQr|NVoe`O(A6_QQwbdu=iKy=R}-Ty@5l z0CcaHzO1?Agp5{nl4 zUF-DfuweNPx&$I(Fd4{y{-r-`9{IO>$AE1fePG-Q_)k3eug&}4U7S<^#$cdgx~M#I z-97=nV^|JspMSM=%00H@}hTFB9aXm%Hczw#p;J4lt|X{bX}WhJ;KK zK6T5D%OGQNAKtzWJO8BFbkq?YyD|6YcHTLRq$H~Wp5~agJ_DV$8v{*Wj@;D& zd~UF_EL_c{xITcby5K~s*G(Ia2{s3V0X+mP>odGKgno+#Oa>nL0G-McQ8MXYya4T zAteAN55N{B9KeY{oCJ0nY0(DDRWATv4RWOtm@iN#y(GwoF?+S-!@x~IsEQVSpLE>D z=AOU)$_VHJS`F@)6$XF%uCGQ_@;7(<(Xvy#7rXv_*96!Y3hcuUJfQjb%{N4QjCXt% z;G`yHh>injM+uhEL5fGPu6)^Yy&V{`^^SXZ6iWIbM=#%X*U(cna{xCBXja;g8Bq{& zlTy=yo=Gy94eUF<@R=}R0}y+MK(38L^uckfQR3#g`Wity{&H)~&E6*@#~t_XIM6gv zm;ytcoXi{pwr_2l-}>Nn%{g1PG~fN!UCUq(Xtt!tk)(<2h@O;^exe*Q?JSJOwgBG@7^}DU0^Wt7WC&=hJB*XaLI$SD2ao{-H1DJ% z7!Bx5q&~N-rvIXbGcDaM;p6)Pb}o2mFaU?Z9WqiPQj8yA%x7`pjq;Ve*FN*tz5HCm z4EH$rmx zo@yjbTje78BLUmDA2b3R7Am_yxqW$N8XAc6NJ*{RH6}yzo@9xi2rt-n zVB1!`3Hsab#gTkiY3hT9VulF~KBtTsuIpus#_?_!N5UWG_9Cf#TQ);ZKs0&s zQm!8p;wT^_7=Vd-JQ-UXkQtEsQd70T@Oz5Ba~!}`L&hVbLRG>MtdhGzy=yXfKHc9G}&T70^pDfa=-^%xNont!PuD(wxsaedyDj49Y;Q{MCWUeKG^W4P1a=LDDgXL^qDba>XwA;u} z7Q1?>{UbztdDCUKCZ$t22xtaWmsOZeQnI!ND7LV?E8dlA?XtWEYF+~jsqjAZeK@Tx zAyZN~9lMig0FU#@TxsXCAcnduwg+v@>cR2e(AV?TCdv?$CazBwTc4L2WA zJS(qpgzu~R`p#nOmfSV>&<(J&5}73<+GLprIFg`-O|Y?AW;Z}Oh_!&lAfbrSs|s{& zLv8vdiVEA2!1&BTlBCS_w$E%?0R@NM|f?5}!)1N52&FIGG13_uc39b0vV0 zBSu-)g(VN~^>Wxdt)qFC%O*yvF$trEbFgd(h)D*>WF}eg-bxRhO^bHfM*C^<)B=tK zKmoXfiP;jW(hu0)fh~H?Y1Uo|{Ho0-KU{LxYu!>lk?NsJOl8yLBs)@l@U#KcU}xE9 zfCj9>FnIt=Vxf)m0u87t^d&?3pVf+xCrvaMBfWF3@3i6IxSsPTU9%-ZRxIR&q|kJ8 z0=78<+uzteT}npPT(uwK>9TFbZe8*WUjpu7O61CIXS+>a?Lo(s~SdF&*uDD(qo9n1pFq;$Uv*-l2 zxh1oGo_2rIG1$SV0IUj8Uw^*X;{kR)H0c3%zdXR&m1W?v$8wdJUI(`Kx*EykxR7MD zOcvVMCA?KLoCe5`+;DUA2cNsGx#Lg&viZi{-)g@7&-XXq`~H764?psFn9q*+PMhET z_^0DM;Bx}dV?1r7jF~aEq!2CSBDWlJBTcksE<#AS^rZyYy^`j}05iPe{%d}<698zYS8WV56RWWWGeV$%1fO(z6!zZ z(2y8R-o>#v6QN@{5XU&cV1;E&pq|i>l{WNT$lEZwut>lcKJ@F&H$M4$@&1l;wuUT- z6zs;@n$GBu;yljNul~u4B)9@_pNrA`T1Jou*g!_8Nm2srN%26<`k~OdVjk3*;S-)MjA?*krrGXd~Iggj5AJuzf2Nrjq~x#Pyf{Qu7a={r%?O zZ~t=hz#rch=5L_8<{LL17r@i))NFvJrEF-UEr9j;XE%Se`OX(V8}E)gUou=lhVnPL zsS{)kHZsXoR>u9kl8pYg3JKFD{~MFLm>0(Le=mf}M3Wpbf^Ld?z_#&%{ln zwDKKB1C4_KngHK-+vhv0k0sjy$gsXPU^sr```#76a@74_{$ke$Cw}#oj|JeayJCz* zx3ly!rasu_XWk-Nv^dQ(wvSc29=P89hPp2+tB?4GlnBS+@ zNy1dUF2`v!UB_qu0s=5K(6!Z|v1|)ahPnMVb-V1tbzIMNm5WiI=Qs=42p}?Y1zCfg zBqOEdbCf7YE9#UGVCPTKkrvP}od`Co6DB~j$j5F2k#sOv(y<^gm|V;#pJuTdgD?ye z`=HD+ZKv7LIceF(b!mCXNmeK=3CzhnkS8mU1Un-e2AL@RaxV9-hk#~N!Dax@A1v`C z_PQudlStIB7>vmV=R1taU9=S-r}r>rDFB^!48UhRho+R8a5s3K5BNNz%V2$W zve?&bK&wy^X#e#GpxF>+wJpulC{0_XAh4B2N~C(AHhF*-Az2T8niUqAm<^}3l#`m# z33N!I@%QDffQ>jLf+lA*0&GBA#92-I{|&KuUJT>r!MyC&PRD+xC&YpkDJ9IH4IblJ zJ%LHqwi79`zuI@T0oNBJRiwk(V63*Tt;_*gEOwNBSPg8S)zu8pc1K~d2w9ihrCF5S z3U)tjmRLG~bFeLVV+m)Lm2*@twl-HA@a)6#U2Y&*DyIN?Xnf_k=;RPmVF8n1t2(w9 zXl<8h&O+=iVWTZ}=Tl3O3|k{57CY+j(C#7j3|Vm)Spqn%lXcv+#4Ys62H}<8{}|U1ZbGSc*#P=3eg`!4TsEya#d*$fxZb#gES$( z(p7i*9Cy|i035?@&E}S<&$pSjkz7V1=04 zD=e0H%VyI;>~1@-s*GiPkrXVC=Rpd{`V(qEw~Sv1@K%OIjF6YeB(*FH$;&LO>u7So zc{3MTtc=lh%>&p#uB#7o9r{05rWu^_hWe5fpPec<3>NiRGF+W0GxL1*r6y0n$HI3W z9S3*;#yO(JofWKn^zN@U5B}9x0?0H{k)M6XwA0@C@uXDt*}qP0Wo$@+)i5C&v>Mn} zixQ)o0OmU{*eM@yXz$#No?dle5q77!u=D&E8T236{!c)EyI44(06vzOW=%W|6RY-; zE`|bf$VhE;Sha^eA&4V1wL&{n{oTuLaJ2$!)Wp{1PQ>Exf z5=pOehNZ0I^c_d6Kw2OZv#yfo7XH-Y9k8Bhra9( zhKxWxOB&z+YN&&0=Db|+&^Dj5FBj%v8|{|*DvoaBXI_@Cg|$HEY7rL3?!TZ`>gByw zVCQz~JPHu=F5j!z;A#~r(Jt9IvNEzN!ahk)XG5J#Go1t01^WGDNb$7)z8^y*E-a74 z^-O?HUdlC%L2?(}fHp?bCrJW0Wh85DH&S9wQwV9Uq%`(Tiq_M7eJrImrRRW=zzuaY z&GI62+kpLDGa&vh{pPJU6H=|XW7B~SgduQN%Q&@MhrX*)ETS-4L;_l_>4TkHs+lCo zE%w%Puji;A?Z}7nQ6J7a0!zHBj@Ia|}dPf&oKilE0Y1k@~xh$tpHrb&`xS$oPCYFHtPW%=ZilC4Xm^MbA&18iD*z8t}saf7)y7Z@be zIJ^6W1uX9pIFWhywv^ZpyDL1W4r&5sZm`lNaaLU}xmlc`eWJcSLg;vukNv z6;>?kcY+yI3i4XQ(C9>W$1 z7JCdjpLH8*8;&TTORAn$^+2SjPdzvZbbz}n6jh33*9V&e3gD!MWMH%i$>;r2rvZm` zB6ixgvazT3CQB2e8W(djb~#FJ(l2=$VszS4e&7wPFsQ6hYB@=H=nrm^nM^Wv)~=%O zLMMx3JQ$ge20!}P|Hb3JoPfDqS=a}>I6)%CEaT;*`bk!Q1D{j@aZ(;(=9xqh1#(yd zn4rTbbz6QCDcUAc6Vuw98(?QAJSl92VJ1!;t4;tn4Y0nMOomq`+ldowJACd*1F<4(JnXIYF%Ov?= z9oT@y=5}W)K=-BN!bTWQ)455etr9X4$H0oRw%R!-Y~B*AOrUDO$wk!PtyX)tiR5Mj zpfNhnVLp>2ea^FfFh=u4FnDB?Cupevq{LoNfL?L~ypps-7GV1a^<`PhR$v2H1IKlq zNrAVgg<#*bOZ_7e)0Vl+L}hi3?K9M8>;$;lIrO_EP4WTgl%E>tH0Oz!O!h<9W+{~_ zDccFaHuoBAm}H`L<7HA!-M0WcPX;ic8DLYZ(ivHshJF`z&I5SLLu&V|T}8*4YuFw1 z3xfpDJ1{vx;0S1IX)ht|mw zaNZdJbDWqyiPg1MN8dA8oofTj@ys7e$$piQ1SKK$!pFO|zVluKe$Cc%n*Rs+Hy#kR SmkNXc0000 Date: Fri, 4 Nov 2022 09:43:13 +0100 Subject: [PATCH 013/631] Fix typo in CSP Report-To header name The header name was Report-To, not Reply-To. In any case, that's now being changed to the Reporting-Endpoints HTTP Response Header. https://w3c.github.io/reporting/#header https://github.com/w3c/reporting/issues/177 CanIUse says the Report-To header is still supported by current Chrome and friends. https://caniuse.com/mdn-http_headers_report-to It doesn't have any data for the Reporting-Endpoints HTTP header, but this article says Chrome 96 supports it. https://web.dev/reporting-api/ (Even though that's come out one year ago, that's not compatible with Network Error Logging which's still using the Report-To version of the API) Signed-off-by: Thomas Citharel --- lib/pleroma/web/plugs/http_security_plug.ex | 2 +- test/pleroma/web/plugs/http_security_plug_test.exs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/pleroma/web/plugs/http_security_plug.ex b/lib/pleroma/web/plugs/http_security_plug.ex index d1e6cc9d3..3e8e931d1 100644 --- a/lib/pleroma/web/plugs/http_security_plug.ex +++ b/lib/pleroma/web/plugs/http_security_plug.ex @@ -68,7 +68,7 @@ def headers do ] } - [{"reply-to", Jason.encode!(report_group)} | headers] + [{"report-to", Jason.encode!(report_group)} | headers] else headers end diff --git a/test/pleroma/web/plugs/http_security_plug_test.exs b/test/pleroma/web/plugs/http_security_plug_test.exs index 4e7befdd5..eb94cd665 100644 --- a/test/pleroma/web/plugs/http_security_plug_test.exs +++ b/test/pleroma/web/plugs/http_security_plug_test.exs @@ -59,9 +59,9 @@ test "it sends `report-to` & `report-uri` CSP response headers", %{conn: conn} d assert csp =~ ~r|report-uri https://endpoint.com;report-to csp-endpoint;| - [reply_to] = Conn.get_resp_header(conn, "reply-to") + [report_to] = Conn.get_resp_header(conn, "report-to") - assert reply_to == + assert report_to == "{\"endpoints\":[{\"url\":\"https://endpoint.com\"}],\"group\":\"csp-endpoint\",\"max-age\":10886400}" end From ccdf55acff7ff7d29682aab3ccf283b59ad33d26 Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Fri, 4 Nov 2022 18:42:12 +0000 Subject: [PATCH 014/631] Fix instance name in email test --- test/pleroma/emails/user_email_test.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/pleroma/emails/user_email_test.exs b/test/pleroma/emails/user_email_test.exs index 771a9a490..564552004 100644 --- a/test/pleroma/emails/user_email_test.exs +++ b/test/pleroma/emails/user_email_test.exs @@ -27,7 +27,7 @@ test "build user invitation email" do token = %Pleroma.UserInviteToken{token: "test-token"} email = UserEmail.user_invitation_email(user, token, "test@test.com", "Jonh") assert email.from == {config[:name], config[:notify_email]} - assert email.subject == "Invitation to Pleroma" + assert email.subject == "Invitation to Akkoma" assert email.to == [{"Jonh", "test@test.com"}] assert email.html_body =~ From b7e8ce235073ab45db24dfc6c27bc6998b43a200 Mon Sep 17 00:00:00 2001 From: floatingghost Date: Sun, 6 Nov 2022 22:49:39 +0000 Subject: [PATCH 015/631] Scrape instance nodeinfo (#251) Co-authored-by: FloatingGhost Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma/pulls/251 --- config/config.exs | 6 +- config/description.exs | 13 + config/test.exs | 2 + lib/pleroma/application.ex | 3 +- lib/pleroma/instances/instance.ex | 203 +++++++++++---- lib/pleroma/web/activity_pub/side_effects.ex | 9 +- .../web/mastodon_api/views/account_view.ex | 34 ++- .../workers/nodeinfo_fetcher_worker.ex | 18 ++ .../20221020135943_add_nodeinfo.exs | 17 ++ test/pleroma/instances/instance_test.exs | 238 +++++++++++++++--- .../web/activity_pub/side_effects_test.exs | 29 +++ .../mastodon_api/views/account_view_test.exs | 100 +++++++- test/pleroma/web/streamer_test.exs | 2 +- test/support/factory.ex | 16 +- 14 files changed, 575 insertions(+), 115 deletions(-) create mode 100644 lib/pleroma/workers/nodeinfo_fetcher_worker.ex create mode 100644 priv/repo/migrations/20221020135943_add_nodeinfo.exs diff --git a/config/config.exs b/config/config.exs index 1af037051..644155aeb 100644 --- a/config/config.exs +++ b/config/config.exs @@ -567,7 +567,8 @@ attachments_cleanup: 1, new_users_digest: 1, mute_expire: 5, - search_indexing: 10 + search_indexing: 10, + nodeinfo_fetcher: 1 ], plugins: [ Oban.Plugins.Pruner, @@ -806,7 +807,8 @@ config :web_push_encryption, http_client: Pleroma.HTTP.WebPush -config :pleroma, :instances_favicons, enabled: false +config :pleroma, :instances_favicons, enabled: true +config :pleroma, :instances_nodeinfo, enabled: true config :floki, :html_parser, Floki.HTMLParser.FastHtml diff --git a/config/description.exs b/config/description.exs index 1ff0a582b..4843c0aae 100644 --- a/config/description.exs +++ b/config/description.exs @@ -3047,6 +3047,19 @@ } ] }, + %{ + group: :pleroma, + key: :instances_nodeinfo, + type: :group, + description: "Control favicons for instances", + children: [ + %{ + key: :enabled, + type: :boolean, + description: "Allow/disallow getting instance nodeinfo" + } + ] + }, %{ group: :ex_aws, key: :s3, diff --git a/config/test.exs b/config/test.exs index a5edb1149..3056dbd03 100644 --- a/config/test.exs +++ b/config/test.exs @@ -139,6 +139,8 @@ # Reduce recompilation time # https://dashbit.co/blog/speeding-up-re-compilation-of-elixir-projects config :phoenix, :plug_init_mode, :runtime +config :pleroma, :instances_favicons, enabled: false +config :pleroma, :instances_nodeinfo, enabled: false if File.exists?("./config/test.secret.exs") do import_config "test.secret.exs" diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex index adccd7c5d..a78924dfa 100644 --- a/lib/pleroma/application.ex +++ b/lib/pleroma/application.ex @@ -156,7 +156,8 @@ 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("translations", default_ttl: :timer.hours(24 * 30), limit: 2500) + build_cachex("translations", default_ttl: :timer.hours(24 * 30), limit: 2500), + build_cachex("instances", default_ttl: :timer.hours(24), limit: 2500) ] end diff --git a/lib/pleroma/instances/instance.ex b/lib/pleroma/instances/instance.ex index 533dbbb82..fcf3181bf 100644 --- a/lib/pleroma/instances/instance.ex +++ b/lib/pleroma/instances/instance.ex @@ -5,6 +5,8 @@ defmodule Pleroma.Instances.Instance do @moduledoc "Instance." + @cachex Pleroma.Config.get([:cachex, :provider], Cachex) + alias Pleroma.Instances alias Pleroma.Instances.Instance alias Pleroma.Repo @@ -22,7 +24,8 @@ defmodule Pleroma.Instances.Instance do field(:host, :string) field(:unreachable_since, :naive_datetime_usec) field(:favicon, :string) - field(:favicon_updated_at, :naive_datetime) + field(:metadata_updated_at, :naive_datetime) + field(:nodeinfo, :map, default: %{}) timestamps() end @@ -31,7 +34,7 @@ defmodule Pleroma.Instances.Instance do def changeset(struct, params \\ %{}) do struct - |> cast(params, [:host, :unreachable_since, :favicon, :favicon_updated_at]) + |> cast(params, [:host, :unreachable_since, :favicon, :nodeinfo, :metadata_updated_at]) |> validate_required([:host]) |> unique_constraint(:host) end @@ -138,63 +141,144 @@ defp parse_datetime(datetime) when is_binary(datetime) do 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() + def needs_update(nil), do: true - if existing_record && existing_record.favicon_updated_at && - NaiveDateTime.diff(now, existing_record.favicon_updated_at) < 86_400 do + def needs_update(%Instance{metadata_updated_at: nil}), do: true + + def needs_update(%Instance{metadata_updated_at: metadata_updated_at}) do + now = NaiveDateTime.utc_now() + NaiveDateTime.diff(now, metadata_updated_at) > 86_400 + end + + def local do + %Instance{ + host: Pleroma.Web.Endpoint.host(), + favicon: Pleroma.Web.Endpoint.url() <> "/favicon.png", + nodeinfo: Pleroma.Web.Nodeinfo.NodeinfoController.raw_nodeinfo() + } + end + + def update_metadata(%URI{host: host} = uri) do + Logger.info("Checking metadata for #{host}") + existing_record = Repo.get_by(Instance, %{host: host}) + + if reachable?(host) do + do_update_metadata(uri, existing_record) + else + {:discard, :unreachable} + end + end + + defp do_update_metadata(%URI{host: host} = uri, existing_record) do + if existing_record do + if needs_update(existing_record) do + Logger.info("Updating metadata for #{host}") + favicon = scrape_favicon(uri) + nodeinfo = scrape_nodeinfo(uri) + + {:ok, instance} = + existing_record + |> changeset(%{ + host: host, + favicon: favicon, + nodeinfo: nodeinfo, + metadata_updated_at: NaiveDateTime.utc_now() + }) + |> Repo.update() + + @cachex.put(:instances_cache, "instances:#{host}", instance) + else + {:discard, "Does not require update"} + end + else + favicon = scrape_favicon(uri) + nodeinfo = scrape_nodeinfo(uri) + + Logger.info("Creating metadata for #{host}") + + {:ok, instance} = + %Instance{} + |> changeset(%{ + host: host, + favicon: favicon, + nodeinfo: nodeinfo, + metadata_updated_at: NaiveDateTime.utc_now() + }) + |> Repo.insert() + + @cachex.put(:instances_cache, "instances:#{host}", instance) + end + end + + def get_favicon(%URI{host: host}) do + existing_record = Repo.get_by(Instance, %{host: host}) + + if existing_record do existing_record.favicon else - favicon = scrape_favicon(instance_uri) - - 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 - rescue - e -> - Logger.warn("Instance.get_or_update_favicon(\"#{host}\") error: #{inspect(e)}") nil + end + end + + defp scrape_nodeinfo(%URI{} = instance_uri) do + with true <- Pleroma.Config.get([:instances_nodeinfo, :enabled]), + {_, true} <- {:reachable, reachable?(instance_uri.host)}, + {:ok, %Tesla.Env{status: 200, body: body}} <- + Tesla.get( + "https://#{instance_uri.host}/.well-known/nodeinfo", + headers: [{"Accept", "application/json"}] + ), + {:ok, json} <- Jason.decode(body), + {:ok, %{"links" => links}} <- {:ok, json}, + {:ok, %{"href" => href}} <- + {:ok, + Enum.find(links, &(&1["rel"] == "http://nodeinfo.diaspora.software/ns/schema/2.0"))}, + {:ok, %Tesla.Env{body: data}} <- + Pleroma.HTTP.get(href, [{"accept", "application/json"}], []), + {:length, true} <- {:length, String.length(data) < 50_000}, + {:ok, nodeinfo} <- Jason.decode(data) do + nodeinfo + else + {:reachable, false} -> + Logger.debug( + "Instance.scrape_nodeinfo(\"#{to_string(instance_uri)}\") ignored unreachable host" + ) + + nil + + {:length, false} -> + Logger.debug( + "Instance.scrape_nodeinfo(\"#{to_string(instance_uri)}\") ignored too long body" + ) + + nil + + _ -> + nil + end end defp scrape_favicon(%URI{} = instance_uri) do - try do - with {_, true} <- {:reachable, reachable?(instance_uri.host)}, - {:ok, %Tesla.Env{body: html}} <- - Pleroma.HTTP.get(to_string(instance_uri), [{"accept", "text/html"}], []), - {_, [favicon_rel | _]} when is_binary(favicon_rel) <- - {:parse, - html |> Floki.parse_document!() |> Floki.attribute("link[rel=icon]", "href")}, - {_, favicon} when is_binary(favicon) <- - {:merge, URI.merge(instance_uri, favicon_rel) |> to_string()} do - favicon - else - {:reachable, false} -> - Logger.debug( - "Instance.scrape_favicon(\"#{to_string(instance_uri)}\") ignored unreachable host" - ) - - nil - - _ -> - nil - end - rescue - e -> - Logger.warn( - "Instance.scrape_favicon(\"#{to_string(instance_uri)}\") error: #{inspect(e)}" + with true <- Pleroma.Config.get([:instances_favicons, :enabled]), + {_, true} <- {:reachable, reachable?(instance_uri.host)}, + {:ok, %Tesla.Env{body: html}} <- + Pleroma.HTTP.get(to_string(instance_uri), [{"accept", "text/html"}], []), + {_, [favicon_rel | _]} when is_binary(favicon_rel) <- + {:parse, html |> Floki.parse_document!() |> Floki.attribute("link[rel=icon]", "href")}, + {_, favicon} when is_binary(favicon) <- + {:merge, URI.merge(instance_uri, favicon_rel) |> to_string()}, + {:length, true} <- {:length, String.length(favicon) < 255} do + favicon + else + {:reachable, false} -> + Logger.debug( + "Instance.scrape_favicon(\"#{to_string(instance_uri)}\") ignored unreachable host" ) nil + + _ -> + nil end end @@ -217,4 +301,25 @@ def perform(:delete_instance, host) when is_binary(host) do end) |> Stream.run() end + + def get_by_url(url_or_host) do + url = host(url_or_host) + Repo.get_by(Instance, host: url) + end + + def get_cached_by_url(url_or_host) do + url = host(url_or_host) + + if url == Pleroma.Web.Endpoint.host() do + {:ok, local()} + else + @cachex.fetch!(:instances_cache, "instances:#{url}", fn _ -> + with %Instance{} = instance <- get_by_url(url) do + {:commit, {:ok, instance}} + else + _ -> {:ignore, nil} + end + end) + end + end end diff --git a/lib/pleroma/web/activity_pub/side_effects.ex b/lib/pleroma/web/activity_pub/side_effects.ex index c3258c75b..18643662e 100644 --- a/lib/pleroma/web/activity_pub/side_effects.ex +++ b/lib/pleroma/web/activity_pub/side_effects.ex @@ -192,6 +192,7 @@ def handle(%{data: %{"type" => "Like"}} = object, meta) do # - Increase the user note count # - Increase the reply count # - Increase replies count + # - Ask for scraping of nodeinfo # - Set up ActivityExpiration # - Set up notifications # - Index incoming posts for search (if needed) @@ -209,6 +210,10 @@ def handle(%{data: %{"type" => "Create"}} = activity, meta) do reply_depth = (meta[:depth] || 0) + 1 + Pleroma.Workers.NodeInfoFetcherWorker.enqueue("process", %{ + "source_url" => activity.data["actor"] + }) + # FIXME: Force inReplyTo to replies if Pleroma.Web.Federator.allowed_thread_distance?(reply_depth) and object.data["replies"] != nil do @@ -234,7 +239,9 @@ def handle(%{data: %{"type" => "Create"}} = activity, meta) do {:ok, activity, meta} else - e -> Repo.rollback(e) + e -> + Logger.error(inspect(e)) + Repo.rollback(e) 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 06acf0a26..cbb57aee6 100644 --- a/lib/pleroma/web/mastodon_api/views/account_view.ex +++ b/lib/pleroma/web/mastodon_api/views/account_view.ex @@ -186,6 +186,16 @@ def render("relationships.json", %{user: user, targets: targets} = opts) do render_many(targets, AccountView, "relationship.json", render_opts) end + def render("instance.json", %{instance: %Pleroma.Instances.Instance{} = instance}) do + %{ + name: instance.host, + favicon: instance.favicon |> MediaProxy.url(), + nodeinfo: instance.nodeinfo + } + end + + def render("instance.json", _), do: nil + defp do_render("show.json", %{user: user} = opts) do user = User.sanitize_html(user, User.html_filter_policy(opts[:for])) display_name = user.name || user.nickname @@ -230,16 +240,20 @@ defp do_render("show.json", %{user: user} = opts) do %{} end - favicon = - 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() + instance = + with {:ok, instance} <- Pleroma.Instances.Instance.get_cached_by_url(user.ap_id) do + instance else + _ -> + nil + end + + favicon = + if is_nil(instance) do nil + else + instance.favicon + |> MediaProxy.url() end %{ @@ -271,7 +285,9 @@ defp do_render("show.json", %{user: user} = opts) do } }, last_status_at: user.last_status_at, - + akkoma: %{ + instance: render("instance.json", %{instance: instance}) + }, # Pleroma extensions # Note: it's insecure to output :email but fully-qualified nickname may serve as safe stub fqn: User.full_nickname(user), diff --git a/lib/pleroma/workers/nodeinfo_fetcher_worker.ex b/lib/pleroma/workers/nodeinfo_fetcher_worker.ex new file mode 100644 index 000000000..27492e1e3 --- /dev/null +++ b/lib/pleroma/workers/nodeinfo_fetcher_worker.ex @@ -0,0 +1,18 @@ +defmodule Pleroma.Workers.NodeInfoFetcherWorker do + use Pleroma.Workers.WorkerHelper, queue: "nodeinfo_fetcher" + + alias Oban.Job + alias Pleroma.Instances.Instance + + @impl Oban.Worker + def perform(%Job{ + args: %{"op" => "process", "source_url" => domain} + }) do + uri = + domain + |> URI.parse() + |> URI.merge("/") + + Instance.update_metadata(uri) + end +end diff --git a/priv/repo/migrations/20221020135943_add_nodeinfo.exs b/priv/repo/migrations/20221020135943_add_nodeinfo.exs new file mode 100644 index 000000000..17707f3f7 --- /dev/null +++ b/priv/repo/migrations/20221020135943_add_nodeinfo.exs @@ -0,0 +1,17 @@ +defmodule Pleroma.Repo.Migrations.AddNodeinfo do + use Ecto.Migration + + def up do + alter table(:instances) do + add_if_not_exists(:nodeinfo, :map, default: %{}) + add_if_not_exists(:metadata_updated_at, :naive_datetime) + end + end + + def down do + alter table(:instances) do + remove_if_exists(:nodeinfo, :map) + remove_if_exists(:metadata_updated_at, :naive_datetime) + end + end +end diff --git a/test/pleroma/instances/instance_test.exs b/test/pleroma/instances/instance_test.exs index e49922724..adc847da5 100644 --- a/test/pleroma/instances/instance_test.exs +++ b/test/pleroma/instances/instance_test.exs @@ -9,12 +9,16 @@ defmodule Pleroma.Instances.InstanceTest do alias Pleroma.Tests.ObanHelpers alias Pleroma.Web.CommonAPI - use Pleroma.DataCase + use Pleroma.DataCase, async: true import ExUnit.CaptureLog import Pleroma.Factory - setup_all do: clear_config([:instance, :federation_reachability_timeout_days], 1) + setup_all do + clear_config([:instance, :federation_reachability_timeout_days], 1) + clear_config([:instances_nodeinfo, :enabled], true) + clear_config([:instances_favicons, :enabled], true) + end describe "set_reachable/1" do test "clears `unreachable_since` of existing matching Instance record having non-nil `unreachable_since`" do @@ -102,62 +106,220 @@ test "does NOT modify `unreachable_since` value of existing record in case it's end end - describe "get_or_update_favicon/1" do - test "Scrapes favicon URLs" do - Tesla.Mock.mock(fn %{url: "https://favicon.example.org/"} -> - %Tesla.Env{ - status: 200, - body: ~s[] - } + describe "update_metadata/1" do + test "Scrapes favicon URLs and nodeinfo" do + Tesla.Mock.mock(fn + %{url: "https://favicon.example.org/"} -> + %Tesla.Env{ + status: 200, + body: ~s[] + } + + %{url: "https://favicon.example.org/.well-known/nodeinfo"} -> + %Tesla.Env{ + status: 200, + body: + Jason.encode!(%{ + links: [ + %{ + rel: "http://nodeinfo.diaspora.software/ns/schema/2.0", + href: "https://favicon.example.org/nodeinfo/2.0" + } + ] + }) + } + + %{url: "https://favicon.example.org/nodeinfo/2.0"} -> + %Tesla.Env{ + status: 200, + body: Jason.encode!(%{version: "2.0", software: %{name: "Akkoma"}}) + } end) - assert "https://favicon.example.org/favicon.png" == - Instance.get_or_update_favicon(URI.parse("https://favicon.example.org/")) + assert {:ok, true} == + Instance.update_metadata(URI.parse("https://favicon.example.org/")) + + {:ok, instance} = Instance.get_cached_by_url("https://favicon.example.org/") + assert instance.favicon == "https://favicon.example.org/favicon.png" + assert instance.nodeinfo == %{"version" => "2.0", "software" => %{"name" => "Akkoma"}} end - test "Returns nil on too long favicon URLs" do + test "Does not retain favicons that are too long" do long_favicon_url = "https://Lorem.ipsum.dolor.sit.amet/consecteturadipiscingelit/Praesentpharetrapurusutaliquamtempus/Mauriseulaoreetarcu/atfacilisisorci/Nullamporttitor/nequesedfeugiatmollis/dolormagnaefficiturlorem/nonpretiumsapienorcieurisus/Nullamveleratsem/Maecenassedaccumsanexnam/favicon.png" - Tesla.Mock.mock(fn %{url: "https://long-favicon.example.org/"} -> - %Tesla.Env{ - status: 200, - body: - ~s[] - } + Tesla.Mock.mock(fn + %{url: "https://long-favicon.example.org/"} -> + %Tesla.Env{ + status: 200, + body: + ~s[] + } + + %{url: "https://long-favicon.example.org/.well-known/nodeinfo"} -> + %Tesla.Env{ + status: 200, + body: + Jason.encode!(%{ + links: [ + %{ + rel: "http://nodeinfo.diaspora.software/ns/schema/2.0", + href: "https://long-favicon.example.org/nodeinfo/2.0" + } + ] + }) + } + + %{url: "https://long-favicon.example.org/nodeinfo/2.0"} -> + %Tesla.Env{ + status: 200, + body: Jason.encode!(%{version: "2.0", software: %{name: "Akkoma"}}) + } end) - assert capture_log(fn -> - assert nil == - Instance.get_or_update_favicon( - URI.parse("https://long-favicon.example.org/") - ) - end) =~ - "Instance.get_or_update_favicon(\"long-favicon.example.org\") error: %Postgrex.Error{" + assert {:ok, true} == + Instance.update_metadata(URI.parse("https://long-favicon.example.org/")) + + {:ok, instance} = Instance.get_cached_by_url("https://long-favicon.example.org/") + assert instance.favicon == nil end test "Handles not getting a favicon URL properly" do - Tesla.Mock.mock(fn %{url: "https://no-favicon.example.org/"} -> - %Tesla.Env{ - status: 200, - body: ~s[

I wil look down and whisper "GNO.."

] - } + Tesla.Mock.mock(fn + %{url: "https://no-favicon.example.org/"} -> + %Tesla.Env{ + status: 200, + body: ~s[

I wil look down and whisper "GNO.."

] + } + + %{url: "https://no-favicon.example.org/.well-known/nodeinfo"} -> + %Tesla.Env{ + status: 200, + body: + Jason.encode!(%{ + links: [ + %{ + rel: "http://nodeinfo.diaspora.software/ns/schema/2.0", + href: "https://no-favicon.example.org/nodeinfo/2.0" + } + ] + }) + } + + %{url: "https://no-favicon.example.org/nodeinfo/2.0"} -> + %Tesla.Env{ + status: 200, + body: Jason.encode!(%{version: "2.0", software: %{name: "Akkoma"}}) + } end) refute capture_log(fn -> - assert nil == - Instance.get_or_update_favicon( - URI.parse("https://no-favicon.example.org/") - ) - end) =~ "Instance.scrape_favicon(\"https://no-favicon.example.org/\") error: " + assert {:ok, true} = + Instance.update_metadata(URI.parse("https://no-favicon.example.org/")) + end) =~ "Instance.update_metadata(\"https://no-favicon.example.org/\") error: " end - test "Doesn't scrapes unreachable instances" do + test "Doesn't scrape unreachable instances" do instance = insert(:instance, unreachable_since: Instances.reachability_datetime_threshold()) url = "https://" <> instance.host - assert capture_log(fn -> assert nil == Instance.get_or_update_favicon(URI.parse(url)) end) =~ - "Instance.scrape_favicon(\"#{url}\") ignored unreachable host" + assert {:discard, :unreachable} == Instance.update_metadata(URI.parse(url)) + end + + test "doesn't continue scraping nodeinfo if we can't find a link" do + Tesla.Mock.mock(fn + %{url: "https://bad-nodeinfo.example.org/"} -> + %Tesla.Env{ + status: 200, + body: ~s[

I wil look down and whisper "GNO.."

] + } + + %{url: "https://bad-nodeinfo.example.org/.well-known/nodeinfo"} -> + %Tesla.Env{ + status: 200, + body: "oepsie woepsie de nodeinfo is kapotie uwu" + } + end) + + assert {:ok, true} == + Instance.update_metadata(URI.parse("https://bad-nodeinfo.example.org/")) + + {:ok, instance} = Instance.get_cached_by_url("https://bad-nodeinfo.example.org/") + assert instance.nodeinfo == nil + end + + test "doesn't store bad json in the nodeinfo" do + Tesla.Mock.mock(fn + %{url: "https://bad-nodeinfo.example.org/"} -> + %Tesla.Env{ + status: 200, + body: ~s[

I wil look down and whisper "GNO.."

] + } + + %{url: "https://bad-nodeinfo.example.org/.well-known/nodeinfo"} -> + %Tesla.Env{ + status: 200, + body: + Jason.encode!(%{ + links: [ + %{ + rel: "http://nodeinfo.diaspora.software/ns/schema/2.0", + href: "https://bad-nodeinfo.example.org/nodeinfo/2.0" + } + ] + }) + } + + %{url: "https://bad-nodeinfo.example.org/nodeinfo/2.0"} -> + %Tesla.Env{ + status: 200, + body: "oepsie woepsie de json might be bad uwu" + } + end) + + assert {:ok, true} == + Instance.update_metadata(URI.parse("https://bad-nodeinfo.example.org/")) + + {:ok, instance} = Instance.get_cached_by_url("https://bad-nodeinfo.example.org/") + assert instance.nodeinfo == nil + end + + test "doesn't store incredibly long json nodeinfo" do + too_long = String.duplicate("a", 50_000) + + Tesla.Mock.mock(fn + %{url: "https://bad-nodeinfo.example.org/"} -> + %Tesla.Env{ + status: 200, + body: ~s[

I wil look down and whisper "GNO.."

] + } + + %{url: "https://bad-nodeinfo.example.org/.well-known/nodeinfo"} -> + %Tesla.Env{ + status: 200, + body: + Jason.encode!(%{ + links: [ + %{ + rel: "http://nodeinfo.diaspora.software/ns/schema/2.0", + href: "https://bad-nodeinfo.example.org/nodeinfo/2.0" + } + ] + }) + } + + %{url: "https://bad-nodeinfo.example.org/nodeinfo/2.0"} -> + %Tesla.Env{ + status: 200, + body: Jason.encode!(%{version: "2.0", software: %{name: too_long}}) + } + end) + + assert {:ok, true} == + Instance.update_metadata(URI.parse("https://bad-nodeinfo.example.org/")) + + {:ok, instance} = Instance.get_cached_by_url("https://bad-nodeinfo.example.org/") + assert instance.nodeinfo == nil end end diff --git a/test/pleroma/web/activity_pub/side_effects_test.exs b/test/pleroma/web/activity_pub/side_effects_test.exs index fa8171eab..ee664bb8f 100644 --- a/test/pleroma/web/activity_pub/side_effects_test.exs +++ b/test/pleroma/web/activity_pub/side_effects_test.exs @@ -21,6 +21,35 @@ defmodule Pleroma.Web.ActivityPub.SideEffectsTest do import Mock import Pleroma.Factory + describe "handle" do + test "it queues a fetch of instance information" do + author = insert(:user, local: false, ap_id: "https://wowee.example.com/users/1") + recipient = insert(:user, local: true) + + {:ok, note_data, _meta} = + Builder.note(%Pleroma.Web.CommonAPI.ActivityDraft{ + user: author, + to: [recipient.ap_id], + mentions: [recipient], + content_html: "hey", + extra: %{"id" => "https://wowee.example.com/notes/1"} + }) + + {:ok, create_activity_data, _meta} = + Builder.create(author, note_data["id"], [recipient.ap_id]) + + {:ok, create_activity, _meta} = ActivityPub.persist(create_activity_data, local: false) + + {:ok, _create_activity, _meta} = + SideEffects.handle(create_activity, local: false, object_data: note_data) + + assert_enqueued( + worker: Pleroma.Workers.NodeInfoFetcherWorker, + args: %{"op" => "process", "source_url" => "https://wowee.example.com/users/1"} + ) + end + end + describe "handle_after_transaction" do test "it streams out notifications and streams" do author = insert(:user, local: true) diff --git a/test/pleroma/web/mastodon_api/views/account_view_test.exs b/test/pleroma/web/mastodon_api/views/account_view_test.exs index 8db887137..d1903af80 100644 --- a/test/pleroma/web/mastodon_api/views/account_view_test.exs +++ b/test/pleroma/web/mastodon_api/views/account_view_test.exs @@ -3,7 +3,7 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.MastodonAPI.AccountViewTest do - use Pleroma.DataCase + use Pleroma.DataCase, async: false alias Pleroma.User alias Pleroma.UserRelationship @@ -12,6 +12,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do import Pleroma.Factory import Tesla.Mock + import Mock setup do mock(fn env -> apply(HttpRequestMock, :request, [env]) end) @@ -25,6 +26,7 @@ test "Represent a user account" do user = insert(:user, %{ + ap_id: "https://example.com/users/chikichikibanban", follower_count: 3, note_count: 5, background: background_image, @@ -38,6 +40,8 @@ test "Represent a user account" do also_known_as: ["https://shitposter.zone/users/shp"] }) + insert(:instance, %{host: "example.com", nodeinfo: %{version: "2.1"}}) + expected = %{ id: to_string(user.id), username: "shp", @@ -50,6 +54,15 @@ test "Represent a user account" do statuses_count: 5, note: "valid html. a
b
c
d
f '&<>"", url: user.ap_id, + akkoma: %{ + instance: %{ + name: "example.com", + nodeinfo: %{ + "version" => "2.1" + }, + favicon: nil + } + }, avatar: "http://localhost:4001/images/avi.png", avatar_static: "http://localhost:4001/images/avi.png", header: "http://localhost:4001/images/banner.png", @@ -98,9 +111,57 @@ test "Represent a user account" do assert expected == AccountView.render("show.json", %{user: user, skip_visibility_check: true}) end + describe "nodeinfo" do + setup do + [ + user: insert(:user, ap_id: "https://somewhere.example.com/users/chikichikibanban"), + instance: + insert(:instance, %{ + host: "somewhere.example.com", + favicon: "https://example.com/favicon.ico" + }) + ] + end + + test "is embedded in the account view", %{user: user} do + assert %{ + akkoma: %{ + instance: %{ + name: "somewhere.example.com", + nodeinfo: %{ + "version" => "2.0" + }, + favicon: "https://example.com/favicon.ico" + } + } + } = AccountView.render("show.json", %{user: user, skip_visibility_check: true}) + end + + test "uses local nodeinfo for local users" do + user = insert(:user) + + assert %{ + akkoma: %{ + instance: %{ + name: "localhost", + nodeinfo: %{ + software: %{ + name: "akkoma" + } + } + } + } + } = AccountView.render("show.json", %{user: user, skip_visibility_check: true}) + end + end + describe "favicon" do setup do - [user: insert(:user)] + [ + user: insert(:user, ap_id: "https://example.com/users/chikichikibanban"), + instance: + insert(:instance, %{host: "example.com", favicon: "https://example.com/favicon.ico"}) + ] end test "is parsed when :instance_favicons is enabled", %{user: user} do @@ -108,13 +169,14 @@ test "is parsed when :instance_favicons is enabled", %{user: user} do assert %{ pleroma: %{ - favicon: - "https://shitposter.club/plugins/Qvitter/img/gnusocial-favicons/favicon-16x16.png" + favicon: "https://example.com/favicon.ico" } } = AccountView.render("show.json", %{user: user, skip_visibility_check: true}) end - test "is nil when :instances_favicons is disabled", %{user: user} do + test "is nil when we have no instance", %{user: user} do + user = %{user | ap_id: "https://wowee.example.com/users/2"} + assert %{pleroma: %{favicon: nil}} = AccountView.render("show.json", %{user: user, skip_visibility_check: true}) end @@ -176,11 +238,18 @@ test "Represent a Service(bot) account" do }, fqn: "shp@shitposter.club", last_status_at: nil, + akkoma: %{ + instance: %{ + name: "localhost", + favicon: "http://localhost:4001/favicon.png", + nodeinfo: %{version: "2.0"} + } + }, pleroma: %{ ap_id: user.ap_id, also_known_as: [], background_image: nil, - favicon: nil, + favicon: "http://localhost:4001/favicon.png", is_confirmed: true, tags: [], is_admin: false, @@ -196,7 +265,13 @@ test "Represent a Service(bot) account" do } } - assert expected == AccountView.render("show.json", %{user: user, skip_visibility_check: true}) + with_mock( + Pleroma.Web.Nodeinfo.NodeinfoController, + raw_nodeinfo: fn -> %{version: "2.0"} end + ) do + assert expected == + AccountView.render("show.json", %{user: user, skip_visibility_check: true}) + end end test "Represent a Funkwhale channel" do @@ -578,6 +653,8 @@ test "uses mediaproxy urls when it's enabled (regardless of media preview proxy emoji: %{"joker_smile" => "https://evil.website/society.png"} ) + insert(:instance, %{host: "localhost", favicon: "https://evil.website/favicon.png"}) + with media_preview_enabled <- [false, true] do clear_config([:media_preview_proxy, :enabled], media_preview_enabled) @@ -586,6 +663,9 @@ test "uses mediaproxy urls when it's enabled (regardless of media preview proxy {key, url} when key in [:avatar, :avatar_static, :header, :header_static] -> String.starts_with?(url, Pleroma.Web.Endpoint.url()) + {:akkoma, %{instance: %{favicon: favicon_url}}} -> + String.starts_with?(favicon_url, Pleroma.Web.Endpoint.url()) + {:emojis, emojis} -> Enum.all?(emojis, fn %{url: url, static_url: static_url} -> String.starts_with?(url, Pleroma.Web.Endpoint.url()) && @@ -598,4 +678,10 @@ test "uses mediaproxy urls when it's enabled (regardless of media preview proxy |> assert() end end + + test "returns nil in the instance field when no instance is held locally" do + user = insert(:user, ap_id: "https://example.com/users/1") + view = AccountView.render("show.json", %{user: user, skip_visibility_check: true}) + assert view[:akkoma][:instance] == nil + end end diff --git a/test/pleroma/web/streamer_test.exs b/test/pleroma/web/streamer_test.exs index 8e2ab5016..a9db5a015 100644 --- a/test/pleroma/web/streamer_test.exs +++ b/test/pleroma/web/streamer_test.exs @@ -3,7 +3,7 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.StreamerTest do - use Pleroma.DataCase + use Pleroma.DataCase, async: false import Pleroma.Factory diff --git a/test/support/factory.ex b/test/support/factory.ex index 54d385bc4..bd9d7fe42 100644 --- a/test/support/factory.ex +++ b/test/support/factory.ex @@ -36,6 +36,15 @@ def conversation_factory do } end + def instance_factory(attrs \\ %{}) do + %Pleroma.Instances.Instance{ + host: attrs[:domain] || "example.com", + nodeinfo: %{version: "2.0", openRegistrations: true}, + unreachable_since: nil + } + |> Map.merge(attrs) + end + def user_factory(attrs \\ %{}) do pem = Enum.random(@rsa_keys) @@ -522,13 +531,6 @@ def oauth_app_factory do } end - def instance_factory do - %Pleroma.Instances.Instance{ - host: "domain.com", - unreachable_since: nil - } - end - def oauth_token_factory(attrs \\ %{}) do scopes = Map.get(attrs, :scopes, ["read"]) oauth_app = Map.get_lazy(attrs, :app, fn -> insert(:oauth_app, scopes: scopes) end) From bbedbaaf5cf1b9a76c656e7ef26df4dec2cc91bf Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Sun, 6 Nov 2022 22:50:11 +0000 Subject: [PATCH 016/631] Changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 34c09cd65..6bc87ada1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## Added - Officially supported docker release - Ability to remove followers unilaterally without a block +- Scraping of nodeinfo from remote instances to display instance info ## Changes - Follows no longer override domain blocks, a domain block is final From 5123b3a5dd9683441f5b4e904deda89fd40098ac Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Sun, 6 Nov 2022 22:55:26 +0000 Subject: [PATCH 017/631] Add enabled check on /translation/languages --- .../web/akkoma_api/controllers/translation_controller.ex | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/pleroma/web/akkoma_api/controllers/translation_controller.ex b/lib/pleroma/web/akkoma_api/controllers/translation_controller.ex index 9983a7e39..ca9b4b64a 100644 --- a/lib/pleroma/web/akkoma_api/controllers/translation_controller.ex +++ b/lib/pleroma/web/akkoma_api/controllers/translation_controller.ex @@ -21,10 +21,12 @@ defmodule Pleroma.Web.AkkomaAPI.TranslationController do @doc "GET /api/v1/akkoma/translation/languages" def languages(conn, _params) do - with {:ok, source_languages, dest_languages} <- get_languages() do + with {:enabled, true} <- {:enabled, Pleroma.Config.get([:translator, :enabled])}, + {:ok, source_languages, dest_languages} <- get_languages() do conn |> json(%{source: source_languages, target: dest_languages}) else + {:enabled, false} -> json(conn, %{}) e -> IO.inspect(e) end end From 31ad09010e03f30643b9e921c4fd85c113071a4d Mon Sep 17 00:00:00 2001 From: floatingghost Date: Sun, 6 Nov 2022 23:50:32 +0000 Subject: [PATCH 018/631] Fix regex usage in MRF (#254) fixes #235 fixes #228 Co-authored-by: FloatingGhost Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma/pulls/254 --- CHANGELOG.md | 4 ++ lib/pleroma/web/activity_pub/mrf.ex | 11 ++- test/pleroma/user_test.exs | 29 ++++---- .../activity_pub/mrf/simple_policy_test.exs | 68 +++++++++---------- test/pleroma/web/activity_pub/mrf_test.exs | 16 ++--- 5 files changed, 72 insertions(+), 56 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6bc87ada1..05d24a821 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## Unreleased +## UPGRADE NOTES +- Change your instance blocks to remove any `*.` prefixes. `example.com` will block `*.example.com` by default now + ## Added - Officially supported docker release - Ability to remove followers unilaterally without a block @@ -14,6 +17,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## Changes - Follows no longer override domain blocks, a domain block is final - Deletes are now the lowest priority to publish and will be handled after creates +- Domain blocks are now subdomain-matches by default ## Fixed - Registrations via ldap are now compatible with the latest OTP24 diff --git a/lib/pleroma/web/activity_pub/mrf.ex b/lib/pleroma/web/activity_pub/mrf.ex index 4df226e80..7b7f44646 100644 --- a/lib/pleroma/web/activity_pub/mrf.ex +++ b/lib/pleroma/web/activity_pub/mrf.ex @@ -149,9 +149,18 @@ defp get_policies(policy) when is_atom(policy), do: [policy] defp get_policies(policies) when is_list(policies), do: policies defp get_policies(_), do: [] + # Matches the following: + # - https://baddomain.net + # - https://extra.baddomain.net/ + # Does NOT match the following: + # - https://maybebaddomain.net/ + def subdomain_regex(domain) do + ~r/^(.+\.)?#{Regex.escape(domain)}$/i + end + @spec subdomains_regex([String.t()]) :: [Regex.t()] def subdomains_regex(domains) when is_list(domains) do - for domain <- domains, do: ~r(^#{String.replace(domain, "*.", "(.*\\.)*")}$)i + Enum.map(domains, &subdomain_regex/1) end @spec subdomain_match?([Regex.t()], String.t()) :: boolean() diff --git a/test/pleroma/user_test.exs b/test/pleroma/user_test.exs index f11aec136..195df2a03 100644 --- a/test/pleroma/user_test.exs +++ b/test/pleroma/user_test.exs @@ -444,17 +444,20 @@ test "it sends a welcome message if it is set" do end setup do: - clear_config(:mrf_simple, - media_removal: [], - media_nsfw: [], - federated_timeline_removal: [], - report_removal: [], - reject: [], - followers_only: [], - accept: [], - avatar_removal: [], - banner_removal: [], - reject_deletes: [] + clear_config( + [:mrf_simple], + %{ + media_removal: [], + media_nsfw: [], + federated_timeline_removal: [], + report_removal: [], + reject: [], + followers_only: [], + accept: [], + avatar_removal: [], + banner_removal: [], + reject_deletes: [] + } ) setup do: @@ -1324,7 +1327,7 @@ test "does not block domain with same end if wildcard added" do collateral_user = insert(:user, %{ap_id: "https://another-awful-and-rude-instance.com/user/bully"}) - {:ok, user} = User.block_domain(user, "*.awful-and-rude-instance.com") + {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com") refute User.blocks?(user, collateral_user) end @@ -1342,7 +1345,7 @@ test "blocks domain with wildcard for subdomain" do user_domain = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"}) - {:ok, user} = User.block_domain(user, "*.awful-and-rude-instance.com") + {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com") assert User.blocks?(user, user_from_subdomain) assert User.blocks?(user, user_with_two_subdomains) diff --git a/test/pleroma/web/activity_pub/mrf/simple_policy_test.exs b/test/pleroma/web/activity_pub/mrf/simple_policy_test.exs index 0569bfed3..5f80c1629 100644 --- a/test/pleroma/web/activity_pub/mrf/simple_policy_test.exs +++ b/test/pleroma/web/activity_pub/mrf/simple_policy_test.exs @@ -46,8 +46,8 @@ test "has a matching host" do end test "match with wildcard domain" do - clear_config([:mrf_simple, :media_removal], [{"*.remote.instance", "Whatever reason"}]) - media_message = build_media_message() + clear_config([:mrf_simple, :media_removal], [{"remote.instance", "Whatever reason"}]) + media_message = build_media_message("sub.remote.instance") local_message = build_local_message() assert SimplePolicy.filter(media_message) == @@ -81,8 +81,8 @@ test "has a matching host" do end test "match with wildcard domain" do - clear_config([:mrf_simple, :media_nsfw], [{"*.remote.instance", "yeah yeah"}]) - media_message = build_media_message() + clear_config([:mrf_simple, :media_nsfw], [{"remote.instance", "yeah yeah"}]) + media_message = build_media_message("sub.remote.instance") local_message = build_local_message() assert SimplePolicy.filter(media_message) == @@ -92,9 +92,9 @@ test "match with wildcard domain" do end end - defp build_media_message do + defp build_media_message(domain \\ "remote.instance") do %{ - "actor" => "https://remote.instance/users/bob", + "actor" => "https://#{domain}/users/bob", "type" => "Create", "object" => %{ "attachment" => [%{}], @@ -124,8 +124,8 @@ test "has a matching host" do end test "match with wildcard domain" do - clear_config([:mrf_simple, :report_removal], [{"*.remote.instance", "suya"}]) - report_message = build_report_message() + clear_config([:mrf_simple, :report_removal], [{"remote.instance", "suya"}]) + report_message = build_report_message("sub.remote.instance") local_message = build_local_message() assert {:reject, _} = SimplePolicy.filter(report_message) @@ -133,9 +133,9 @@ test "match with wildcard domain" do end end - defp build_report_message do + defp build_report_message(domain \\ "remote.instance") do %{ - "actor" => "https://remote.instance/users/bob", + "actor" => "https://#{domain}/users/bob", "type" => "Flag" } end @@ -143,7 +143,7 @@ defp build_report_message do describe "when :federated_timeline_removal" do test "is empty" do clear_config([:mrf_simple, :federated_timeline_removal], []) - {_, ftl_message} = build_ftl_actor_and_message() + {_, ftl_message} = build_ftl_actor_and_message("https://remote.instance/users/bob") local_message = build_local_message() assert SimplePolicy.filter(ftl_message) == {:ok, ftl_message} @@ -151,7 +151,7 @@ test "is empty" do end test "has a matching host" do - {actor, ftl_message} = build_ftl_actor_and_message() + {actor, ftl_message} = build_ftl_actor_and_message("https://remote.instance/users/bob") ftl_message_actor_host = ftl_message @@ -172,7 +172,7 @@ test "has a matching host" do end test "match with wildcard domain" do - {actor, ftl_message} = build_ftl_actor_and_message() + {actor, ftl_message} = build_ftl_actor_and_message("https://sub.remote.instance/users/bob") ftl_message_actor_host = ftl_message @@ -181,7 +181,7 @@ test "match with wildcard domain" do |> Map.fetch!(:host) clear_config([:mrf_simple, :federated_timeline_removal], [ - {"*." <> ftl_message_actor_host, "owo"} + {ftl_message_actor_host, "owo"} ]) local_message = build_local_message() @@ -196,7 +196,7 @@ test "match with wildcard domain" do end test "has a matching host but only as:Public in to" do - {_actor, ftl_message} = build_ftl_actor_and_message() + {_actor, ftl_message} = build_ftl_actor_and_message("https://remote.instance/users/bob") ftl_message_actor_host = ftl_message @@ -253,8 +253,8 @@ test "obfuscates domains listed in :transparency_obfuscate_domains" do end end - defp build_ftl_actor_and_message do - actor = insert(:user) + defp build_ftl_actor_and_message(ap_id) do + actor = insert(:user, ap_id: ap_id) {actor, %{ @@ -282,9 +282,9 @@ test "activity has a matching host" do end test "activity matches with wildcard domain" do - clear_config([:mrf_simple, :reject], [{"*.remote.instance", ""}]) + clear_config([:mrf_simple, :reject], [{"remote.instance", ""}]) - remote_message = build_remote_message() + remote_message = build_remote_message("sub.remote.instance") assert {:reject, _} = SimplePolicy.filter(remote_message) end @@ -325,7 +325,7 @@ test "reject by URI object" do describe "when :followers_only" do test "is empty" do clear_config([:mrf_simple, :followers_only], []) - {_, ftl_message} = build_ftl_actor_and_message() + {_, ftl_message} = build_ftl_actor_and_message("https://remote.instance/users/alice") local_message = build_local_message() assert SimplePolicy.filter(ftl_message) == {:ok, ftl_message} @@ -412,10 +412,10 @@ test "activity has a matching host" do end test "activity matches with wildcard domain" do - clear_config([:mrf_simple, :accept], [{"*.remote.instance", ""}]) + clear_config([:mrf_simple, :accept], [{"remote.instance", ""}]) local_message = build_local_message() - remote_message = build_remote_message() + remote_message = build_remote_message("sub.remote.instance") assert SimplePolicy.filter(local_message) == {:ok, local_message} assert SimplePolicy.filter(remote_message) == {:ok, remote_message} @@ -457,9 +457,9 @@ test "has a matching host" do end test "match with wildcard domain" do - clear_config([:mrf_simple, :avatar_removal], [{"*.remote.instance", ""}]) + clear_config([:mrf_simple, :avatar_removal], [{"remote.instance", ""}]) - remote_user = build_remote_user() + remote_user = build_remote_user("sub.remote.instance") {:ok, filtered} = SimplePolicy.filter(remote_user) refute filtered["icon"] @@ -493,9 +493,9 @@ test "has a matching host" do end test "match with wildcard domain" do - clear_config([:mrf_simple, :banner_removal], [{"*.remote.instance", ""}]) + clear_config([:mrf_simple, :banner_removal], [{"remote.instance", ""}]) - remote_user = build_remote_user() + remote_user = build_remote_user("sub.remote.instance") {:ok, filtered} = SimplePolicy.filter(remote_user) refute filtered["image"] @@ -553,10 +553,10 @@ test "it rejects the deletion" do end describe "when :reject_deletes match with wildcard domain" do - setup do: clear_config([:mrf_simple, :reject_deletes], [{"*.remote.instance", ""}]) + setup do: clear_config([:mrf_simple, :reject_deletes], [{"remote.instance", ""}]) test "it rejects the deletion" do - deletion_message = build_remote_deletion_message() + deletion_message = build_remote_deletion_message("sub.remote.instance") assert {:reject, _} = SimplePolicy.filter(deletion_message) end @@ -570,13 +570,13 @@ defp build_local_message do } end - defp build_remote_message do - %{"actor" => "https://remote.instance/users/bob"} + defp build_remote_message(domain \\ "remote.instance") do + %{"actor" => "https://#{domain}/users/bob"} end - defp build_remote_user do + defp build_remote_user(domain \\ "remote.instance") do %{ - "id" => "https://remote.instance/users/bob", + "id" => "https://#{domain}/users/bob", "icon" => %{ "url" => "http://example.com/image.jpg", "type" => "Image" @@ -589,10 +589,10 @@ defp build_remote_user do } end - defp build_remote_deletion_message do + defp build_remote_deletion_message(domain \\ "remote.instance") do %{ "type" => "Delete", - "actor" => "https://remote.instance/users/bob" + "actor" => "https://#{domain}/users/bob" } end end diff --git a/test/pleroma/web/activity_pub/mrf_test.exs b/test/pleroma/web/activity_pub/mrf_test.exs index ed3233758..ec4dab30f 100644 --- a/test/pleroma/web/activity_pub/mrf_test.exs +++ b/test/pleroma/web/activity_pub/mrf_test.exs @@ -9,8 +9,8 @@ defmodule Pleroma.Web.ActivityPub.MRFTest do test "subdomains_regex/1" do assert MRF.subdomains_regex(["unsafe.tld", "*.unsafe.tld"]) == [ - ~r/^unsafe.tld$/i, - ~r/^(.*\.)*unsafe.tld$/i + ~r/^(.+\.)?unsafe\.tld$/i, + ~r/^(.+\.)?\*\.unsafe\.tld$/i ] end @@ -18,7 +18,7 @@ test "subdomains_regex/1" do test "common domains" do regexes = MRF.subdomains_regex(["unsafe.tld", "unsafe2.tld"]) - assert regexes == [~r/^unsafe.tld$/i, ~r/^unsafe2.tld$/i] + assert regexes == [~r/^(.+\.)?unsafe\.tld$/i, ~r/^(.+\.)?unsafe2\.tld$/i] assert MRF.subdomain_match?(regexes, "unsafe.tld") assert MRF.subdomain_match?(regexes, "unsafe2.tld") @@ -27,9 +27,9 @@ test "common domains" do end test "wildcard domains with one subdomain" do - regexes = MRF.subdomains_regex(["*.unsafe.tld"]) + regexes = MRF.subdomains_regex(["unsafe.tld"]) - assert regexes == [~r/^(.*\.)*unsafe.tld$/i] + assert regexes == [~r/^(.+\.)?unsafe\.tld$/i] assert MRF.subdomain_match?(regexes, "unsafe.tld") assert MRF.subdomain_match?(regexes, "sub.unsafe.tld") @@ -38,9 +38,9 @@ test "wildcard domains with one subdomain" do end test "wildcard domains with two subdomains" do - regexes = MRF.subdomains_regex(["*.unsafe.tld"]) + regexes = MRF.subdomains_regex(["unsafe.tld"]) - assert regexes == [~r/^(.*\.)*unsafe.tld$/i] + assert regexes == [~r/^(.+\.)?unsafe\.tld$/i] assert MRF.subdomain_match?(regexes, "unsafe.tld") assert MRF.subdomain_match?(regexes, "sub.sub.unsafe.tld") @@ -51,7 +51,7 @@ test "wildcard domains with two subdomains" do test "matches are case-insensitive" do regexes = MRF.subdomains_regex(["UnSafe.TLD", "UnSAFE2.Tld"]) - assert regexes == [~r/^UnSafe.TLD$/i, ~r/^UnSAFE2.Tld$/i] + assert regexes == [~r/^(.+\.)?UnSafe\.TLD$/i, ~r/^(.+\.)?UnSAFE2\.Tld$/i] assert MRF.subdomain_match?(regexes, "UNSAFE.TLD") assert MRF.subdomain_match?(regexes, "UNSAFE2.TLD") From 48309c141e8f555c277136122fe339534f88d39a Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Sun, 6 Nov 2022 23:57:43 +0000 Subject: [PATCH 019/631] Add "differences" in readme --- README.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/README.md b/README.md index c3ead7fc1..74b8919e4 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,27 @@ For clients it supports the [Mastodon client API](https://docs.joinmastodon.org/ - [Client Applications for Akkoma](https://docs.akkoma.dev/stable/clients/) +## Differences with Pleroma + +Akkoma is a faster-paced fork, it has a varied and potentially experimental feature set tailored specifically to the corner of the fediverse inhabited by the project +creator and contributors. + +This should not be considered a one-for-one match with pleroma; it is more opinionated in many ways, and has a smaller community (which is good or +bad depending on your view) + +For example, Akkoma has: +- Custom Emoji reactions (compatible with misskey) +- Misskey-flavoured markdown support +- Elasticsearch and Meilisearch support for search +- Mastodon frontend (Glitch-Soc and Fedibird flavours) support +- Automatic post translation via DeepL or LibreTranslate +- A multitude of heavy modifications to the Pleroma Frontend (Pleroma-FE) +- The "bubble" concept, in which instance administrators can choose closely-related instances to make a "community of communities", so to say + +And takes a more opinionated stance on issues like Domain blocks, which are enforced far more on Akkoma. + +Take a look at the Changelog if you want a full list of recent changes, everything since 3.0 has been Akkoma. + ## Installation ### OTP releases (Recommended) From e0032e47992bca069e61a8208c322c0eb8a0c9e3 Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Mon, 7 Nov 2022 00:08:20 +0000 Subject: [PATCH 020/631] Add rollbacks for associated_object_id --- docs/docs/installation/migrating_to_akkoma.md | 9 + ...2322_add_associated_object_id_function.exs | 37 +++++ ...0_switch_to_associated_object_id_index.exs | 37 +++++ ..._visibility_to_use_new_object_id_index.exs | 156 ++++++++++++++++++ 4 files changed, 239 insertions(+) create mode 100644 priv/repo/optional_migrations/pleroma_develop_rollbacks/20220711182322_add_associated_object_id_function.exs create mode 100644 priv/repo/optional_migrations/pleroma_develop_rollbacks/20220711192750_switch_to_associated_object_id_index.exs create mode 100644 priv/repo/optional_migrations/pleroma_develop_rollbacks/20220821004840_change_thread_visibility_to_use_new_object_id_index.exs diff --git a/docs/docs/installation/migrating_to_akkoma.md b/docs/docs/installation/migrating_to_akkoma.md index d8ea0ea25..b64cdd056 100644 --- a/docs/docs/installation/migrating_to_akkoma.md +++ b/docs/docs/installation/migrating_to_akkoma.md @@ -34,6 +34,15 @@ git pull -r # to run "git merge stable" instead (or develop if you want) ``` +### WARNING - Migrating from Pleroma Develop +If you are on pleroma develop, and have updated since 2022-08, you may have issues with database migrations. + +Please roll back the given migrations: + +```bash +MIX_ENV=prod mix ecto.rollback --migrations-path priv/repo/optional_migrations/pleroma_develop_rollbacks -n3 +``` + Then compile, migrate and restart as usual. ## From OTP diff --git a/priv/repo/optional_migrations/pleroma_develop_rollbacks/20220711182322_add_associated_object_id_function.exs b/priv/repo/optional_migrations/pleroma_develop_rollbacks/20220711182322_add_associated_object_id_function.exs new file mode 100644 index 000000000..76348f31a --- /dev/null +++ b/priv/repo/optional_migrations/pleroma_develop_rollbacks/20220711182322_add_associated_object_id_function.exs @@ -0,0 +1,37 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2022 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Repo.Migrations.AddAssociatedObjectIdFunction do + use Ecto.Migration + + def up do + statement = """ + CREATE OR REPLACE FUNCTION associated_object_id(data jsonb) RETURNS varchar AS $$ + DECLARE + object_data jsonb; + BEGIN + IF jsonb_typeof(data->'object') = 'array' THEN + object_data := data->'object'->0; + ELSE + object_data := data->'object'; + END IF; + + IF jsonb_typeof(object_data->'id') = 'string' THEN + RETURN object_data->>'id'; + ELSIF jsonb_typeof(object_data) = 'string' THEN + RETURN object_data#>>'{}'; + ELSE + RETURN NULL; + END IF; + END; + $$ LANGUAGE plpgsql IMMUTABLE; + """ + + execute(statement) + end + + def down do + execute("DROP FUNCTION IF EXISTS associated_object_id(data jsonb)") + end +end diff --git a/priv/repo/optional_migrations/pleroma_develop_rollbacks/20220711192750_switch_to_associated_object_id_index.exs b/priv/repo/optional_migrations/pleroma_develop_rollbacks/20220711192750_switch_to_associated_object_id_index.exs new file mode 100644 index 000000000..75c1cd40b --- /dev/null +++ b/priv/repo/optional_migrations/pleroma_develop_rollbacks/20220711192750_switch_to_associated_object_id_index.exs @@ -0,0 +1,37 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2022 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Repo.Migrations.SwitchToAssociatedObjectIdIndex do + use Ecto.Migration + @disable_ddl_transaction true + @disable_migration_lock true + + def up do + drop_if_exists( + index(:activities, ["(coalesce(data->'object'->>'id', data->>'object'))"], + name: :activities_create_objects_index + ) + ) + + create( + index(:activities, ["associated_object_id(data)"], + name: :activities_create_objects_index, + concurrently: true + ) + ) + end + + def down do + drop_if_exists( + index(:activities, ["associated_object_id(data)"], name: :activities_create_objects_index) + ) + + create( + index(:activities, ["(coalesce(data->'object'->>'id', data->>'object'))"], + name: :activities_create_objects_index, + concurrently: true + ) + ) + end +end diff --git a/priv/repo/optional_migrations/pleroma_develop_rollbacks/20220821004840_change_thread_visibility_to_use_new_object_id_index.exs b/priv/repo/optional_migrations/pleroma_develop_rollbacks/20220821004840_change_thread_visibility_to_use_new_object_id_index.exs new file mode 100644 index 000000000..bb56843cb --- /dev/null +++ b/priv/repo/optional_migrations/pleroma_develop_rollbacks/20220821004840_change_thread_visibility_to_use_new_object_id_index.exs @@ -0,0 +1,156 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2022 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Repo.Migrations.ChangeThreadVisibilityToUseNewObjectIdIndex do + use Ecto.Migration + + def up do + execute(update_thread_visibility()) + end + + def down do + execute(restore_thread_visibility()) + end + + def update_thread_visibility do + """ + CREATE OR REPLACE FUNCTION thread_visibility(actor varchar, activity_id varchar, local_public varchar default '') RETURNS boolean AS $$ + DECLARE + public varchar := 'https://www.w3.org/ns/activitystreams#Public'; + child objects%ROWTYPE; + activity activities%ROWTYPE; + author_fa varchar; + valid_recipients varchar[]; + actor_user_following varchar[]; + BEGIN + --- Fetch actor following + SELECT array_agg(following.follower_address) INTO actor_user_following FROM following_relationships + JOIN users ON users.id = following_relationships.follower_id + JOIN users AS following ON following.id = following_relationships.following_id + WHERE users.ap_id = actor; + + --- Fetch our initial activity. + SELECT * INTO activity FROM activities WHERE activities.data->>'id' = activity_id; + + LOOP + --- Ensure that we have an activity before continuing. + --- If we don't, the thread is not satisfiable. + IF activity IS NULL THEN + RETURN false; + END IF; + + --- We only care about Create activities. + IF activity.data->>'type' != 'Create' THEN + RETURN true; + END IF; + + --- Normalize the child object into child. + SELECT * INTO child FROM objects + INNER JOIN activities ON associated_object_id(activities.data) = objects.data->>'id' + WHERE associated_object_id(activity.data) = objects.data->>'id'; + + --- Fetch the author's AS2 following collection. + SELECT COALESCE(users.follower_address, '') INTO author_fa FROM users WHERE users.ap_id = activity.actor; + + --- Prepare valid recipients array. + valid_recipients := ARRAY[actor, public]; + --- If we specified local public, add it. + IF local_public <> '' THEN + valid_recipients := valid_recipients || local_public; + END IF; + IF ARRAY[author_fa] && actor_user_following THEN + valid_recipients := valid_recipients || author_fa; + END IF; + + --- Check visibility. + IF NOT valid_recipients && activity.recipients THEN + --- activity not visible, break out of the loop + RETURN false; + END IF; + + --- If there's a parent, load it and do this all over again. + IF (child.data->'inReplyTo' IS NOT NULL) AND (child.data->'inReplyTo' != 'null'::jsonb) THEN + SELECT * INTO activity FROM activities + INNER JOIN objects ON associated_object_id(activities.data) = objects.data->>'id' + WHERE child.data->>'inReplyTo' = objects.data->>'id'; + ELSE + RETURN true; + END IF; + END LOOP; + END; + $$ LANGUAGE plpgsql IMMUTABLE; + """ + end + + # priv/repo/migrations/20220509180452_change_thread_visibility_to_be_local_only_aware.exs + def restore_thread_visibility do + """ + CREATE OR REPLACE FUNCTION thread_visibility(actor varchar, activity_id varchar, local_public varchar default '') RETURNS boolean AS $$ + DECLARE + public varchar := 'https://www.w3.org/ns/activitystreams#Public'; + child objects%ROWTYPE; + activity activities%ROWTYPE; + author_fa varchar; + valid_recipients varchar[]; + actor_user_following varchar[]; + BEGIN + --- Fetch actor following + SELECT array_agg(following.follower_address) INTO actor_user_following FROM following_relationships + JOIN users ON users.id = following_relationships.follower_id + JOIN users AS following ON following.id = following_relationships.following_id + WHERE users.ap_id = actor; + + --- Fetch our initial activity. + SELECT * INTO activity FROM activities WHERE activities.data->>'id' = activity_id; + + LOOP + --- Ensure that we have an activity before continuing. + --- If we don't, the thread is not satisfiable. + IF activity IS NULL THEN + RETURN false; + END IF; + + --- We only care about Create activities. + IF activity.data->>'type' != 'Create' THEN + RETURN true; + END IF; + + --- Normalize the child object into child. + SELECT * INTO child FROM objects + INNER JOIN activities ON COALESCE(activities.data->'object'->>'id', activities.data->>'object') = objects.data->>'id' + WHERE COALESCE(activity.data->'object'->>'id', activity.data->>'object') = objects.data->>'id'; + + --- Fetch the author's AS2 following collection. + SELECT COALESCE(users.follower_address, '') INTO author_fa FROM users WHERE users.ap_id = activity.actor; + + --- Prepare valid recipients array. + valid_recipients := ARRAY[actor, public]; + --- If we specified local public, add it. + IF local_public <> '' THEN + valid_recipients := valid_recipients || local_public; + END IF; + IF ARRAY[author_fa] && actor_user_following THEN + valid_recipients := valid_recipients || author_fa; + END IF; + + --- Check visibility. + IF NOT valid_recipients && activity.recipients THEN + --- activity not visible, break out of the loop + RETURN false; + END IF; + + --- If there's a parent, load it and do this all over again. + IF (child.data->'inReplyTo' IS NOT NULL) AND (child.data->'inReplyTo' != 'null'::jsonb) THEN + SELECT * INTO activity FROM activities + INNER JOIN objects ON COALESCE(activities.data->'object'->>'id', activities.data->>'object') = objects.data->>'id' + WHERE child.data->>'inReplyTo' = objects.data->>'id'; + ELSE + RETURN true; + END IF; + END LOOP; + END; + $$ LANGUAGE plpgsql IMMUTABLE; + """ + end +end From c0eecb55bf67afe0e199482a52d38d4d976e4bd6 Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Mon, 7 Nov 2022 13:32:34 +0000 Subject: [PATCH 021/631] Update finch --- mix.exs | 2 +- mix.lock | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mix.exs b/mix.exs index 108930f2c..d95cc1778 100644 --- a/mix.exs +++ b/mix.exs @@ -139,7 +139,7 @@ defp deps do {:castore, "~> 0.1"}, {:cowlib, "~> 2.9", override: true}, {:gun, "~> 2.0.0-rc.1", override: true}, - {:finch, "~> 0.10.0"}, + {:finch, "~> 0.13.0"}, {:jason, "~> 1.2"}, {:mogrify, "~> 0.9.1"}, {:ex_aws, "~> 2.1.6"}, diff --git a/mix.lock b/mix.lock index d0d20f7d3..d3400da7a 100644 --- a/mix.lock +++ b/mix.lock @@ -7,7 +7,7 @@ "cachex": {:hex, :cachex, "3.4.0", "868b2959ea4aeb328c6b60ff66c8d5123c083466ad3c33d3d8b5f142e13101fb", [:mix], [{:eternal, "~> 1.2", [hex: :eternal, repo: "hexpm", optional: false]}, {:jumper, "~> 1.0", [hex: :jumper, repo: "hexpm", optional: false]}, {:sleeplocks, "~> 1.1", [hex: :sleeplocks, repo: "hexpm", optional: false]}, {:unsafe, "~> 1.0", [hex: :unsafe, repo: "hexpm", optional: false]}], "hexpm", "370123b1ab4fba4d2965fb18f87fd758325709787c8c5fce35b3fe80645ccbe5"}, "calendar": {:hex, :calendar, "1.0.0", "f52073a708528482ec33d0a171954ca610fe2bd28f1e871f247dc7f1565fa807", [:mix], [{:tzdata, "~> 0.5.20 or ~> 0.1.201603 or ~> 1.0", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm", "990e9581920c82912a5ee50e62ff5ef96da6b15949a2ee4734f935fdef0f0a6f"}, "captcha": {:git, "https://git.pleroma.social/pleroma/elixir-libraries/elixir-captcha.git", "e0f16822d578866e186a0974d65ad58cddc1e2ab", [ref: "e0f16822d578866e186a0974d65ad58cddc1e2ab"]}, - "castore": {:hex, :castore, "0.1.17", "ba672681de4e51ed8ec1f74ed624d104c0db72742ea1a5e74edbc770c815182f", [:mix], [], "hexpm", "d9844227ed52d26e7519224525cb6868650c272d4a3d327ce3ca5570c12163f9"}, + "castore": {:hex, :castore, "0.1.18", "deb5b9ab02400561b6f5708f3e7660fc35ca2d51bfc6a940d2f513f89c2975fc", [:mix], [], "hexpm", "61bbaf6452b782ef80b33cdb45701afbcf0a918a45ebe7e73f1130d661e66a06"}, "certifi": {:hex, :certifi, "2.9.0", "6f2a475689dd47f19fb74334859d460a2dc4e3252a3324bd2111b8f0429e7e21", [:rebar3], [], "hexpm", "266da46bdb06d6c6d35fde799bcb28d36d985d424ad7c08b5bb48f5b5cdd4641"}, "combine": {:hex, :combine, "0.10.0", "eff8224eeb56498a2af13011d142c5e7997a80c8f5b97c499f84c841032e429f", [:mix], [], "hexpm", "1b1dbc1790073076580d0d1d64e42eae2366583e7aecd455d1215b0d16f2451b"}, "comeonin": {:hex, :comeonin, "5.3.3", "2c564dac95a35650e9b6acfe6d2952083d8a08e4a89b93a481acb552b325892e", [:mix], [], "hexpm", "3e38c9c2cb080828116597ca8807bb482618a315bfafd98c90bc22a821cc84df"}, @@ -43,14 +43,14 @@ "fast_html": {:hex, :fast_html, "2.0.5", "c61760340606c1077ff1f196f17834056cb1dd3d5cb92a9f2cabf28bc6221c3c", [:make, :mix], [{:elixir_make, "~> 0.4", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.2.0", [hex: :nimble_pool, repo: "hexpm", optional: false]}], "hexpm", "605f4f4829443c14127694ebabb681778712ceecb4470ec32aa31012330e6506"}, "fast_sanitize": {:hex, :fast_sanitize, "0.2.3", "67b93dfb34e302bef49fec3aaab74951e0f0602fd9fa99085987af05bd91c7a5", [:mix], [{:fast_html, "~> 2.0", [hex: :fast_html, repo: "hexpm", optional: false]}, {:plug, "~> 1.8", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "e8ad286d10d0386e15d67d0ee125245ebcfbc7d7290b08712ba9013c8c5e56e2"}, "file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"}, - "finch": {:hex, :finch, "0.10.2", "9ad27d68270d879f73f26604bb2e573d40f29bf0e907064a9a337f90a16a0312", [:mix], [{:castore, "~> 0.1", [hex: :castore, repo: "hexpm", optional: false]}, {:mint, "~> 1.3", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.2", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "dd8b11b282072cec2ef30852283949c248bd5d2820c88d8acc89402b81db7550"}, + "finch": {:hex, :finch, "0.13.0", "c881e5460ec563bf02d4f4584079e62201db676ed4c0ef3e59189331c4eddf7b", [:mix], [{:castore, "~> 0.1", [hex: :castore, repo: "hexpm", optional: false]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.3", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.2.6", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "49957dcde10dcdc042a123a507a9c5ec5a803f53646d451db2f7dea696fba6cc"}, "flake_id": {:hex, :flake_id, "0.1.0", "7716b086d2e405d09b647121a166498a0d93d1a623bead243e1f74216079ccb3", [:mix], [{:base62, "~> 1.2", [hex: :base62, repo: "hexpm", optional: false]}, {:ecto, ">= 2.0.0", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm", "31fc8090fde1acd267c07c36ea7365b8604055f897d3a53dd967658c691bd827"}, "floki": {:hex, :floki, "0.33.1", "f20f1eb471e726342b45ccb68edb9486729e7df94da403936ea94a794f072781", [:mix], [{:html_entities, "~> 0.5.0", [hex: :html_entities, repo: "hexpm", optional: false]}], "hexpm", "461035fd125f13fdf30f243c85a0b1e50afbec876cbf1ceefe6fddd2e6d712c6"}, "gen_smtp": {:hex, :gen_smtp, "0.15.0", "9f51960c17769b26833b50df0b96123605a8024738b62db747fece14eb2fbfcc", [:rebar3], [], "hexpm", "29bd14a88030980849c7ed2447b8db6d6c9278a28b11a44cafe41b791205440f"}, "gettext": {:git, "https://github.com/tusooa/gettext.git", "72fb2496b6c5280ed911bdc3756890e7f38a4808", [ref: "72fb2496b6c5280ed911bdc3756890e7f38a4808"]}, "gun": {:hex, :gun, "2.0.0-rc.2", "7c489a32dedccb77b6e82d1f3c5a7dadfbfa004ec14e322cdb5e579c438632d2", [:make, :rebar3], [{:cowlib, "2.11.0", [hex: :cowlib, repo: "hexpm", optional: false]}], "hexpm", "6b9d1eae146410d727140dbf8b404b9631302ecc2066d1d12f22097ad7d254fc"}, "hackney": {:hex, :hackney, "1.18.1", "f48bf88f521f2a229fc7bae88cf4f85adc9cd9bcf23b5dc8eb6a1788c662c4f6", [:rebar3], [{:certifi, "~>2.9.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~>6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~>1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.3.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~>1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "a4ecdaff44297e9b5894ae499e9a070ea1888c84afdd1fd9b7b2bc384950128e"}, - "hpax": {:hex, :hpax, "0.1.1", "2396c313683ada39e98c20a75a82911592b47e5c24391363343bde74f82396ca", [:mix], [], "hexpm", "0ae7d5a0b04a8a60caf7a39fcf3ec476f35cc2cc16c05abea730d3ce6ac6c826"}, + "hpax": {:hex, :hpax, "0.1.2", "09a75600d9d8bbd064cdd741f21fc06fc1f4cf3d0fcc335e5aa19be1a7235c84", [:mix], [], "hexpm", "2c87843d5a23f5f16748ebe77969880e29809580efdaccd615cd3bed628a8c13"}, "html_entities": {:hex, :html_entities, "0.5.2", "9e47e70598da7de2a9ff6af8758399251db6dbb7eebe2b013f2bbd2515895c3c", [:mix], [], "hexpm", "c53ba390403485615623b9531e97696f076ed415e8d8058b1dbaa28181f4fdcc"}, "http_signatures": {:hex, :http_signatures, "0.1.1", "ca7ebc1b61542b163644c8c3b1f0e0f41037d35f2395940d3c6c7deceab41fd8", [:mix], [], "hexpm", "cc3b8a007322cc7b624c0c15eec49ee58ac977254ff529a3c482f681465942a3"}, "httpoison": {:hex, :httpoison, "1.8.1", "df030d96de89dad2e9983f92b0c506a642d4b1f4a819c96ff77d12796189c63e", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "35156a6d678d6d516b9229e208942c405cf21232edd632327ecfaf4fd03e79e0"}, From 7bbaa8f8e07044726c5b97b9ab8126ca41f2fd78 Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Mon, 7 Nov 2022 22:33:18 +0000 Subject: [PATCH 022/631] automatically trim loading *. prefixes on domain blocks --- CHANGELOG.md | 3 - lib/pleroma/web/activity_pub/mrf.ex | 2 + .../activity_pub/mrf/simple_policy_test.exs | 68 +++++++++---------- test/pleroma/web/activity_pub/mrf_test.exs | 2 +- 4 files changed, 37 insertions(+), 38 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 05d24a821..15472eda6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,9 +6,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## Unreleased -## UPGRADE NOTES -- Change your instance blocks to remove any `*.` prefixes. `example.com` will block `*.example.com` by default now - ## Added - Officially supported docker release - Ability to remove followers unilaterally without a block diff --git a/lib/pleroma/web/activity_pub/mrf.ex b/lib/pleroma/web/activity_pub/mrf.ex index 7b7f44646..0d4986e68 100644 --- a/lib/pleroma/web/activity_pub/mrf.ex +++ b/lib/pleroma/web/activity_pub/mrf.ex @@ -154,6 +154,8 @@ defp get_policies(_), do: [] # - https://extra.baddomain.net/ # Does NOT match the following: # - https://maybebaddomain.net/ + def subdomain_regex("*." <> domain), do: subdomain_regex(domain) + def subdomain_regex(domain) do ~r/^(.+\.)?#{Regex.escape(domain)}$/i end diff --git a/test/pleroma/web/activity_pub/mrf/simple_policy_test.exs b/test/pleroma/web/activity_pub/mrf/simple_policy_test.exs index 5f80c1629..0569bfed3 100644 --- a/test/pleroma/web/activity_pub/mrf/simple_policy_test.exs +++ b/test/pleroma/web/activity_pub/mrf/simple_policy_test.exs @@ -46,8 +46,8 @@ test "has a matching host" do end test "match with wildcard domain" do - clear_config([:mrf_simple, :media_removal], [{"remote.instance", "Whatever reason"}]) - media_message = build_media_message("sub.remote.instance") + clear_config([:mrf_simple, :media_removal], [{"*.remote.instance", "Whatever reason"}]) + media_message = build_media_message() local_message = build_local_message() assert SimplePolicy.filter(media_message) == @@ -81,8 +81,8 @@ test "has a matching host" do end test "match with wildcard domain" do - clear_config([:mrf_simple, :media_nsfw], [{"remote.instance", "yeah yeah"}]) - media_message = build_media_message("sub.remote.instance") + clear_config([:mrf_simple, :media_nsfw], [{"*.remote.instance", "yeah yeah"}]) + media_message = build_media_message() local_message = build_local_message() assert SimplePolicy.filter(media_message) == @@ -92,9 +92,9 @@ test "match with wildcard domain" do end end - defp build_media_message(domain \\ "remote.instance") do + defp build_media_message do %{ - "actor" => "https://#{domain}/users/bob", + "actor" => "https://remote.instance/users/bob", "type" => "Create", "object" => %{ "attachment" => [%{}], @@ -124,8 +124,8 @@ test "has a matching host" do end test "match with wildcard domain" do - clear_config([:mrf_simple, :report_removal], [{"remote.instance", "suya"}]) - report_message = build_report_message("sub.remote.instance") + clear_config([:mrf_simple, :report_removal], [{"*.remote.instance", "suya"}]) + report_message = build_report_message() local_message = build_local_message() assert {:reject, _} = SimplePolicy.filter(report_message) @@ -133,9 +133,9 @@ test "match with wildcard domain" do end end - defp build_report_message(domain \\ "remote.instance") do + defp build_report_message do %{ - "actor" => "https://#{domain}/users/bob", + "actor" => "https://remote.instance/users/bob", "type" => "Flag" } end @@ -143,7 +143,7 @@ defp build_report_message(domain \\ "remote.instance") do describe "when :federated_timeline_removal" do test "is empty" do clear_config([:mrf_simple, :federated_timeline_removal], []) - {_, ftl_message} = build_ftl_actor_and_message("https://remote.instance/users/bob") + {_, ftl_message} = build_ftl_actor_and_message() local_message = build_local_message() assert SimplePolicy.filter(ftl_message) == {:ok, ftl_message} @@ -151,7 +151,7 @@ test "is empty" do end test "has a matching host" do - {actor, ftl_message} = build_ftl_actor_and_message("https://remote.instance/users/bob") + {actor, ftl_message} = build_ftl_actor_and_message() ftl_message_actor_host = ftl_message @@ -172,7 +172,7 @@ test "has a matching host" do end test "match with wildcard domain" do - {actor, ftl_message} = build_ftl_actor_and_message("https://sub.remote.instance/users/bob") + {actor, ftl_message} = build_ftl_actor_and_message() ftl_message_actor_host = ftl_message @@ -181,7 +181,7 @@ test "match with wildcard domain" do |> Map.fetch!(:host) clear_config([:mrf_simple, :federated_timeline_removal], [ - {ftl_message_actor_host, "owo"} + {"*." <> ftl_message_actor_host, "owo"} ]) local_message = build_local_message() @@ -196,7 +196,7 @@ test "match with wildcard domain" do end test "has a matching host but only as:Public in to" do - {_actor, ftl_message} = build_ftl_actor_and_message("https://remote.instance/users/bob") + {_actor, ftl_message} = build_ftl_actor_and_message() ftl_message_actor_host = ftl_message @@ -253,8 +253,8 @@ test "obfuscates domains listed in :transparency_obfuscate_domains" do end end - defp build_ftl_actor_and_message(ap_id) do - actor = insert(:user, ap_id: ap_id) + defp build_ftl_actor_and_message do + actor = insert(:user) {actor, %{ @@ -282,9 +282,9 @@ test "activity has a matching host" do end test "activity matches with wildcard domain" do - clear_config([:mrf_simple, :reject], [{"remote.instance", ""}]) + clear_config([:mrf_simple, :reject], [{"*.remote.instance", ""}]) - remote_message = build_remote_message("sub.remote.instance") + remote_message = build_remote_message() assert {:reject, _} = SimplePolicy.filter(remote_message) end @@ -325,7 +325,7 @@ test "reject by URI object" do describe "when :followers_only" do test "is empty" do clear_config([:mrf_simple, :followers_only], []) - {_, ftl_message} = build_ftl_actor_and_message("https://remote.instance/users/alice") + {_, ftl_message} = build_ftl_actor_and_message() local_message = build_local_message() assert SimplePolicy.filter(ftl_message) == {:ok, ftl_message} @@ -412,10 +412,10 @@ test "activity has a matching host" do end test "activity matches with wildcard domain" do - clear_config([:mrf_simple, :accept], [{"remote.instance", ""}]) + clear_config([:mrf_simple, :accept], [{"*.remote.instance", ""}]) local_message = build_local_message() - remote_message = build_remote_message("sub.remote.instance") + remote_message = build_remote_message() assert SimplePolicy.filter(local_message) == {:ok, local_message} assert SimplePolicy.filter(remote_message) == {:ok, remote_message} @@ -457,9 +457,9 @@ test "has a matching host" do end test "match with wildcard domain" do - clear_config([:mrf_simple, :avatar_removal], [{"remote.instance", ""}]) + clear_config([:mrf_simple, :avatar_removal], [{"*.remote.instance", ""}]) - remote_user = build_remote_user("sub.remote.instance") + remote_user = build_remote_user() {:ok, filtered} = SimplePolicy.filter(remote_user) refute filtered["icon"] @@ -493,9 +493,9 @@ test "has a matching host" do end test "match with wildcard domain" do - clear_config([:mrf_simple, :banner_removal], [{"remote.instance", ""}]) + clear_config([:mrf_simple, :banner_removal], [{"*.remote.instance", ""}]) - remote_user = build_remote_user("sub.remote.instance") + remote_user = build_remote_user() {:ok, filtered} = SimplePolicy.filter(remote_user) refute filtered["image"] @@ -553,10 +553,10 @@ test "it rejects the deletion" do end describe "when :reject_deletes match with wildcard domain" do - setup do: clear_config([:mrf_simple, :reject_deletes], [{"remote.instance", ""}]) + setup do: clear_config([:mrf_simple, :reject_deletes], [{"*.remote.instance", ""}]) test "it rejects the deletion" do - deletion_message = build_remote_deletion_message("sub.remote.instance") + deletion_message = build_remote_deletion_message() assert {:reject, _} = SimplePolicy.filter(deletion_message) end @@ -570,13 +570,13 @@ defp build_local_message do } end - defp build_remote_message(domain \\ "remote.instance") do - %{"actor" => "https://#{domain}/users/bob"} + defp build_remote_message do + %{"actor" => "https://remote.instance/users/bob"} end - defp build_remote_user(domain \\ "remote.instance") do + defp build_remote_user do %{ - "id" => "https://#{domain}/users/bob", + "id" => "https://remote.instance/users/bob", "icon" => %{ "url" => "http://example.com/image.jpg", "type" => "Image" @@ -589,10 +589,10 @@ defp build_remote_user(domain \\ "remote.instance") do } end - defp build_remote_deletion_message(domain \\ "remote.instance") do + defp build_remote_deletion_message do %{ "type" => "Delete", - "actor" => "https://#{domain}/users/bob" + "actor" => "https://remote.instance/users/bob" } end end diff --git a/test/pleroma/web/activity_pub/mrf_test.exs b/test/pleroma/web/activity_pub/mrf_test.exs index ec4dab30f..f04c69afb 100644 --- a/test/pleroma/web/activity_pub/mrf_test.exs +++ b/test/pleroma/web/activity_pub/mrf_test.exs @@ -10,7 +10,7 @@ defmodule Pleroma.Web.ActivityPub.MRFTest do test "subdomains_regex/1" do assert MRF.subdomains_regex(["unsafe.tld", "*.unsafe.tld"]) == [ ~r/^(.+\.)?unsafe\.tld$/i, - ~r/^(.+\.)?\*\.unsafe\.tld$/i + ~r/^(.+\.)?unsafe\.tld$/i ] end From a0b8e3c84280c11ab43b7660414b64b55c1b7259 Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Tue, 8 Nov 2022 10:39:01 +0000 Subject: [PATCH 023/631] Don't mess with the cache on metadata update --- lib/pleroma/application.ex | 2 +- lib/pleroma/instances/instance.ex | 21 +++++++------------ test/pleroma/instances/instance_test.exs | 12 +++++------ .../web/admin_api/views/report_view_test.exs | 2 +- 4 files changed, 16 insertions(+), 21 deletions(-) diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex index a78924dfa..b9bcad40c 100644 --- a/lib/pleroma/application.ex +++ b/lib/pleroma/application.ex @@ -157,7 +157,7 @@ defp cachex_children do build_cachex("failed_proxy_url", limit: 2500), build_cachex("banned_urls", default_ttl: :timer.hours(24 * 30), limit: 5_000), build_cachex("translations", default_ttl: :timer.hours(24 * 30), limit: 2500), - build_cachex("instances", default_ttl: :timer.hours(24), limit: 2500) + build_cachex("instances", default_ttl: :timer.hours(24), ttl_interval: 1000, limit: 2500) ] end diff --git a/lib/pleroma/instances/instance.ex b/lib/pleroma/instances/instance.ex index fcf3181bf..5ee408f21 100644 --- a/lib/pleroma/instances/instance.ex +++ b/lib/pleroma/instances/instance.ex @@ -176,17 +176,14 @@ defp do_update_metadata(%URI{host: host} = uri, existing_record) do favicon = scrape_favicon(uri) nodeinfo = scrape_nodeinfo(uri) - {:ok, instance} = - existing_record - |> changeset(%{ - host: host, - favicon: favicon, - nodeinfo: nodeinfo, - metadata_updated_at: NaiveDateTime.utc_now() - }) - |> Repo.update() - - @cachex.put(:instances_cache, "instances:#{host}", instance) + existing_record + |> changeset(%{ + host: host, + favicon: favicon, + nodeinfo: nodeinfo, + metadata_updated_at: NaiveDateTime.utc_now() + }) + |> Repo.update() else {:discard, "Does not require update"} end @@ -205,8 +202,6 @@ defp do_update_metadata(%URI{host: host} = uri, existing_record) do metadata_updated_at: NaiveDateTime.utc_now() }) |> Repo.insert() - - @cachex.put(:instances_cache, "instances:#{host}", instance) end end diff --git a/test/pleroma/instances/instance_test.exs b/test/pleroma/instances/instance_test.exs index adc847da5..6ec55c7b7 100644 --- a/test/pleroma/instances/instance_test.exs +++ b/test/pleroma/instances/instance_test.exs @@ -136,7 +136,7 @@ test "Scrapes favicon URLs and nodeinfo" do } end) - assert {:ok, true} == + assert {:ok, %Instance{host: "favicon.example.org"}} = Instance.update_metadata(URI.parse("https://favicon.example.org/")) {:ok, instance} = Instance.get_cached_by_url("https://favicon.example.org/") @@ -177,7 +177,7 @@ test "Does not retain favicons that are too long" do } end) - assert {:ok, true} == + assert {:ok, %Instance{host: "long-favicon.example.org"}} = Instance.update_metadata(URI.parse("https://long-favicon.example.org/")) {:ok, instance} = Instance.get_cached_by_url("https://long-favicon.example.org/") @@ -214,7 +214,7 @@ test "Handles not getting a favicon URL properly" do end) refute capture_log(fn -> - assert {:ok, true} = + assert {:ok, %Instance{host: "no-favicon.example.org"}} = Instance.update_metadata(URI.parse("https://no-favicon.example.org/")) end) =~ "Instance.update_metadata(\"https://no-favicon.example.org/\") error: " end @@ -241,7 +241,7 @@ test "doesn't continue scraping nodeinfo if we can't find a link" do } end) - assert {:ok, true} == + assert {:ok, %Instance{host: "bad-nodeinfo.example.org"}} = Instance.update_metadata(URI.parse("https://bad-nodeinfo.example.org/")) {:ok, instance} = Instance.get_cached_by_url("https://bad-nodeinfo.example.org/") @@ -277,7 +277,7 @@ test "doesn't store bad json in the nodeinfo" do } end) - assert {:ok, true} == + assert {:ok, %Instance{host: "bad-nodeinfo.example.org"}} = Instance.update_metadata(URI.parse("https://bad-nodeinfo.example.org/")) {:ok, instance} = Instance.get_cached_by_url("https://bad-nodeinfo.example.org/") @@ -315,7 +315,7 @@ test "doesn't store incredibly long json nodeinfo" do } end) - assert {:ok, true} == + assert {:ok, %Instance{host: "bad-nodeinfo.example.org"}} = Instance.update_metadata(URI.parse("https://bad-nodeinfo.example.org/")) {:ok, instance} = Instance.get_cached_by_url("https://bad-nodeinfo.example.org/") diff --git a/test/pleroma/web/admin_api/views/report_view_test.exs b/test/pleroma/web/admin_api/views/report_view_test.exs index 093e2d95d..1c115528a 100644 --- a/test/pleroma/web/admin_api/views/report_view_test.exs +++ b/test/pleroma/web/admin_api/views/report_view_test.exs @@ -45,7 +45,7 @@ test "renders a report" do ReportView.render("show.json", Report.extract_report_info(activity)) |> Map.delete(:created_at) - assert result == expected + assert Jason.encode!(result) == Jason.encode!(expected) end test "includes reported statuses" do From 479aacb1b66349390c65372e142b4cb477f60c65 Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Tue, 8 Nov 2022 11:01:47 +0000 Subject: [PATCH 024/631] Add fallback for reports that don't have attached activities --- .../web/mastodon_api/views/status_view.ex | 364 +++++++++--------- .../web/admin_api/views/report_view_test.exs | 2 +- 2 files changed, 184 insertions(+), 182 deletions(-) diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex index b3a35526e..929641b84 100644 --- a/lib/pleroma/web/mastodon_api/views/status_view.ex +++ b/lib/pleroma/web/mastodon_api/views/status_view.ex @@ -209,212 +209,214 @@ def render( end def render("show.json", %{activity: %{data: %{"object" => _object}} = activity} = opts) do - object = Object.normalize(activity, fetch: false) + with %Object{} = object <- Object.normalize(activity, fetch: false) do + user = CommonAPI.get_user(activity.data["actor"]) + user_follower_address = user.follower_address - user = CommonAPI.get_user(activity.data["actor"]) - user_follower_address = user.follower_address + like_count = object.data["like_count"] || 0 + announcement_count = object.data["announcement_count"] || 0 - like_count = object.data["like_count"] || 0 - announcement_count = object.data["announcement_count"] || 0 + hashtags = Object.hashtags(object) + sensitive = object.data["sensitive"] || Enum.member?(hashtags, "nsfw") - hashtags = Object.hashtags(object) - sensitive = object.data["sensitive"] || Enum.member?(hashtags, "nsfw") + tags = Object.tags(object) - tags = Object.tags(object) + tag_mentions = + tags + |> Enum.filter(fn tag -> is_map(tag) and tag["type"] == "Mention" end) + |> Enum.map(fn tag -> tag["href"] end) - tag_mentions = - tags - |> Enum.filter(fn tag -> is_map(tag) and tag["type"] == "Mention" end) - |> Enum.map(fn tag -> tag["href"] end) + mentions = + (object.data["to"] ++ tag_mentions) + |> Enum.uniq() + |> Enum.map(fn + Pleroma.Constants.as_public() -> nil + ^user_follower_address -> nil + ap_id -> User.get_cached_by_ap_id(ap_id) + end) + |> Enum.filter(& &1) + |> Enum.map(fn user -> AccountView.render("mention.json", %{user: user}) end) - mentions = - (object.data["to"] ++ tag_mentions) - |> Enum.uniq() - |> Enum.map(fn - Pleroma.Constants.as_public() -> nil - ^user_follower_address -> nil - ap_id -> User.get_cached_by_ap_id(ap_id) - end) - |> Enum.filter(& &1) - |> Enum.map(fn user -> AccountView.render("mention.json", %{user: user}) end) + favorited = opts[:for] && opts[:for].ap_id in (object.data["likes"] || []) - favorited = opts[:for] && opts[:for].ap_id in (object.data["likes"] || []) + bookmarked = Activity.get_bookmark(activity, opts[:for]) != nil - bookmarked = Activity.get_bookmark(activity, opts[:for]) != nil + client_posted_this_activity = opts[:for] && user.id == opts[:for].id - client_posted_this_activity = opts[:for] && user.id == opts[:for].id + expires_at = + with true <- client_posted_this_activity, + %Oban.Job{scheduled_at: scheduled_at} <- + Pleroma.Workers.PurgeExpiredActivity.get_expiration(activity.id) do + scheduled_at + else + _ -> nil + end - expires_at = - with true <- client_posted_this_activity, - %Oban.Job{scheduled_at: scheduled_at} <- - Pleroma.Workers.PurgeExpiredActivity.get_expiration(activity.id) do - scheduled_at - else - _ -> nil - end + thread_muted? = + cond do + is_nil(opts[:for]) -> false + is_boolean(activity.thread_muted?) -> activity.thread_muted? + true -> CommonAPI.thread_muted?(opts[:for], activity) + end - thread_muted? = - cond do - is_nil(opts[:for]) -> false - is_boolean(activity.thread_muted?) -> activity.thread_muted? - true -> CommonAPI.thread_muted?(opts[:for], activity) - end + attachment_data = object.data["attachment"] || [] + attachments = render_many(attachment_data, StatusView, "attachment.json", as: :attachment) - attachment_data = object.data["attachment"] || [] - attachments = render_many(attachment_data, StatusView, "attachment.json", as: :attachment) + created_at = Utils.to_masto_date(object.data["published"]) - created_at = Utils.to_masto_date(object.data["published"]) + edited_at = + with %{"updated" => updated} <- object.data, + date <- Utils.to_masto_date(updated), + true <- date != "" do + date + else + _ -> + nil + end - edited_at = - with %{"updated" => updated} <- object.data, - date <- Utils.to_masto_date(updated), - true <- date != "" do - date - else - _ -> - nil - end + reply_to = get_reply_to(activity, opts) - reply_to = get_reply_to(activity, opts) + reply_to_user = reply_to && CommonAPI.get_user(reply_to.data["actor"]) - reply_to_user = reply_to && CommonAPI.get_user(reply_to.data["actor"]) + history_len = + 1 + + (Object.Updater.history_for(object.data) + |> Map.get("orderedItems") + |> length()) - history_len = - 1 + - (Object.Updater.history_for(object.data) - |> Map.get("orderedItems") - |> length()) + # See render("history.json", ...) for more details + # Here the implicit index of the current content is 0 + chrono_order = history_len - 1 - # See render("history.json", ...) for more details - # Here the implicit index of the current content is 0 - chrono_order = history_len - 1 + content = + object + |> render_content() - content = - object - |> render_content() - - content_html = - content - |> Activity.HTML.get_cached_scrubbed_html_for_activity( - User.html_filter_policy(opts[:for]), - activity, - "mastoapi:content:#{chrono_order}" - ) - - content_plaintext = - content - |> Activity.HTML.get_cached_stripped_html_for_activity( - activity, - "mastoapi:content:#{chrono_order}" - ) - - summary = object.data["summary"] || "" - - card = render("card.json", Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity)) - - url = - if user.local do - Pleroma.Web.Router.Helpers.o_status_url(Pleroma.Web.Endpoint, :notice, activity) - else - object.data["url"] || object.data["external_url"] || object.data["id"] - end - - direct_conversation_id = - with {_, nil} <- {:direct_conversation_id, opts[:direct_conversation_id]}, - {_, true} <- {:include_id, opts[:with_direct_conversation_id]}, - {_, %User{} = for_user} <- {:for_user, opts[:for]} do - Activity.direct_conversation_id(activity, for_user) - else - {:direct_conversation_id, participation_id} when is_integer(participation_id) -> - participation_id - - _e -> - nil - end - - emoji_reactions = - object.data - |> Map.get("reactions", []) - |> EmojiReactionController.filter_allowed_users( - opts[:for], - Map.get(opts, :with_muted, false) - ) - |> Stream.map(fn {emoji, users, url} -> - build_emoji_map(emoji, users, url, opts[:for]) - end) - |> Enum.to_list() - - # Status muted state (would do 1 request per status unless user mutes are preloaded) - muted = - thread_muted? || - UserRelationship.exists?( - get_in(opts, [:relationships, :user_relationships]), - :mute, - opts[:for], - user, - fn for_user, user -> User.mutes?(for_user, user) end + content_html = + content + |> Activity.HTML.get_cached_scrubbed_html_for_activity( + User.html_filter_policy(opts[:for]), + activity, + "mastoapi:content:#{chrono_order}" ) - {pinned?, pinned_at} = pin_data(object, user) + content_plaintext = + content + |> Activity.HTML.get_cached_stripped_html_for_activity( + activity, + "mastoapi:content:#{chrono_order}" + ) - quote = Activity.get_quoted_activity_from_object(object) + summary = object.data["summary"] || "" - %{ - id: to_string(activity.id), - uri: object.data["id"], - url: url, - account: - AccountView.render("show.json", %{ - user: user, - for: opts[:for] - }), - in_reply_to_id: reply_to && to_string(reply_to.id), - in_reply_to_account_id: reply_to_user && to_string(reply_to_user.id), - reblog: nil, - card: card, - content: content_html, - text: opts[:with_source] && get_source_text(object.data["source"]), - created_at: created_at, - edited_at: edited_at, - reblogs_count: announcement_count, - replies_count: object.data["repliesCount"] || 0, - favourites_count: like_count, - reblogged: reblogged?(activity, opts[:for]), - favourited: present?(favorited), - bookmarked: present?(bookmarked), - muted: muted, - pinned: pinned?, - sensitive: sensitive, - spoiler_text: summary, - visibility: get_visibility(object), - media_attachments: attachments, - poll: render(PollView, "show.json", object: object, for: opts[:for]), - mentions: mentions, - tags: build_tags(tags), - application: build_application(object.data["generator"]), - language: nil, - emojis: build_emojis(object.data["emoji"]), - quote_id: if(quote, do: quote.id, else: nil), - quote: maybe_render_quote(quote, opts), - emoji_reactions: emoji_reactions, - pleroma: %{ - local: activity.local, - conversation_id: get_context_id(activity), - context: object.data["context"], - in_reply_to_account_acct: reply_to_user && reply_to_user.nickname, - content: %{"text/plain" => content_plaintext}, - spoiler_text: %{"text/plain" => summary}, - expires_at: expires_at, - direct_conversation_id: direct_conversation_id, - thread_muted: thread_muted?, + card = render("card.json", Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity)) + + url = + if user.local do + Pleroma.Web.Router.Helpers.o_status_url(Pleroma.Web.Endpoint, :notice, activity) + else + object.data["url"] || object.data["external_url"] || object.data["id"] + end + + direct_conversation_id = + with {_, nil} <- {:direct_conversation_id, opts[:direct_conversation_id]}, + {_, true} <- {:include_id, opts[:with_direct_conversation_id]}, + {_, %User{} = for_user} <- {:for_user, opts[:for]} do + Activity.direct_conversation_id(activity, for_user) + else + {:direct_conversation_id, participation_id} when is_integer(participation_id) -> + participation_id + + _e -> + nil + end + + emoji_reactions = + object.data + |> Map.get("reactions", []) + |> EmojiReactionController.filter_allowed_users( + opts[:for], + Map.get(opts, :with_muted, false) + ) + |> Stream.map(fn {emoji, users, url} -> + build_emoji_map(emoji, users, url, opts[:for]) + end) + |> Enum.to_list() + + # Status muted state (would do 1 request per status unless user mutes are preloaded) + muted = + thread_muted? || + UserRelationship.exists?( + get_in(opts, [:relationships, :user_relationships]), + :mute, + opts[:for], + user, + fn for_user, user -> User.mutes?(for_user, user) end + ) + + {pinned?, pinned_at} = pin_data(object, user) + + quote = Activity.get_quoted_activity_from_object(object) + + %{ + id: to_string(activity.id), + uri: object.data["id"], + url: url, + account: + AccountView.render("show.json", %{ + user: user, + for: opts[:for] + }), + in_reply_to_id: reply_to && to_string(reply_to.id), + in_reply_to_account_id: reply_to_user && to_string(reply_to_user.id), + reblog: nil, + card: card, + content: content_html, + text: opts[:with_source] && get_source_text(object.data["source"]), + created_at: created_at, + edited_at: edited_at, + reblogs_count: announcement_count, + replies_count: object.data["repliesCount"] || 0, + favourites_count: like_count, + reblogged: reblogged?(activity, opts[:for]), + favourited: present?(favorited), + bookmarked: present?(bookmarked), + muted: muted, + pinned: pinned?, + sensitive: sensitive, + spoiler_text: summary, + visibility: get_visibility(object), + media_attachments: attachments, + poll: render(PollView, "show.json", object: object, for: opts[:for]), + mentions: mentions, + tags: build_tags(tags), + application: build_application(object.data["generator"]), + language: nil, + emojis: build_emojis(object.data["emoji"]), + quote_id: if(quote, do: quote.id, else: nil), + quote: maybe_render_quote(quote, opts), emoji_reactions: emoji_reactions, - parent_visible: visible_for_user?(reply_to, opts[:for]), - pinned_at: pinned_at - }, - akkoma: %{ - source: object.data["source"] + pleroma: %{ + local: activity.local, + conversation_id: get_context_id(activity), + context: object.data["context"], + in_reply_to_account_acct: reply_to_user && reply_to_user.nickname, + content: %{"text/plain" => content_plaintext}, + spoiler_text: %{"text/plain" => summary}, + expires_at: expires_at, + direct_conversation_id: direct_conversation_id, + thread_muted: thread_muted?, + emoji_reactions: emoji_reactions, + parent_visible: visible_for_user?(reply_to, opts[:for]), + pinned_at: pinned_at + }, + akkoma: %{ + source: object.data["source"] + } } - } + else + nil -> nil + end end def render("show.json", _) do diff --git a/test/pleroma/web/admin_api/views/report_view_test.exs b/test/pleroma/web/admin_api/views/report_view_test.exs index 1c115528a..d9ff48dde 100644 --- a/test/pleroma/web/admin_api/views/report_view_test.exs +++ b/test/pleroma/web/admin_api/views/report_view_test.exs @@ -3,7 +3,7 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.AdminAPI.ReportViewTest do - use Pleroma.DataCase, async: true + use Pleroma.DataCase, async: false import Pleroma.Factory From 2e895b6c0262e4a77e42225b2a1b1386edbcb4cd Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Tue, 8 Nov 2022 11:03:43 +0000 Subject: [PATCH 025/631] make metdata check a debug log --- lib/pleroma/instances/instance.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pleroma/instances/instance.ex b/lib/pleroma/instances/instance.ex index 5ee408f21..aed0cd2d0 100644 --- a/lib/pleroma/instances/instance.ex +++ b/lib/pleroma/instances/instance.ex @@ -159,7 +159,7 @@ def local do end def update_metadata(%URI{host: host} = uri) do - Logger.info("Checking metadata for #{host}") + Logger.debug("Checking metadata for #{host}") existing_record = Repo.get_by(Instance, %{host: host}) if reachable?(host) do From 4e8ab0deeb16e942bb677c5f0fc7dc6ba1508801 Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Tue, 8 Nov 2022 13:50:04 +0000 Subject: [PATCH 026/631] fix count of poll voters --- lib/pleroma/web/mastodon_api/views/poll_view.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pleroma/web/mastodon_api/views/poll_view.ex b/lib/pleroma/web/mastodon_api/views/poll_view.ex index 71bc8b949..aa6443754 100644 --- a/lib/pleroma/web/mastodon_api/views/poll_view.ex +++ b/lib/pleroma/web/mastodon_api/views/poll_view.ex @@ -68,7 +68,7 @@ defp options_and_votes_count(options) do end) end - defp voters_count(%{data: %{"voters" => [_ | _] = voters}}) do + defp voters_count(%{data: %{"voters" => voters}}) when is_list(voters) do length(voters) end From 0681a26dbb58b420105275fdaca11ec627257837 Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Tue, 8 Nov 2022 13:54:43 +0000 Subject: [PATCH 027/631] Remove unused pattern --- lib/pleroma/instances/instance.ex | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/lib/pleroma/instances/instance.ex b/lib/pleroma/instances/instance.ex index aed0cd2d0..27dbf7661 100644 --- a/lib/pleroma/instances/instance.ex +++ b/lib/pleroma/instances/instance.ex @@ -193,15 +193,14 @@ defp do_update_metadata(%URI{host: host} = uri, existing_record) do Logger.info("Creating metadata for #{host}") - {:ok, instance} = - %Instance{} - |> changeset(%{ - host: host, - favicon: favicon, - nodeinfo: nodeinfo, - metadata_updated_at: NaiveDateTime.utc_now() - }) - |> Repo.insert() + %Instance{} + |> changeset(%{ + host: host, + favicon: favicon, + nodeinfo: nodeinfo, + metadata_updated_at: NaiveDateTime.utc_now() + }) + |> Repo.insert() end end From 53fbe26c802e58325783fe005811747c652c6a47 Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Wed, 9 Nov 2022 13:22:44 +0000 Subject: [PATCH 028/631] reference "stable" in all URLs --- docs/docs/installation/migrating_from_source_otp_en.md | 2 +- docs/docs/installation/otp_en.md | 2 +- docs/docs/installation/verifying_otp_releases.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/docs/installation/migrating_from_source_otp_en.md b/docs/docs/installation/migrating_from_source_otp_en.md index 148564d9a..505f3cd6d 100644 --- a/docs/docs/installation/migrating_from_source_otp_en.md +++ b/docs/docs/installation/migrating_from_source_otp_en.md @@ -87,7 +87,7 @@ export FLAVOUR="amd64-musl" # Clone the release build into a temporary directory and unpack it # Replace `stable` with `unstable` if you want to run the unstable branch su akkoma -s $SHELL -lc " -curl 'https://akkoma-updates.s3-website.fr-par.scw.cloud/develop/akkoma-$FLAVOUR.zip' -o /tmp/akkoma.zip +curl 'https://akkoma-updates.s3-website.fr-par.scw.cloud/stable/akkoma-$FLAVOUR.zip' -o /tmp/akkoma.zip unzip /tmp/akkoma.zip -d /tmp/ " diff --git a/docs/docs/installation/otp_en.md b/docs/docs/installation/otp_en.md index 3e00d3262..3d5d2152b 100644 --- a/docs/docs/installation/otp_en.md +++ b/docs/docs/installation/otp_en.md @@ -123,7 +123,7 @@ export FLAVOUR="amd64-musl" # Clone the release build into a temporary directory and unpack it su akkoma -s $SHELL -lc " -curl 'https://akkoma-updates.s3-website.fr-par.scw.cloud/develop/akkoma-$FLAVOUR.zip' -o /tmp/akkoma.zip +curl 'https://akkoma-updates.s3-website.fr-par.scw.cloud/stable/akkoma-$FLAVOUR.zip' -o /tmp/akkoma.zip unzip /tmp/akkoma.zip -d /tmp/ " diff --git a/docs/docs/installation/verifying_otp_releases.md b/docs/docs/installation/verifying_otp_releases.md index 86dacfec2..5f1ac6949 100644 --- a/docs/docs/installation/verifying_otp_releases.md +++ b/docs/docs/installation/verifying_otp_releases.md @@ -4,7 +4,7 @@ All stable OTP releases are cryptographically signed, to allow you to verify the integrity if you choose to. Releases are signed with [Signify](https://man.openbsd.org/signify.1), -with [the public key in the main repository](https://akkoma.dev/AkkomaGang/akkoma/src/branch/develop/SIGNING_KEY.pub) +with [the public key in the main repository](https://akkoma.dev/AkkomaGang/akkoma/src/branch/stable/SIGNING_KEY.pub) Release URLs will always be of the form From cc6a0762022644ea751767ed6b7673e069aca855 Mon Sep 17 00:00:00 2001 From: floatingghost Date: Thu, 10 Nov 2022 03:16:32 +0000 Subject: [PATCH 029/631] Include requested_by in relationship (#260) Co-authored-by: FloatingGhost Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma/pulls/260 --- .../web/mastodon_api/views/account_view.ex | 13 +++++++------ .../mastodon_api/views/account_view_test.exs | 19 +++++++++++++++++++ 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex index cbb57aee6..a04ffaaf3 100644 --- a/lib/pleroma/web/mastodon_api/views/account_view.ex +++ b/lib/pleroma/web/mastodon_api/views/account_view.ex @@ -94,12 +94,12 @@ def render( followed_by = if following_relationships do - case FollowingRelationship.find(following_relationships, target, reading_user) do - %{state: :follow_accept} -> true - _ -> false - end + target_to_user_following_relation = + FollowingRelationship.find(following_relationships, target, reading_user) + + User.get_follow_state(target, reading_user, target_to_user_following_relation) else - User.following?(target, reading_user) + User.get_follow_state(target, reading_user) end subscribing = @@ -115,7 +115,7 @@ def render( %{ id: to_string(target.id), following: follow_state == :follow_accept, - followed_by: followed_by, + followed_by: followed_by == :follow_accept, blocking: UserRelationship.exists?( user_relationships, @@ -151,6 +151,7 @@ def render( subscribing: subscribing, notifying: subscribing, requested: follow_state == :follow_pending, + requested_by: followed_by == :follow_pending, domain_blocking: User.blocks_domain?(reading_user, target), showing_reblogs: not UserRelationship.exists?( diff --git a/test/pleroma/web/mastodon_api/views/account_view_test.exs b/test/pleroma/web/mastodon_api/views/account_view_test.exs index d1903af80..f4a5f4d50 100644 --- a/test/pleroma/web/mastodon_api/views/account_view_test.exs +++ b/test/pleroma/web/mastodon_api/views/account_view_test.exs @@ -347,6 +347,7 @@ defp test_relationship_rendering(user, other_user, expected_result) do subscribing: false, notifying: false, requested: false, + requested_by: false, domain_blocking: false, showing_reblogs: true, endorsed: false, @@ -432,6 +433,24 @@ test "represent a relationship for the user with a pending follow request" do end end + test "represent a relationship for a user with an inbound pending follow request" do + follower = insert(:user) + followed = insert(:user, is_locked: true) + + {:ok, follower, followed, _} = CommonAPI.follow(follower, followed) + + follower = User.get_cached_by_id(follower.id) + followed = User.get_cached_by_id(followed.id) + + expected = + Map.merge( + @blank_response, + %{requested_by: true, followed_by: false, id: to_string(follower.id)} + ) + + test_relationship_rendering(followed, follower, expected) + end + test "returns the settings store if the requesting user is the represented user and it's requested specifically" do user = insert(:user, pleroma_settings_store: %{fe: "test"}) From f7c1e15d08eaec176f5e7c33bfe9f8783c2caa49 Mon Sep 17 00:00:00 2001 From: Weblate Date: Fri, 19 Aug 2022 09:25:17 +0000 Subject: [PATCH 030/631] Translated using Weblate (Spanish) Currently translated at 21.6% (23 of 106 strings) Co-authored-by: mint Translate-URL: http://translate.akkoma.dev/projects/akkoma/akkoma-backend-errors/es/ Translation: Pleroma fe/Akkoma Backend (Errors) --- priv/gettext/es/LC_MESSAGES/errors.po | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/priv/gettext/es/LC_MESSAGES/errors.po b/priv/gettext/es/LC_MESSAGES/errors.po index 0a6fceaad..166e2fb98 100644 --- a/priv/gettext/es/LC_MESSAGES/errors.po +++ b/priv/gettext/es/LC_MESSAGES/errors.po @@ -3,16 +3,16 @@ msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2020-09-09 09:49+0000\n" -"PO-Revision-Date: 2020-09-11 21:26+0000\n" -"Last-Translator: tarteka \n" -"Language-Team: Spanish \n" +"PO-Revision-Date: 2022-08-19 09:25+0000\n" +"Last-Translator: mint \n" +"Language-Team: Spanish \n" "Language: es\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.0.4\n" +"X-Generator: Weblate 4.13.1\n" ## This file is a PO Template file. ## @@ -66,8 +66,8 @@ msgstr[1] "debe tener %{count} caracteres" msgid "should have %{count} item(s)" msgid_plural "should have %{count} item(s)" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "debería tener %{count} item" +msgstr[1] "debería tener %{count} items" msgid "should be at least %{count} character(s)" msgid_plural "should be at least %{count} character(s)" From f2c6749b57af4967d8a1e796d00f825ca269ca14 Mon Sep 17 00:00:00 2001 From: Weblate Date: Fri, 19 Aug 2022 09:25:17 +0000 Subject: [PATCH 031/631] Update translation files Updated by "Squash Git commits" hook in Weblate. Translation: Pleroma fe/Akkoma Backend (Errors) Translate-URL: http://translate.akkoma.dev/projects/akkoma/akkoma-backend-errors/ --- priv/gettext/nl/LC_MESSAGES/posix_errors.po | 163 ++++++++++++++++++++ 1 file changed, 163 insertions(+) create mode 100644 priv/gettext/nl/LC_MESSAGES/posix_errors.po diff --git a/priv/gettext/nl/LC_MESSAGES/posix_errors.po b/priv/gettext/nl/LC_MESSAGES/posix_errors.po new file mode 100644 index 000000000..d94b0c8e2 --- /dev/null +++ b/priv/gettext/nl/LC_MESSAGES/posix_errors.po @@ -0,0 +1,163 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2022-08-16 10:49+0000\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: nl\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Translate Toolkit 3.7.1\n" + +## This file is a PO Template file. +## +## `msgid`s here are often extracted from source code. +## Add new translations manually only if they're dynamic +## translations that can't be statically extracted. +## +## Run `mix gettext.extract` to bring this file up to +## date. Leave `msgstr`s empty as changing them here as no +## effect: edit them in PO (`.po`) files instead. +msgid "eperm" +msgstr "" + +msgid "eacces" +msgstr "" + +msgid "eagain" +msgstr "" + +msgid "ebadf" +msgstr "" + +msgid "ebadmsg" +msgstr "" + +msgid "ebusy" +msgstr "" + +msgid "edeadlk" +msgstr "" + +msgid "edeadlock" +msgstr "" + +msgid "edquot" +msgstr "" + +msgid "eexist" +msgstr "" + +msgid "efault" +msgstr "" + +msgid "efbig" +msgstr "" + +msgid "eftype" +msgstr "" + +msgid "eintr" +msgstr "" + +msgid "einval" +msgstr "" + +msgid "eio" +msgstr "" + +msgid "eisdir" +msgstr "" + +msgid "eloop" +msgstr "" + +msgid "emfile" +msgstr "" + +msgid "emlink" +msgstr "" + +msgid "emultihop" +msgstr "" + +msgid "enametoolong" +msgstr "" + +msgid "enfile" +msgstr "" + +msgid "enobufs" +msgstr "" + +msgid "enodev" +msgstr "" + +msgid "enolck" +msgstr "" + +msgid "enolink" +msgstr "" + +msgid "enoent" +msgstr "" + +msgid "enomem" +msgstr "" + +msgid "enospc" +msgstr "" + +msgid "enosr" +msgstr "" + +msgid "enostr" +msgstr "" + +msgid "enosys" +msgstr "" + +msgid "enotblk" +msgstr "" + +msgid "enotdir" +msgstr "" + +msgid "enotsup" +msgstr "" + +msgid "enxio" +msgstr "" + +msgid "eopnotsupp" +msgstr "" + +msgid "eoverflow" +msgstr "" + +msgid "epipe" +msgstr "" + +msgid "erange" +msgstr "" + +msgid "erofs" +msgstr "" + +msgid "espipe" +msgstr "" + +msgid "esrch" +msgstr "" + +msgid "estale" +msgstr "" + +msgid "etxtbsy" +msgstr "" + +msgid "exdev" +msgstr "" From c5b6cb746f2ae6f54f9e3d84c49c11b86548ecf3 Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Thu, 10 Nov 2022 03:17:00 +0000 Subject: [PATCH 032/631] add requested_by changelog entry --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 15472eda6..0e71b2127 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Officially supported docker release - Ability to remove followers unilaterally without a block - Scraping of nodeinfo from remote instances to display instance info +- `requested_by` in relationships when the user has requested to follow you ## Changes - Follows no longer override domain blocks, a domain block is final From 66eb844bd2e7d7f07dcb07624d695672dfedd89d Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Thu, 10 Nov 2022 03:38:10 +0000 Subject: [PATCH 033/631] Update documentation builder --- docs/Pipfile.lock | 95 +++++++++++++++++++++++++++++++---------------- 1 file changed, 63 insertions(+), 32 deletions(-) diff --git a/docs/Pipfile.lock b/docs/Pipfile.lock index ae39a2776..c7b8f50db 100644 --- a/docs/Pipfile.lock +++ b/docs/Pipfile.lock @@ -14,6 +14,22 @@ ] }, "default": { + "certifi": { + "hashes": [ + "sha256:0d9c601124e5a6ba9712dbc60d9c53c21e34f5f641fe83002317394311bdce14", + "sha256:90c1a32f1d68f940488354e36370f6cca89f0f106db09518524c88d6ed83f382" + ], + "markers": "python_version >= '3.6'", + "version": "==2022.9.24" + }, + "charset-normalizer": { + "hashes": [ + "sha256:5a3d016c7c547f69d6f81fb0db9449ce888b418b5b9952cc5e6e66843e9dd845", + "sha256:83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f" + ], + "markers": "python_version >= '3.6'", + "version": "==2.1.1" + }, "click": { "hashes": [ "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e", @@ -29,13 +45,13 @@ ], "version": "==2.1.0" }, - "importlib-metadata": { + "idna": { "hashes": [ - "sha256:637245b8bab2b6502fcbc752cc4b7a6f6243bb02b31c5c26156ad103d3d45670", - "sha256:7401a975809ea1fdc658c3aa4f78cc2195a0e019c5cbc4c06122884e9ae80c23" + "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4", + "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2" ], - "markers": "python_version >= '3.7'", - "version": "==4.12.0" + "markers": "python_version >= '3.5'", + "version": "==3.4" }, "jinja2": { "hashes": [ @@ -55,10 +71,10 @@ }, "markdown-include": { "hashes": [ - "sha256:6f5d680e36f7780c7f0f61dca53ca581bd50d1b56137ddcd6353efafa0c3e4a2" + "sha256:a06183b7c7225e73112737acdc6fe0ac0686c39457234eeb5ede23881fed001d" ], "index": "pypi", - "version": "==0.6.0" + "version": "==0.7.0" }, "markupsafe": { "hashes": [ @@ -116,27 +132,27 @@ }, "mkdocs": { "hashes": [ - "sha256:26bd2b03d739ac57a3e6eed0b7bcc86168703b719c27b99ad6ca91dc439aacde", - "sha256:b504405b04da38795fec9b2e5e28f6aa3a73bb0960cb6d5d27ead28952bd35ea" + "sha256:8947af423a6d0facf41ea1195b8e1e8c85ad94ac95ae307fe11232e0424b11c5", + "sha256:c8856a832c1e56702577023cd64cc5f84948280c1c0fcc6af4cd39006ea6aa8c" ], - "markers": "python_version >= '3.6'", - "version": "==1.3.0" + "markers": "python_version >= '3.7'", + "version": "==1.4.2" }, "mkdocs-material": { "hashes": [ - "sha256:263f2721f3abe533b61f7c8bed435a0462620912742c919821ac2d698b4bfe67", - "sha256:dc82b667d2a83f0de581b46a6d0949732ab77e7638b87ea35b770b33bc02e75a" + "sha256:143ea55843b3747b640e1110824d91e8a4c670352380e166e64959f9abe98862", + "sha256:45eeabb23d2caba8fa3b85c91d9ec8e8b22add716e9bba8faf16d56af8aa5622" ], "index": "pypi", - "version": "==8.3.9" + "version": "==8.5.9" }, "mkdocs-material-extensions": { "hashes": [ - "sha256:a82b70e533ce060b2a5d9eb2bc2e1be201cf61f901f93704b4acf6e3d5983a44", - "sha256:bfd24dfdef7b41c312ede42648f9eb83476ea168ec163b613f9abd12bbfddba2" + "sha256:96ca979dae66d65c2099eefe189b49d5ac62f76afb59c38e069ffc7cf3c131ec", + "sha256:bcc2e5fc70c0ec50e59703ee6e639d87c7e664c0c441c014ea84461a90f1e902" ], - "markers": "python_version >= '3.6'", - "version": "==1.0.3" + "markers": "python_version >= '3.7'", + "version": "==1.1" }, "packaging": { "hashes": [ @@ -148,19 +164,19 @@ }, "pygments": { "hashes": [ - "sha256:5eb116118f9612ff1ee89ac96437bb6b49e8f04d8a13b514ba26f620208e26eb", - "sha256:dc9c10fb40944260f6ed4c688ece0cd2048414940f1cea51b8b226318411c519" + "sha256:56a8508ae95f98e2b9bdf93a6be5ae3f7d8af858b43e02c5a2ff083726be40c1", + "sha256:f643f331ab57ba3c9d89212ee4a2dabc6e94f117cf4eefde99a0574720d14c42" ], "markers": "python_version >= '3.6'", - "version": "==2.12.0" + "version": "==2.13.0" }, "pymdown-extensions": { "hashes": [ - "sha256:3ef2d998c0d5fa7eb09291926d90d69391283561cf6306f85cd588a5eb5befa0", - "sha256:ec141c0f4983755349f0c8710416348d1a13753976c028186ed14f190c8061c4" + "sha256:1bd4a173095ef8c433b831af1f3cb13c10883be0c100ae613560668e594651f7", + "sha256:8e62688a8b1128acd42fa823f3d429d22f4284b5e6dd4d3cd56721559a5a211b" ], "markers": "python_version >= '3.7'", - "version": "==9.5" + "version": "==9.8" }, "pyparsing": { "hashes": [ @@ -180,6 +196,7 @@ }, "pyyaml": { "hashes": [ + "sha256:01b45c0191e6d66c470b6cf1b9531a771a83c1c4208272ead47a3ae4f2f603bf", "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293", "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b", "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57", @@ -191,26 +208,32 @@ "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287", "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513", "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0", + "sha256:432557aa2c09802be39460360ddffd48156e30721f5e8d917f01d31694216782", "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0", "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92", "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f", "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2", "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc", + "sha256:81957921f441d50af23654aa6c5e5eaf9b06aba7f0a19c18a538dc7ef291c5a1", "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c", "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86", "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4", "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c", "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34", "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b", + "sha256:afa17f5bc4d1b10afd4466fd3a44dc0e245382deca5b3c353d8b757f9e3ecb8d", "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c", "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb", + "sha256:bfaef573a63ba8923503d27530362590ff4f576c626d86a9fed95822a8255fd7", "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737", "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3", "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d", + "sha256:d4b0ba9512519522b118090257be113b9468d804b19d63c71dbcf4a48fa32358", "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53", "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78", "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803", "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a", + "sha256:dbad0e9d368bb989f4515da330b88a057617d16b6a8245084f1b05400f24609f", "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174", "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5" ], @@ -225,6 +248,14 @@ "markers": "python_version >= '3.6'", "version": "==0.1" }, + "requests": { + "hashes": [ + "sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983", + "sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349" + ], + "markers": "python_version >= '3.7' and python_version < '4'", + "version": "==2.28.1" + }, "six": { "hashes": [ "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", @@ -233,6 +264,14 @@ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==1.16.0" }, + "urllib3": { + "hashes": [ + "sha256:3fa96cf423e6987997fc326ae8df396db2a8b7c667747d47ddd8ecba91f4a74e", + "sha256:b930dd878d5a8afb066a637fbb35144fe7901e3b209d1cd4f524bd0e9deee997" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5' and python_version < '4'", + "version": "==1.26.12" + }, "watchdog": { "hashes": [ "sha256:083171652584e1b8829581f965b9b7723ca5f9a2cd7e20271edf264cfd7c1412", @@ -263,14 +302,6 @@ ], "markers": "python_version >= '3.6'", "version": "==2.1.9" - }, - "zipp": { - "hashes": [ - "sha256:56bf8aadb83c24db6c4b577e13de374ccfb67da2078beba1d037c17980bf43ad", - "sha256:c4f6e5bbf48e74f7a38e7cc5b0480ff42b0ae5178957d564d18932525d5cf099" - ], - "markers": "python_version >= '3.7'", - "version": "==3.8.0" } }, "develop": {} From 539c6d6666aa7ec30a80f1a20f63c8908da2b53b Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Thu, 10 Nov 2022 03:40:36 +0000 Subject: [PATCH 034/631] update requirements.txt --- docs/requirements.txt | 174 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 155 insertions(+), 19 deletions(-) diff --git a/docs/requirements.txt b/docs/requirements.txt index 70fbd9dc4..3167d24b5 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,22 +1,158 @@ -click==8.1.3 -ghp-import==2.1.0 -importlib-metadata==4.12.0 -Jinja2==3.1.2 -Markdown==3.3.7 -markdown-include==0.6.0 -MarkupSafe==2.1.1 -mergedeep==1.3.4 -mkdocs==1.3.0 -mkdocs-bootswatch==1.1 -mkdocs-material==8.1.8 -mkdocs-material-extensions==1.0.3 +appdirs==1.4.4 +arrow==1.2.2 +astroid==2.8.5 +attrs==21.2.0 +aws-sam-translator==1.40.0 +aws-xray-sdk==2.8.0 +awscli-local==0.17 +backports.entry-points-selectable==1.1.0 +bcrypt==3.2.0 +binaryornot==0.4.4 +black==19.10b0 +bleach==4.1.0 +blurhash==1.1.4 +boto==2.49.0 +boto3==1.20.7 +botocore==1.23.7 +certifi==2021.5.30 +cffi==1.15.0 +cfn-lint==0.56.1 +chardet==4.0.0 +charset-normalizer==2.0.7 +Cheetah3==3.2.6.post1 +cli-routed==1.0.0 +click==8.0.3 +colorama==0.4.4 +colored==1.4.3 +confpy==0.11.0 +cookiecutter==1.7.3 +cosmos-release==1.0 +coverage==6.1.2 +cryptography==35.0.0 +decorator==5.1.1 +distlib==0.3.3 +distro==1.7.0 +docker==5.0.3 +docker-compose==1.29.2 +dockerpty==0.4.1 +docopt==0.6.2 +docutils==0.18 +ecdsa==0.14.1 +emoji==1.7.0 +entrypoints==0.3 +execnet==1.9.0 +filelock==3.3.0 +flake8==3.7.8 +Flask==2.0.2 +Flask-Cors==3.0.10 +freezegun==1.1.0 +future==0.18.2 +humanize==4.0.0 +idna==3.3 +importlib-metadata==4.8.2 +inflection==0.3.1 +iniconfig==1.1.1 +isort==5.10.1 +itsdangerous==2.0.1 +jedi==0.17.2 +jeepney==0.7.1 +Jinja2==3.0.3 +jinja2-time==0.2.0 +jmespath==0.10.0 +jschema-to-python==1.2.3 +jsondiff==1.3.0 +jsonpatch==1.32 +jsonpickle==2.0.0 +jsonpointer==2.2 +jsonschema==3.2.0 +junit-xml==1.9 +keyring==23.2.1 +lambda-repository-cli==0.6.0 +lazy-object-proxy==1.6.0 +localstack-client==1.26 +lxml==4.6.4 +MarkupSafe==2.0.1 +Mastodon.py==1.5.0 +mccabe==0.6.1 +mock==4.0.3 +mutagen==1.45.1 +networkx==2.6.3 +ordereddict==1.1 packaging==21.3 -Pygments==2.11.2 -pymdown-extensions==9.1 -pyparsing==3.0.9 +paramiko==2.10.3 +parso==0.7.1 +pathspec==0.9.0 +pbr==5.8.0 +pipenv==2021.5.29 +pkginfo==1.7.1 +platformdirs==2.4.0 +pluggy==1.0.0 +poyo==0.5.0 +prompt-toolkit==3.0.22 +psutil==5.9.0 +py==1.11.0 +pyaml==21.10.1 +pyasn1==0.4.8 +pycodestyle==2.5.0 +pycparser==2.21 +pycryptodomex==3.14.1 +pycurl==7.44.1 +pyflakes==2.1.1 +Pygments==2.10.0 +pylint==2.11.1 +pymongo==4.0.1 +PyNaCl==1.5.0 +pyparsing==3.0.6 +pyrsistent==0.18.0 +pytest==6.2.5 +pytest-cov==3.0.0 +pytest-forked==1.3.0 +pytest-xdist==2.4.0 python-dateutil==2.8.2 -PyYAML==6.0 -pyyaml_env_tag==0.1 +python-dotenv==0.20.0 +python-jose==3.3.0 +python-jsonrpc-server==0.4.0 +python-language-server==0.36.2 +python-magic==0.4.25 +python-slugify==6.1.2 +pytz==2021.3 +PyYAML==5.4.1 +readme-renderer==30.0 +regex==2019.11.1 +requests==2.26.0 +requests-toolbelt==0.9.1 +requirements-parser==0.3.1 +responses==0.16.0 +rfc3986==1.5.0 +rpmvenv==0.25.0 +rsa==4.7.2 +s3transfer==0.5.0 +sarif-om==1.0.4 +SecretStorage==3.3.1 +semver==2.9.1 six==1.16.0 -watchdog==2.1.9 -zipp==3.8.0 +sshpubkeys==3.3.1 +sure==2.0.0 +text-unidecode==1.3 +texttable==1.6.4 +toml==0.10.2 +tomli==1.2.2 +tootstream==0.3.8.1 +tqdm==4.62.3 +twine==3.6.0 +typed-ast==1.5.0 +types-setuptools==57.4.7 +ujson==4.2.0 +urllib3==1.26.7 +venvctrl==0.4.2 +virtualenv==20.8.1 +virtualenv-clone==0.5.7 +wcwidth==0.2.5 +webencodings==0.5.1 +websocket-client==0.59.0 +websockets==10.2 +Werkzeug==2.0.2 +wrapt==1.13.3 +xmltodict==0.12.0 +yt-dlp==2022.2.4 +zipp==3.6.0 From f8b4e360a0d11a9c875455ed83122ffa39ee9eee Mon Sep 17 00:00:00 2001 From: Eloy Degen Date: Thu, 10 Nov 2022 10:00:39 +0100 Subject: [PATCH 035/631] Fix typo in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 74b8919e4..212f99c60 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ This is a fork of Pleroma, which is a microblogging server software that can federate (= exchange messages with) other servers that support ActivityPub. What that means is that you can host a server for yourself or your friends and stay in control of your online identity, but still exchange messages with people on larger servers. Akkoma will federate with all servers that implement ActivityPub, like Friendica, GNU Social, Hubzilla, Mastodon, Misskey, Peertube, and Pixelfed. -Akkoma is written in Elixir and uses PostgresSQL for data storage. +Akkoma is written in Elixir and uses PostgreSQL for data storage. For clients it supports the [Mastodon client API](https://docs.joinmastodon.org/api/guidelines/) with Pleroma extensions (see the API section on ). From dcc36df8cf97122308aa1616285064910cbdf7c5 Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Thu, 10 Nov 2022 10:55:57 +0000 Subject: [PATCH 036/631] add manual deploy for docs --- .gitignore | 1 + docs/Makefile | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/.gitignore b/.gitignore index f9de4ed49..14373fb8c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ # App artifacts docs/site +*.zip *.sw* secret /_build diff --git a/docs/Makefile b/docs/Makefile index 022459cf0..85b6dee65 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -1,9 +1,14 @@ all: install pipenv run mkdocs build +branch := $(shell git rev-parse --abbrev-ref HEAD) install: pipenv install clean: rm -rf site serve: pipenv run python3 -m http.server -d site +zip: + zip -r docs.zip site/* +deploy: + cd site && rclone copy . scaleway:akkoma-docs/$(branch) From bab1ab5b6c74de5f02d9ddd06f0026efa547c2a5 Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Thu, 10 Nov 2022 11:54:12 +0000 Subject: [PATCH 037/631] strip \r and \r from content-disposition filenames --- lib/pleroma/web/plugs/uploaded_media.ex | 9 ++++++++- test/pleroma/web/plugs/uploaded_media_plug_test.exs | 11 +++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/lib/pleroma/web/plugs/uploaded_media.ex b/lib/pleroma/web/plugs/uploaded_media.ex index 7b87d8f17..72f20e8de 100644 --- a/lib/pleroma/web/plugs/uploaded_media.ex +++ b/lib/pleroma/web/plugs/uploaded_media.ex @@ -35,7 +35,7 @@ def call(%{request_path: <<"/", @path, "/", file::binary>>} = conn, opts) do conn = case fetch_query_params(conn) do %{query_params: %{"name" => name}} = conn -> - name = String.replace(name, "\"", "\\\"") + name = escape_header_value(name) put_resp_header(conn, "content-disposition", "filename=\"#{name}\"") @@ -98,4 +98,11 @@ defp get_media(conn, unknown, _) do |> send_resp(:internal_server_error, dgettext("errors", "Internal Error")) |> halt() end + + defp escape_header_value(value) do + value + |> String.replace("\"", "\\\"") + |> String.replace("\\r", "") + |> String.replace("\\n", "") + end end diff --git a/test/pleroma/web/plugs/uploaded_media_plug_test.exs b/test/pleroma/web/plugs/uploaded_media_plug_test.exs index 75f313282..c71a7e789 100644 --- a/test/pleroma/web/plugs/uploaded_media_plug_test.exs +++ b/test/pleroma/web/plugs/uploaded_media_plug_test.exs @@ -40,4 +40,15 @@ test "sends Content-Disposition header when name param is set", %{ &(&1 == {"content-disposition", "filename=\"\\\"cofe\\\".gif\""}) ) end + + test "removes control characters from the Content-Disposition header", %{ + attachment_url: attachment_url + } do + conn = get(build_conn(), attachment_url <> "?name=\"cofe\".gif\\r\\n") + + assert Enum.any?( + conn.resp_headers, + &(&1 == {"content-disposition", "filename=\"\\\"cofe\\\".gif\""}) + ) + end end From ac0c00cdee239e6bc37c0df2bfdb9f0ec1d24606 Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Thu, 10 Nov 2022 17:26:51 +0000 Subject: [PATCH 038/631] Add media sources to connect-src if media proxy is enabled --- lib/pleroma/web/plugs/http_security_plug.ex | 14 ++++++-------- test/pleroma/web/plugs/http_security_plug_test.exs | 8 ++++++++ 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/lib/pleroma/web/plugs/http_security_plug.ex b/lib/pleroma/web/plugs/http_security_plug.ex index 3e8e931d1..43b075447 100644 --- a/lib/pleroma/web/plugs/http_security_plug.ex +++ b/lib/pleroma/web/plugs/http_security_plug.ex @@ -104,14 +104,12 @@ defp csp_string do {[img_src, " https:"], [media_src, " https:"]} end - connect_src = ["connect-src 'self' blob: ", static_url, ?\s, websocket_url] - - connect_src = - if Config.get(:env) == :dev do - [connect_src, " http://localhost:3035/"] - else - connect_src - end + connect_src = if Config.get([:media_proxy, :enabled]) do + sources = build_csp_multimedia_source_list() + ["connect-src 'self' blob: ", static_url, ?\s, websocket_url, ?\s, sources] + else + ["connect-src 'self' blob: ", static_url, ?\s, websocket_url] + end script_src = if Config.get(:env) == :dev do diff --git a/test/pleroma/web/plugs/http_security_plug_test.exs b/test/pleroma/web/plugs/http_security_plug_test.exs index eb94cd665..7f85f4a11 100644 --- a/test/pleroma/web/plugs/http_security_plug_test.exs +++ b/test/pleroma/web/plugs/http_security_plug_test.exs @@ -100,12 +100,14 @@ test "media_proxy with base_url", %{conn: conn} do url = "https://example.com" clear_config([:media_proxy, :base_url], url) assert_media_img_src(conn, url) + assert_connect_src(conn, url) end test "upload with base url", %{conn: conn} do url = "https://example2.com" clear_config([Pleroma.Upload, :base_url], url) assert_media_img_src(conn, url) + assert_connect_src(conn, url) end test "with S3 public endpoint", %{conn: conn} do @@ -138,6 +140,12 @@ defp assert_media_img_src(conn, url) do assert csp =~ "img-src 'self' data: blob: #{url};" end + defp assert_connect_src(conn, url) do + conn = get(conn, "/api/v1/instance") + [csp] = Conn.get_resp_header(conn, "content-security-policy") + assert csp =~ ~r/connect-src 'self' blob: [^;]+ #{url}/ + end + test "it does not send CSP headers when disabled", %{conn: conn} do clear_config([:http_security, :enabled], false) From 634463ff64b0e32bd0b247c0f9b011928acf2b72 Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Fri, 11 Nov 2022 16:07:07 +0000 Subject: [PATCH 039/631] fix requirements --- docs/requirements.txt | 178 ++++++------------------------------------ 1 file changed, 23 insertions(+), 155 deletions(-) diff --git a/docs/requirements.txt b/docs/requirements.txt index 3167d24b5..d67bbf65f 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,158 +1,26 @@ -appdirs==1.4.4 -arrow==1.2.2 -astroid==2.8.5 -attrs==21.2.0 -aws-sam-translator==1.40.0 -aws-xray-sdk==2.8.0 -awscli-local==0.17 -backports.entry-points-selectable==1.1.0 -bcrypt==3.2.0 -binaryornot==0.4.4 -black==19.10b0 -bleach==4.1.0 -blurhash==1.1.4 -boto==2.49.0 -boto3==1.20.7 -botocore==1.23.7 -certifi==2021.5.30 -cffi==1.15.0 -cfn-lint==0.56.1 -chardet==4.0.0 -charset-normalizer==2.0.7 -Cheetah3==3.2.6.post1 -cli-routed==1.0.0 -click==8.0.3 -colorama==0.4.4 -colored==1.4.3 -confpy==0.11.0 -cookiecutter==1.7.3 -cosmos-release==1.0 -coverage==6.1.2 -cryptography==35.0.0 -decorator==5.1.1 -distlib==0.3.3 -distro==1.7.0 -docker==5.0.3 -docker-compose==1.29.2 -dockerpty==0.4.1 -docopt==0.6.2 -docutils==0.18 -ecdsa==0.14.1 -emoji==1.7.0 -entrypoints==0.3 -execnet==1.9.0 -filelock==3.3.0 -flake8==3.7.8 -Flask==2.0.2 -Flask-Cors==3.0.10 -freezegun==1.1.0 -future==0.18.2 -humanize==4.0.0 -idna==3.3 -importlib-metadata==4.8.2 -inflection==0.3.1 -iniconfig==1.1.1 -isort==5.10.1 -itsdangerous==2.0.1 -jedi==0.17.2 -jeepney==0.7.1 -Jinja2==3.0.3 -jinja2-time==0.2.0 -jmespath==0.10.0 -jschema-to-python==1.2.3 -jsondiff==1.3.0 -jsonpatch==1.32 -jsonpickle==2.0.0 -jsonpointer==2.2 -jsonschema==3.2.0 -junit-xml==1.9 -keyring==23.2.1 -lambda-repository-cli==0.6.0 -lazy-object-proxy==1.6.0 -localstack-client==1.26 -lxml==4.6.4 -MarkupSafe==2.0.1 -Mastodon.py==1.5.0 -mccabe==0.6.1 -mock==4.0.3 -mutagen==1.45.1 -networkx==2.6.3 -ordereddict==1.1 +certifi==2022.9.24 +charset-normalizer==2.1.1 +click==8.1.3 +ghp-import==2.1.0 +idna==3.4 +importlib-metadata==4.12.0 +Jinja2==3.1.2 +Markdown==3.3.7 +markdown-include==0.7.0 +MarkupSafe==2.1.1 +mergedeep==1.3.4 +mkdocs==1.4.2 +mkdocs-material==8.5.9 +mkdocs-material-extensions==1.1 packaging==21.3 -paramiko==2.10.3 -parso==0.7.1 -pathspec==0.9.0 -pbr==5.8.0 -pipenv==2021.5.29 -pkginfo==1.7.1 -platformdirs==2.4.0 -pluggy==1.0.0 -poyo==0.5.0 -prompt-toolkit==3.0.22 -psutil==5.9.0 -py==1.11.0 -pyaml==21.10.1 -pyasn1==0.4.8 -pycodestyle==2.5.0 -pycparser==2.21 -pycryptodomex==3.14.1 -pycurl==7.44.1 -pyflakes==2.1.1 -Pygments==2.10.0 -pylint==2.11.1 -pymongo==4.0.1 -PyNaCl==1.5.0 -pyparsing==3.0.6 -pyrsistent==0.18.0 -pytest==6.2.5 -pytest-cov==3.0.0 -pytest-forked==1.3.0 -pytest-xdist==2.4.0 +Pygments==2.13.0 +pymdown-extensions==9.8 +pyparsing==3.0.9 python-dateutil==2.8.2 -python-dotenv==0.20.0 -python-jose==3.3.0 -python-jsonrpc-server==0.4.0 -python-language-server==0.36.2 -python-magic==0.4.25 -python-slugify==6.1.2 -pytz==2021.3 -PyYAML==5.4.1 -readme-renderer==30.0 -regex==2019.11.1 -requests==2.26.0 -requests-toolbelt==0.9.1 -requirements-parser==0.3.1 -responses==0.16.0 -rfc3986==1.5.0 -rpmvenv==0.25.0 -rsa==4.7.2 -s3transfer==0.5.0 -sarif-om==1.0.4 -SecretStorage==3.3.1 -semver==2.9.1 +PyYAML==6.0 +pyyaml_env_tag==0.1 +requests==2.28.1 six==1.16.0 -sshpubkeys==3.3.1 -sure==2.0.0 -text-unidecode==1.3 -texttable==1.6.4 -toml==0.10.2 -tomli==1.2.2 -tootstream==0.3.8.1 -tqdm==4.62.3 -twine==3.6.0 -typed-ast==1.5.0 -types-setuptools==57.4.7 -ujson==4.2.0 -urllib3==1.26.7 -venvctrl==0.4.2 -virtualenv==20.8.1 -virtualenv-clone==0.5.7 -wcwidth==0.2.5 -webencodings==0.5.1 -websocket-client==0.59.0 -websockets==10.2 -Werkzeug==2.0.2 -wrapt==1.13.3 -xmltodict==0.12.0 -yt-dlp==2022.2.4 -zipp==3.6.0 +urllib3==1.26.12 +watchdog==2.1.9 +zipp==3.8.0 From 89dbc7177b55c7f49632e75915fdcc77f737f20e Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Fri, 11 Nov 2022 16:12:04 +0000 Subject: [PATCH 040/631] Chores for 2022.11 --- CHANGELOG.md | 7 ++++++- README.md | 5 ++--- lib/pleroma/web/plugs/http_security_plug.ex | 13 +++++++------ mix.exs | 2 +- 4 files changed, 16 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e71b2127..ac6695c36 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). -## Unreleased +## 2022.11 ## Added - Officially supported docker release @@ -20,6 +20,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## Fixed - Registrations via ldap are now compatible with the latest OTP24 +## Update notes +- If you use LDAP and run from source, please update your elixir/erlang + to the latest. The changes in OTP24.3 are breaking. +- You can now remove the leading `*.` from domain blocks, but you do not have to. + ## 2022.10 ### Added diff --git a/README.md b/README.md index 212f99c60..8d35212aa 100644 --- a/README.md +++ b/README.md @@ -46,15 +46,13 @@ If your platform is not supported, or you just want to be able to edit the sourc - [Alpine Linux](https://docs.akkoma.dev/stable/installation/alpine_linux_en/) - [Arch Linux](https://docs.akkoma.dev/stable/installation/arch_linux_en/) - [Debian-based](https://docs.akkoma.dev/stable/installation/debian_based_en/) -- [Debian-based (jp)](https://docs.akkoma.dev/stable/installation/debian_based_jp/) - [FreeBSD](https://docs.akkoma.dev/stable/installation/freebsd_en/) - [Gentoo Linux](https://docs.akkoma.dev/stable/installation/gentoo_en/) - [NetBSD](https://docs.akkoma.dev/stable/installation/netbsd_en/) - [OpenBSD](https://docs.akkoma.dev/stable/installation/openbsd_en/) -- [OpenBSD (fi)](https://docs.akkoma.dev/stable/installation/openbsd_fi/) ### Docker -While we don’t provide docker files, other people have written very good ones. Take a look at or . +Docker installation is supported via [this setup](https://docs.akkoma.dev/stable/installation/docker_en/) ### Compilation Troubleshooting If you ever encounter compilation issues during the updating of Akkoma, you can try these commands and see if they fix things: @@ -66,3 +64,4 @@ If you ever encounter compilation issues during the updating of Akkoma, you can ## Documentation - https://docs.akkoma.dev/stable +- https://docs.akkoma.dev/develop diff --git a/lib/pleroma/web/plugs/http_security_plug.ex b/lib/pleroma/web/plugs/http_security_plug.ex index 43b075447..fc2f7b268 100644 --- a/lib/pleroma/web/plugs/http_security_plug.ex +++ b/lib/pleroma/web/plugs/http_security_plug.ex @@ -104,12 +104,13 @@ defp csp_string do {[img_src, " https:"], [media_src, " https:"]} end - connect_src = if Config.get([:media_proxy, :enabled]) do - sources = build_csp_multimedia_source_list() - ["connect-src 'self' blob: ", static_url, ?\s, websocket_url, ?\s, sources] - else - ["connect-src 'self' blob: ", static_url, ?\s, websocket_url] - end + connect_src = + if Config.get([:media_proxy, :enabled]) do + sources = build_csp_multimedia_source_list() + ["connect-src 'self' blob: ", static_url, ?\s, websocket_url, ?\s, sources] + else + ["connect-src 'self' blob: ", static_url, ?\s, websocket_url] + end script_src = if Config.get(:env) == :dev do diff --git a/mix.exs b/mix.exs index d95cc1778..201299aa5 100644 --- a/mix.exs +++ b/mix.exs @@ -4,7 +4,7 @@ defmodule Pleroma.Mixfile do def project do [ app: :pleroma, - version: version("3.3.1"), + version: version("3.4.0"), elixir: "~> 1.12", elixirc_paths: elixirc_paths(Mix.env()), compilers: [:phoenix, :gettext] ++ Mix.compilers(), From 35cddd7cf7c8a95dcdc5c97466eac082f9eca939 Mon Sep 17 00:00:00 2001 From: nocebo Date: Sun, 13 Nov 2022 08:43:12 +0000 Subject: [PATCH 041/631] change default redirectRootNoLogin to /main/public close #268 --- config/config.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/config.exs b/config/config.exs index 644155aeb..fd470ed93 100644 --- a/config/config.exs +++ b/config/config.exs @@ -317,7 +317,7 @@ nsfwCensorImage: "", postContentType: "text/plain", redirectRootLogin: "/main/friends", - redirectRootNoLogin: "/main/all", + redirectRootNoLogin: "/main/public", scopeCopy: true, sidebarRight: false, showFeaturesPanel: true, From c1127e321b151a98709072c1789a04c98bcf8c91 Mon Sep 17 00:00:00 2001 From: floatingghost Date: Sun, 13 Nov 2022 23:55:51 +0000 Subject: [PATCH 042/631] Add configurable timeline per oban job (#273) Heavily inspired by https://git.pleroma.social/pleroma/pleroma/-/merge_requests/3777 Co-authored-by: FloatingGhost Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma/pulls/273 --- config/config.exs | 21 +++++++++++++++ config/description.exs | 26 +++++++++++++++++++ lib/pleroma/workers/backup_worker.ex | 6 +++++ lib/pleroma/workers/purge_expired_activity.ex | 5 ++++ lib/pleroma/workers/purge_expired_filter.ex | 5 ++++ lib/pleroma/workers/purge_expired_token.ex | 5 ++++ lib/pleroma/workers/worker_helper.ex | 6 +++++ .../workers/purge_expired_activity_test.exs | 5 ++++ .../scheduled_activity_worker_test.exs | 5 ++++ 9 files changed, 84 insertions(+) diff --git a/config/config.exs b/config/config.exs index fd470ed93..ba77d8b02 100644 --- a/config/config.exs +++ b/config/config.exs @@ -584,6 +584,27 @@ federator_incoming: 5, federator_outgoing: 5, search_indexing: 2 + ], + timeout: [ + activity_expiration: :timer.seconds(5), + token_expiration: :timer.seconds(5), + filter_expiration: :timer.seconds(5), + backup: :timer.seconds(900), + federator_incoming: :timer.seconds(10), + federator_outgoing: :timer.seconds(10), + ingestion_queue: :timer.seconds(5), + web_push: :timer.seconds(5), + mailer: :timer.seconds(5), + transmogrifier: :timer.seconds(5), + scheduled_activities: :timer.seconds(5), + poll_notifications: :timer.seconds(5), + background: :timer.seconds(5), + remote_fetcher: :timer.seconds(10), + attachments_cleanup: :timer.seconds(900), + new_users_digest: :timer.seconds(10), + mute_expire: :timer.seconds(5), + search_indexing: :timer.seconds(5), + nodeinfo_fetcher: :timer.seconds(10) ] config :pleroma, Pleroma.Formatter, diff --git a/config/description.exs b/config/description.exs index 4843c0aae..287abb747 100644 --- a/config/description.exs +++ b/config/description.exs @@ -1979,6 +1979,32 @@ federator_incoming: 5, federator_outgoing: 5 ] + }, + %{ + key: :timeout, + type: {:keyword, :integer}, + description: "Timeout for jobs, per `Oban` queue, in ms", + suggestions: [ + activity_expiration: :timer.seconds(5), + token_expiration: :timer.seconds(5), + filter_expiration: :timer.seconds(5), + backup: :timer.seconds(900), + federator_incoming: :timer.seconds(10), + federator_outgoing: :timer.seconds(10), + ingestion_queue: :timer.seconds(5), + web_push: :timer.seconds(5), + mailer: :timer.seconds(5), + transmogrifier: :timer.seconds(5), + scheduled_activities: :timer.seconds(5), + poll_notifications: :timer.seconds(5), + background: :timer.seconds(5), + remote_fetcher: :timer.seconds(10), + attachments_cleanup: :timer.seconds(900), + new_users_digest: :timer.seconds(10), + mute_expire: :timer.seconds(5), + search_indexing: :timer.seconds(5), + nodeinfo_fetcher: :timer.seconds(10) + ] } ] }, diff --git a/lib/pleroma/workers/backup_worker.ex b/lib/pleroma/workers/backup_worker.ex index 66c5c3591..4ab08706e 100644 --- a/lib/pleroma/workers/backup_worker.ex +++ b/lib/pleroma/workers/backup_worker.ex @@ -14,6 +14,11 @@ def process(backup, admin_user_id \\ nil) do |> Oban.insert() end + @impl Oban.Worker + def timeout(_job) do + Pleroma.Config.get([:workers, :timeout, :backup]) || :timer.minutes(1) + end + def schedule_deletion(backup) do days = Pleroma.Config.get([Backup, :purge_after_days]) time = 60 * 60 * 24 * days @@ -30,6 +35,7 @@ def delete(backup) do |> Oban.insert() end + @impl true def perform(%Job{ args: %{"op" => "process", "backup_id" => backup_id, "admin_user_id" => admin_user_id} }) do diff --git a/lib/pleroma/workers/purge_expired_activity.ex b/lib/pleroma/workers/purge_expired_activity.ex index 027171c1e..ece84df37 100644 --- a/lib/pleroma/workers/purge_expired_activity.ex +++ b/lib/pleroma/workers/purge_expired_activity.ex @@ -27,6 +27,11 @@ def enqueue(args) do end end + @impl Oban.Worker + def timeout(_job) do + Pleroma.Config.get([:workers, :timeout, :activity_expiration]) || :timer.minutes(1) + end + @impl true def perform(%Oban.Job{args: %{"activity_id" => id}}) do with %Activity{} = activity <- find_activity(id), diff --git a/lib/pleroma/workers/purge_expired_filter.ex b/lib/pleroma/workers/purge_expired_filter.ex index 4740d52e9..dd6a22a68 100644 --- a/lib/pleroma/workers/purge_expired_filter.ex +++ b/lib/pleroma/workers/purge_expired_filter.ex @@ -24,6 +24,11 @@ def enqueue(args) do |> Oban.insert() end + @impl Oban.Worker + def timeout(_job) do + Pleroma.Config.get([:workers, :timeout, :filter_expiration]) || :timer.minutes(1) + end + @impl true def perform(%Job{args: %{"filter_id" => id}}) do Pleroma.Filter diff --git a/lib/pleroma/workers/purge_expired_token.ex b/lib/pleroma/workers/purge_expired_token.ex index cfdf5c6dc..1773aeff9 100644 --- a/lib/pleroma/workers/purge_expired_token.ex +++ b/lib/pleroma/workers/purge_expired_token.ex @@ -19,6 +19,11 @@ def enqueue(args) do |> Oban.insert() end + @impl Oban.Worker + def timeout(_job) do + Pleroma.Config.get([:workers, :timeout, :token_expiration]) || :timer.minutes(1) + end + @impl true def perform(%Oban.Job{args: %{"token_id" => id, "mod" => module}}) do module diff --git a/lib/pleroma/workers/worker_helper.ex b/lib/pleroma/workers/worker_helper.ex index 4befbeb3b..97c0e4e5c 100644 --- a/lib/pleroma/workers/worker_helper.ex +++ b/lib/pleroma/workers/worker_helper.ex @@ -43,6 +43,12 @@ def enqueue(op, params, worker_args \\ []) do |> apply(:new, [params, worker_args]) |> Oban.insert() end + + @impl Oban.Worker + def timeout(_job) do + queue_atom = String.to_atom(unquote(queue)) + Config.get([:workers, :timeout, queue_atom]) || :timer.minutes(1) + end end end end diff --git a/test/pleroma/workers/purge_expired_activity_test.exs b/test/pleroma/workers/purge_expired_activity_test.exs index 98f30f61f..6285dca3e 100644 --- a/test/pleroma/workers/purge_expired_activity_test.exs +++ b/test/pleroma/workers/purge_expired_activity_test.exs @@ -56,4 +56,9 @@ test "error if actiivity was not found" do assert {:error, :activity_not_found} = perform_job(Pleroma.Workers.PurgeExpiredActivity, %{activity_id: "some_if"}) end + + test "has a timeout" do + clear_config([:workers, :timeout, :activity_expiration], 50) + assert Pleroma.Workers.PurgeExpiredActivity.timeout(%Oban.Job{}) == 50 + end end diff --git a/test/pleroma/workers/scheduled_activity_worker_test.exs b/test/pleroma/workers/scheduled_activity_worker_test.exs index 5558d5b5f..9f5f1b687 100644 --- a/test/pleroma/workers/scheduled_activity_worker_test.exs +++ b/test/pleroma/workers/scheduled_activity_worker_test.exs @@ -49,4 +49,9 @@ test "error message for non-existent scheduled activity" do ScheduledActivityWorker.perform(%Oban.Job{args: %{"activity_id" => 42}}) end) =~ "Couldn't find scheduled activity: 42" end + + test "has a timeout" do + clear_config([:workers, :timeout, :scheduled_activities], :timer.minutes(5)) + assert ScheduledActivityWorker.timeout(nil) == :timer.minutes(5) + end end From 893bfde66fdfe37f20e15cb26989d2ddf36d4964 Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Mon, 14 Nov 2022 00:01:31 +0000 Subject: [PATCH 043/631] Remove references to soykaf Fixes #271 --- .../docs/development/API/differences_in_mastoapi_responses.md | 2 +- docs/docs/development/API/prometheus.md | 2 +- docs/docs/index.md | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/docs/development/API/differences_in_mastoapi_responses.md b/docs/docs/development/API/differences_in_mastoapi_responses.md index 752be1762..b41561c45 100644 --- a/docs/docs/development/API/differences_in_mastoapi_responses.md +++ b/docs/docs/development/API/differences_in_mastoapi_responses.md @@ -195,7 +195,7 @@ Additional parameters can be added to the JSON body/Form data: - `preview`: boolean, if set to `true` the post won't be actually posted, but the status entity would still be rendered back. This could be useful for previewing rich text/custom emoji, for example. - `content_type`: string, contain the MIME type of the status, it is transformed into HTML by the backend. You can get the list of the supported MIME types with the nodeinfo endpoint. -- `to`: A list of nicknames (like `lain@soykaf.club` or `lain` on the local server) that will be used to determine who is going to be addressed by this post. Using this will disable the implicit addressing by mentioned names in the `status` body, only the people in the `to` list will be addressed. The normal rules for post visibility are not affected by this and will still apply. +- `to`: A list of nicknames (like `admin@otp.akkoma.dev` or `admin` on the local server) that will be used to determine who is going to be addressed by this post. Using this will disable the implicit addressing by mentioned names in the `status` body, only the people in the `to` list will be addressed. The normal rules for post visibility are not affected by this and will still apply. - `visibility`: string, besides standard MastoAPI values (`direct`, `private`, `unlisted`, `local` or `public`) it can be used to address a List by setting it to `list:LIST_ID`. - `expires_in`: The number of seconds the posted activity should expire in. When a posted activity expires it will be deleted from the server, and a delete request for it will be federated. This needs to be longer than an hour. - `in_reply_to_conversation_id`: Will reply to a given conversation, addressing only the people who are part of the recipient set of that conversation. Sets the visibility to `direct`. diff --git a/docs/docs/development/API/prometheus.md b/docs/docs/development/API/prometheus.md index 0c23a404d..39ecc5d38 100644 --- a/docs/docs/development/API/prometheus.md +++ b/docs/docs/development/API/prometheus.md @@ -40,5 +40,5 @@ The following is a config example to use with [Grafana](https://grafana.com) metrics_path: /api/pleroma/app_metrics scheme: https static_configs: - - targets: ['pleroma.soykaf.com'] + - targets: ['otp.akkoma.dev'] ``` diff --git a/docs/docs/index.md b/docs/docs/index.md index 1018e9c2b..f5b00b457 100644 --- a/docs/docs/index.md +++ b/docs/docs/index.md @@ -29,14 +29,14 @@ If you don't feel like joining an existing instance, but instead prefer to deplo Installation instructions can be found in the installation section of these docs. ## I got an account, now what? -Great! Now you can explore the fediverse! Open the login page for your Akkoma instance (e.g. ) and login with your username and password. (If you don't have an account yet, click on Register) +Great! Now you can explore the fediverse! Open the login page for your Akkoma instance (e.g. ) and login with your username and password. (If you don't have an account yet, click on Register) ### Pleroma-FE The default front-end used by Akkoma is Pleroma-FE. You can find more information on what it is and how to use it in the [Introduction to Pleroma-FE](https://docs-fe.akkoma.dev/stable/). ### Mastodon interface If the Pleroma-FE interface isn't your thing, or you're just trying something new but you want to keep using the familiar Mastodon interface, we got that too! -Just add a "/web" after your instance url (e.g. ) and you'll end on the Mastodon web interface, but with a Akkoma backend! MAGIC! +Just add a "/web" after your instance url (e.g. ) and you'll end on the Mastodon web interface, but with a Akkoma backend! MAGIC! The Mastodon interface is from the Glitch-soc fork. For more information on the Mastodon interface you can check the [Mastodon](https://docs.joinmastodon.org/) and [Glitch-soc](https://glitch-soc.github.io/docs/) documentation. Remember, what you see is only the frontend part of Mastodon, the backend is still Akkoma. From 2a1f17e3ede2054f31c35b5dc240f51d0d5509d1 Mon Sep 17 00:00:00 2001 From: floatingghost Date: Mon, 14 Nov 2022 15:07:26 +0000 Subject: [PATCH 044/631] and i yoink (#275) Co-authored-by: Mark Felder Co-authored-by: FloatingGhost Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma/pulls/275 --- lib/pleroma/web/federator.ex | 6 ++- lib/pleroma/workers/backup_worker.ex | 2 +- lib/pleroma/workers/purge_expired_activity.ex | 2 +- lib/pleroma/workers/purge_expired_filter.ex | 2 +- lib/pleroma/workers/purge_expired_token.ex | 2 +- lib/pleroma/workers/worker_helper.ex | 2 +- .../pleroma/workers/publisher_worker_test.exs | 52 +++++++++++++++++++ 7 files changed, 61 insertions(+), 7 deletions(-) create mode 100644 test/pleroma/workers/publisher_worker_test.exs diff --git a/lib/pleroma/web/federator.ex b/lib/pleroma/web/federator.ex index 770044de2..3a00424c6 100644 --- a/lib/pleroma/web/federator.ex +++ b/lib/pleroma/web/federator.ex @@ -48,7 +48,9 @@ def publish(%{id: "pleroma:fakeid"} = activity) do @impl true def publish(%{data: %{"object" => object}} = activity) when is_binary(object) do - PublisherWorker.enqueue("publish", %{"activity_id" => activity.id, "object_data" => nil}) + PublisherWorker.enqueue("publish", %{"activity_id" => activity.id, "object_data" => nil}, + priority: publish_priority(activity) + ) end @impl true @@ -63,7 +65,7 @@ def publish(%{data: %{"object" => object}} = activity) when is_map(object) or is ) end - defp publish_priority(%{type: "Delete"}), do: 3 + defp publish_priority(%{data: %{"type" => "Delete"}}), do: 3 defp publish_priority(_), do: 0 # Job Worker Callbacks diff --git a/lib/pleroma/workers/backup_worker.ex b/lib/pleroma/workers/backup_worker.ex index 4ab08706e..cf78f1cb9 100644 --- a/lib/pleroma/workers/backup_worker.ex +++ b/lib/pleroma/workers/backup_worker.ex @@ -16,7 +16,7 @@ def process(backup, admin_user_id \\ nil) do @impl Oban.Worker def timeout(_job) do - Pleroma.Config.get([:workers, :timeout, :backup]) || :timer.minutes(1) + Pleroma.Config.get([:workers, :timeout, :backup], :timer.minutes(1)) end def schedule_deletion(backup) do diff --git a/lib/pleroma/workers/purge_expired_activity.ex b/lib/pleroma/workers/purge_expired_activity.ex index ece84df37..652e1d6b1 100644 --- a/lib/pleroma/workers/purge_expired_activity.ex +++ b/lib/pleroma/workers/purge_expired_activity.ex @@ -29,7 +29,7 @@ def enqueue(args) do @impl Oban.Worker def timeout(_job) do - Pleroma.Config.get([:workers, :timeout, :activity_expiration]) || :timer.minutes(1) + Pleroma.Config.get([:workers, :timeout, :activity_expiration], :timer.minutes(1)) end @impl true diff --git a/lib/pleroma/workers/purge_expired_filter.ex b/lib/pleroma/workers/purge_expired_filter.ex index dd6a22a68..593380d13 100644 --- a/lib/pleroma/workers/purge_expired_filter.ex +++ b/lib/pleroma/workers/purge_expired_filter.ex @@ -26,7 +26,7 @@ def enqueue(args) do @impl Oban.Worker def timeout(_job) do - Pleroma.Config.get([:workers, :timeout, :filter_expiration]) || :timer.minutes(1) + Pleroma.Config.get([:workers, :timeout, :filter_expiration], :timer.minutes(1)) end @impl true diff --git a/lib/pleroma/workers/purge_expired_token.ex b/lib/pleroma/workers/purge_expired_token.ex index 1773aeff9..b4db84f4e 100644 --- a/lib/pleroma/workers/purge_expired_token.ex +++ b/lib/pleroma/workers/purge_expired_token.ex @@ -21,7 +21,7 @@ def enqueue(args) do @impl Oban.Worker def timeout(_job) do - Pleroma.Config.get([:workers, :timeout, :token_expiration]) || :timer.minutes(1) + Pleroma.Config.get([:workers, :timeout, :token_expiration], :timer.minutes(1)) end @impl true diff --git a/lib/pleroma/workers/worker_helper.ex b/lib/pleroma/workers/worker_helper.ex index 97c0e4e5c..4c0a55774 100644 --- a/lib/pleroma/workers/worker_helper.ex +++ b/lib/pleroma/workers/worker_helper.ex @@ -47,7 +47,7 @@ def enqueue(op, params, worker_args \\ []) do @impl Oban.Worker def timeout(_job) do queue_atom = String.to_atom(unquote(queue)) - Config.get([:workers, :timeout, queue_atom]) || :timer.minutes(1) + Config.get([:workers, :timeout, queue_atom], :timer.minutes(1)) end end end diff --git a/test/pleroma/workers/publisher_worker_test.exs b/test/pleroma/workers/publisher_worker_test.exs new file mode 100644 index 000000000..cf0ac0ccb --- /dev/null +++ b/test/pleroma/workers/publisher_worker_test.exs @@ -0,0 +1,52 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2022 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Workers.PublisherWorkerTest do + use Pleroma.DataCase, async: true + use Oban.Testing, repo: Pleroma.Repo + + import Pleroma.Factory + + alias Pleroma.Object + alias Pleroma.Web.ActivityPub.ActivityPub + alias Pleroma.Web.ActivityPub.Builder + alias Pleroma.Web.CommonAPI + alias Pleroma.Web.Federator + + describe "Oban job priority:" do + setup do + user = insert(:user) + + {:ok, post} = CommonAPI.post(user, %{status: "Regrettable post"}) + object = Object.normalize(post, fetch: false) + {:ok, delete_data, _meta} = Builder.delete(user, object.data["id"]) + {:ok, delete, _meta} = ActivityPub.persist(delete_data, local: true) + + %{ + post: post, + delete: delete + } + end + + test "Deletions are lower priority", %{delete: delete} do + assert {:ok, %Oban.Job{priority: 3}} = Federator.publish(delete) + end + + test "Creates are normal priority", %{post: post} do + assert {:ok, %Oban.Job{priority: 0}} = Federator.publish(post) + end + end + + describe "Oban job timeout" do + test "should have a timeout" do + clear_config([:workers, :timeout, :federator_outgoing], :timer.minutes(2)) + assert Pleroma.Workers.PublisherWorker.timeout(nil) == :timer.minutes(2) + end + + test "should use a default timeout if none specified" do + clear_config([:workers, :timeout, :federator_outgoing]) + assert Pleroma.Workers.PublisherWorker.timeout(nil) == :timer.seconds(10) + end + end +end From 7a833aff906d5009f77abd65580fee839d5932bc Mon Sep 17 00:00:00 2001 From: Francis Dinh Date: Tue, 15 Nov 2022 07:51:19 -0500 Subject: [PATCH 045/631] docs: Update links to list of akkoma instances The old links were for Pleroma instances and one of them isn't even active anymore. --- docs/docs/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/index.md b/docs/docs/index.md index f5b00b457..241f790dc 100644 --- a/docs/docs/index.md +++ b/docs/docs/index.md @@ -23,7 +23,7 @@ will be posted via [@akkoma@ihba](https://ihatebeinga.live/users/akkoma) ## How can I use it? -Akkoma instances are already widely deployed, a list can be found at and . +Akkoma instances are already widely deployed, a list can be found at and . If you don't feel like joining an existing instance, but instead prefer to deploy your own instance, that's easy too! Installation instructions can be found in the installation section of these docs. From 3e0a5851e528135a04ca8f9ab59607ecc3ba42d9 Mon Sep 17 00:00:00 2001 From: "Haelwenn (lanodan) Monnier" Date: Tue, 15 Nov 2022 17:23:47 +0000 Subject: [PATCH 046/631] Set instance reachable on fetch --- lib/pleroma/object/fetcher.ex | 5 +++++ test/pleroma/object/fetcher_test.exs | 12 ++++++++++++ 2 files changed, 17 insertions(+) diff --git a/lib/pleroma/object/fetcher.ex b/lib/pleroma/object/fetcher.ex index 8ec28345f..aafab6643 100644 --- a/lib/pleroma/object/fetcher.ex +++ b/lib/pleroma/object/fetcher.ex @@ -4,6 +4,7 @@ defmodule Pleroma.Object.Fetcher do alias Pleroma.HTTP + alias Pleroma.Instances alias Pleroma.Maps alias Pleroma.Object alias Pleroma.Object.Containment @@ -234,6 +235,10 @@ def fetch_and_contain_remote_object_from_id(id) when is_binary(id) do {:ok, body} <- get_object(id), {:ok, data} <- safe_json_decode(body), :ok <- Containment.contain_origin_from_id(id, data) do + unless Instances.reachable?(id) do + Instances.set_reachable(id) + end + {:ok, data} else {:scheme, _} -> diff --git a/test/pleroma/object/fetcher_test.exs b/test/pleroma/object/fetcher_test.exs index c321032ad..cd5437617 100644 --- a/test/pleroma/object/fetcher_test.exs +++ b/test/pleroma/object/fetcher_test.exs @@ -6,6 +6,7 @@ defmodule Pleroma.Object.FetcherTest do use Pleroma.DataCase alias Pleroma.Activity + alias Pleroma.Instances alias Pleroma.Object alias Pleroma.Object.Fetcher @@ -159,6 +160,17 @@ test "it does not fetch a spoofed object uploaded on an instance as an attachmen "https://patch.cx/media/03ca3c8b4ac3ddd08bf0f84be7885f2f88de0f709112131a22d83650819e36c2.json" ) end + + test "it resets instance reachability on successful fetch" do + id = "http://mastodon.example.org/@admin/99541947525187367" + Instances.set_consistently_unreachable(id) + refute Instances.reachable?(id) + + {:ok, object} = + Fetcher.fetch_object_from_id("http://mastodon.example.org/@admin/99541947525187367") + + assert Instances.reachable?(id) + end end describe "implementation quirks" do From d4ca1217d3123dcf8aa0c2d9c7d5c9403eabb10e Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Wed, 16 Nov 2022 10:13:41 +0000 Subject: [PATCH 047/631] Be very specific about the double-quotes in strings --- docs/docs/configuration/cheatsheet.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/configuration/cheatsheet.md b/docs/docs/configuration/cheatsheet.md index ec8bea0cc..075283a26 100644 --- a/docs/docs/configuration/cheatsheet.md +++ b/docs/docs/configuration/cheatsheet.md @@ -59,7 +59,7 @@ To add configuration to your config file, you can copy it from the base config. * `cleanup_attachments`: Remove attachments along with statuses. Does not affect duplicate files and attachments without status. Enabling this will increase load to database when deleting statuses on larger instances. * `show_reactions`: Let favourites and emoji reactions be viewed through the API (default: `true`). * `password_reset_token_validity`: The time after which reset tokens aren't accepted anymore, in seconds (default: one day). -* `local_bubble`: Array of domains representing instances closely related to yours. Used to populate the `bubble` timeline. e.g `['example.com']`, (default: `[]`) +* `local_bubble`: Array of domains representing instances closely related to yours. Used to populate the `bubble` timeline. e.g `["example.com"]`, (default: `[]`) ## :database * `improved_hashtag_timeline`: Setting to force toggle / force disable improved hashtags timeline. `:enabled` forces hashtags to be fetched from `hashtags` table for hashtags timeline. `:disabled` forces object-embedded hashtags to be used (slower). Keep it `:auto` for automatic behaviour (it is auto-set to `:enabled` [unless overridden] when HashtagsTableMigrator completes). From e45b242d8871e5eebbd43d6fdaf6aed3b74f5bcf Mon Sep 17 00:00:00 2001 From: Francis Dinh Date: Thu, 17 Nov 2022 22:48:33 -0500 Subject: [PATCH 048/631] Update copyright info - Bump years to 2022 where appropriate - Add copyright for Akkoma authors - Remove references to deleted images --- COPYING | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/COPYING b/COPYING index dd25f1d81..a2985de57 100644 --- a/COPYING +++ b/COPYING @@ -1,12 +1,15 @@ -Unless otherwise stated this repository is copyright © 2017-2021 -Pleroma Authors , and is distributed under -The GNU Affero General Public License Version 3, you should have received a -copy of the license file as AGPL-3. +Unless otherwise stated this repository is +Copyright © 2017-2022 Pleroma Authors +Copyright © 2022 Akkoma Authors +and is distributed under The GNU Affero General Public License Version 3, you +should have received a copy of the license file as AGPL-3. --- -Files inside docs directory are copyright © 2021 Pleroma Authors -, and are distributed under the Creative Commons +Files inside docs directory are +Copyright © 2021-2022 Pleroma Authors +Copyright © 2022 Akkoma Authors +and are distributed under the Creative Commons Attribution 4.0 International license, you should have received a copy of the license file as CC-BY-4.0. @@ -16,9 +19,7 @@ The following files are copyright © 2019 shitposter.club, and are distributed under the Creative Commons Attribution-ShareAlike 4.0 International license, you should have received a copy of the license file as CC-BY-SA-4.0. -priv/static/images/pleroma-fox-tan.png priv/static/images/pleroma-fox-tan-smol.png -priv/static/images/pleroma-tan.png --- @@ -35,8 +36,6 @@ The following files are copyright © 2017-2020 Pleroma Authors Attribution-ShareAlike 4.0 International license, you should have received a copy of the license file as CC-BY-SA-4.0. -priv/static/images/avi.png -priv/static/images/banner.png priv/static/instance/thumbnail.jpeg --- From e1e0d5d75922c0e6738d97963f0df5ed4327d253 Mon Sep 17 00:00:00 2001 From: floatingghost Date: Fri, 18 Nov 2022 11:14:35 +0000 Subject: [PATCH 049/631] microblogpub federation fixes (#288) Co-authored-by: FloatingGhost Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma/pulls/288 --- lib/pleroma/http/adapter_helper.ex | 1 + lib/pleroma/user.ex | 3 +- lib/pleroma/web/activity_pub/activity_pub.ex | 14 ++++- .../user_with_invalid_also_known_as.json | 57 +++++++++++++++++++ test/pleroma/object/fetcher_test.exs | 2 +- test/pleroma/user_test.exs | 19 +++++++ 6 files changed, 93 insertions(+), 3 deletions(-) create mode 100644 test/fixtures/microblogpub/user_with_invalid_also_known_as.json diff --git a/lib/pleroma/http/adapter_helper.ex b/lib/pleroma/http/adapter_helper.ex index 4949dd727..e837ac8d4 100644 --- a/lib/pleroma/http/adapter_helper.ex +++ b/lib/pleroma/http/adapter_helper.ex @@ -99,6 +99,7 @@ defp proxy_type(_), do: {:error, :unknown} | {:error, atom()} | nil def parse_proxy(nil), do: nil + def parse_proxy(""), do: nil def parse_proxy(proxy) when is_binary(proxy) do with %URI{} = uri <- URI.parse(proxy), diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 700cab2b5..eb907a2d8 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -1910,7 +1910,8 @@ def get_or_fetch_by_ap_id(ap_id) do {%User{} = user, _} -> {:ok, user} - _ -> + e -> + Logger.error("Could not fetch user, #{inspect(e)}") {:error, :not_found} end end diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index dcdc7085f..254d91a7e 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -1530,6 +1530,18 @@ defp object_to_user_data(data, additional) do # we request WebFinger here nickname = additional[:nickname_from_acct] || generate_nickname(data) + # also_known_as must be a URL + also_known_as = + data + |> Map.get("alsoKnownAs", []) + |> Enum.filter(fn url -> + case URI.parse(url) do + %URI{scheme: "http"} -> true + %URI{scheme: "https"} -> true + _ -> false + end + end) + %{ ap_id: data["id"], uri: get_actor_url(data["url"]), @@ -1547,7 +1559,7 @@ defp object_to_user_data(data, additional) do featured_address: featured_address, bio: data["summary"] || "", actor_type: actor_type, - also_known_as: Map.get(data, "alsoKnownAs", []), + also_known_as: also_known_as, public_key: public_key, inbox: data["inbox"], shared_inbox: shared_inbox, diff --git a/test/fixtures/microblogpub/user_with_invalid_also_known_as.json b/test/fixtures/microblogpub/user_with_invalid_also_known_as.json new file mode 100644 index 000000000..a03076226 --- /dev/null +++ b/test/fixtures/microblogpub/user_with_invalid_also_known_as.json @@ -0,0 +1,57 @@ +{ + "@context": [ + "https://www.w3.org/ns/activitystreams", + "https://w3id.org/security/v1", + { + "Hashtag": "as:Hashtag", + "sensitive": "as:sensitive", + "manuallyApprovesFollowers": "as:manuallyApprovesFollowers", + "alsoKnownAs": { + "@id": "as:alsoKnownAs", + "@type": "@id" + }, + "movedTo": { + "@id": "as:movedTo", + "@type": "@id" + }, + "toot": "http://joinmastodon.org/ns#", + "featured": { + "@id": "toot:featured", + "@type": "@id" + }, + "Emoji": "toot:Emoji", + "blurhash": "toot:blurhash", + "votersCount": "toot:votersCount", + "schema": "http://schema.org#", + "PropertyValue": "schema:PropertyValue", + "value": "schema:value", + "ostatus": "http://ostatus.org#", + "conversation": "ostatus:conversation" + } + ], + "type": "Person", + "id": "https://mbp.example.com", + "following": "https://mbp.example.com/following", + "followers": "https://mbp.example.com/followers", + "featured": "https://mbp.example.com/featured", + "inbox": "https://mbp.example.com/inbox", + "outbox": "https://mbp.example.com/outbox", + "preferredUsername": "MBP", + "name": "MBP", + "summary": "wowee", + "endpoints": { + "sharedInbox": "https://mbp.example.com/inbox" + }, + "url": "https://mbp.example.com/", + "manuallyApprovesFollowers": false, + "attachment": [], + "icon": { + "mediaType": "image/jpeg", + "type": "Image", + "url": "https://beta.4201337.xyz/static/denise.jpg" + }, + "tag": [], + "alsoKnownAs": [ + "example@elsewhere.com" + ] +} diff --git a/test/pleroma/object/fetcher_test.exs b/test/pleroma/object/fetcher_test.exs index cd5437617..71306cdfe 100644 --- a/test/pleroma/object/fetcher_test.exs +++ b/test/pleroma/object/fetcher_test.exs @@ -166,7 +166,7 @@ test "it resets instance reachability on successful fetch" do Instances.set_consistently_unreachable(id) refute Instances.reachable?(id) - {:ok, object} = + {:ok, _object} = Fetcher.fetch_object_from_id("http://mastodon.example.org/@admin/99541947525187367") assert Instances.reachable?(id) diff --git a/test/pleroma/user_test.exs b/test/pleroma/user_test.exs index 195df2a03..44763daf7 100644 --- a/test/pleroma/user_test.exs +++ b/test/pleroma/user_test.exs @@ -968,6 +968,25 @@ test "it returns the old user if stale, but unfetchable" do assert user.last_refreshed_at == orig_user.last_refreshed_at end + + test "it doesn't fail on invalid alsoKnownAs entries" do + Tesla.Mock.mock(fn + %{url: "https://mbp.example.com/"} -> + %Tesla.Env{ + status: 200, + body: + "test/fixtures/microblogpub/user_with_invalid_also_known_as.json" + |> File.read!(), + headers: [{"content-type", "application/activity+json"}] + } + + _ -> + %Tesla.Env{status: 404} + end) + + assert {:ok, %User{also_known_as: []}} = + User.get_or_fetch_by_ap_id("https://mbp.example.com/") + end end test "returns an ap_id for a user" do From 14c1a4220b0bbb351551e96bd5ebd6634867f061 Mon Sep 17 00:00:00 2001 From: Norm Date: Fri, 18 Nov 2022 11:19:37 +0000 Subject: [PATCH 050/631] docs: Update list of clients (#284) In addition to making the page refer to Akkoma instead of Pleroma, I've also removed clients that were not updated in a year or more and updated links to websites and the contact links of authors. Also removed language that suggested these clients are in any way "officially supported". Co-authored-by: Francis Dinh Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma/pulls/284 Co-authored-by: Norm Co-committed-by: Norm --- docs/docs/clients.md | 64 +++++--------------------------------------- 1 file changed, 7 insertions(+), 57 deletions(-) diff --git a/docs/docs/clients.md b/docs/docs/clients.md index 5650ea236..fb8408718 100644 --- a/docs/docs/clients.md +++ b/docs/docs/clients.md @@ -1,21 +1,8 @@ -# Pleroma Clients -Note: Additional clients may be working but theses are officially supporting Pleroma. -Feel free to contact us to be added to this list! +# Akkoma Clients +Note: Additional clients may work, but these are known to work with Akkoma. +Apps listed here might not support all of Akkoma's features. ## Desktop -### Roma for Desktop -- Homepage: -- Source Code: -- Platforms: Windows, Mac, Linux -- Features: MastoAPI, Streaming Ready - -### Social -- Source Code: -- Contact: [@brainblasted@social.libre.fi](https://social.libre.fi/users/brainblasted) -- Platforms: Linux (GNOME) -- Note(2019-01-28): Not at a pre-alpha stage yet -- Features: MastoAPI - ### Whalebird - Homepage: - Source Code: @@ -30,28 +17,16 @@ Feel free to contact us to be added to this list! - Platforms: Android - Features: MastoAPI, ActivityPub (Client-to-Server) -### Amaroq -- Homepage: -- Source Code: -- Contact: [@eurasierboy@mastodon.social](https://mastodon.social/users/eurasierboy) -- Platforms: iOS -- Features: MastoAPI, No Streaming - ### Fedilab - Homepage: -- Source Code: -- Contact: [@fedilab@framapiaf.org](https://framapiaf.org/users/fedilab) +- Source Code: +- Contact: [@apps@toot.felilab.app](https://toot.fedilab.app/@apps) - Platforms: Android - Features: MastoAPI, Streaming Ready, Moderation, Text Formatting -### Kyclos -- Source Code: -- Platforms: SailfishOS -- Features: MastoAPI, No Streaming - ### Husky -- Source code: -- Contact: [@Husky@enigmatic.observer](https://enigmatic.observer/users/Husky) +- Source code: +- Contact: [@captainepoch@stereophonic.space](https://stereophonic.space/captainepoch) - Platforms: Android - Features: MastoAPI, No Streaming, Emoji Reactions, Text Formatting, FE Stickers @@ -68,32 +43,7 @@ Feel free to contact us to be added to this list! - Platforms: Android - Features: MastoAPI, No Streaming -### Twidere -- Homepage: -- Source Code: -- Contact: -- Platform: Android -- Features: MastoAPI, No Streaming - -### Indigenous -- Homepage: -- Source Code: -- Contact: [@swentel@realize.be](https://realize.be) -- Platforms: Android -- Features: MastoAPI, No Streaming - ## Alternative Web Interfaces -### Brutaldon -- Homepage: -- Source Code: -- Contact: [@gcupc@glitch.social](https://glitch.social/users/gcupc) -- Features: MastoAPI, No Streaming - -### Halcyon -- Source Code: -- Contact: [@halcyon@social.csswg.org](https://social.csswg.org/users/halcyon) -- Features: MastoAPI, Streaming Ready - ### Pinafore - Homepage: - Source Code: From fb5f846e8caac4c4b2335e5b89697e0de6ee58b2 Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Fri, 18 Nov 2022 11:22:30 +0000 Subject: [PATCH 051/631] Add `languages` to cheatsheet --- docs/docs/configuration/cheatsheet.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/docs/configuration/cheatsheet.md b/docs/docs/configuration/cheatsheet.md index 075283a26..49c37147d 100644 --- a/docs/docs/configuration/cheatsheet.md +++ b/docs/docs/configuration/cheatsheet.md @@ -60,6 +60,7 @@ To add configuration to your config file, you can copy it from the base config. * `show_reactions`: Let favourites and emoji reactions be viewed through the API (default: `true`). * `password_reset_token_validity`: The time after which reset tokens aren't accepted anymore, in seconds (default: one day). * `local_bubble`: Array of domains representing instances closely related to yours. Used to populate the `bubble` timeline. e.g `["example.com"]`, (default: `[]`) +* `languages`: List of Language Codes used by the instance. This is used to try and set a default language from the frontend. It will try and find the first match between the languages set here and the user's browser languages. It will default to the first language in this setting if there is no match.. (default `["en"]`) ## :database * `improved_hashtag_timeline`: Setting to force toggle / force disable improved hashtags timeline. `:enabled` forces hashtags to be fetched from `hashtags` table for hashtags timeline. `:disabled` forces object-embedded hashtags to be used (slower). Keep it `:auto` for automatic behaviour (it is auto-set to `:enabled` [unless overridden] when HashtagsTableMigrator completes). From 11fc1beba5f504e1e5dd466c91490e22020e66f6 Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Sat, 12 Nov 2022 17:52:37 -0500 Subject: [PATCH 052/631] Fix reports which do not have a user The check for deactivated users was being applied to report activities. --- lib/pleroma/web/activity_pub/activity_pub.ex | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 254d91a7e..5f7541b02 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -1247,6 +1247,7 @@ defp exclude_poll_votes(query, _) do end end + defp exclude_invisible_actors(query, %{type: "Flag"}), do: query defp exclude_invisible_actors(query, %{invisible_actors: true}), do: query defp exclude_invisible_actors(query, _opts) do @@ -1385,7 +1386,7 @@ def fetch_activities_query(recipients, opts \\ %{}) do |> restrict_instance(opts) |> restrict_announce_object_actor(opts) |> restrict_filtered(opts) - |> Activity.restrict_deactivated_users() + |> maybe_restrict_deactivated_users(opts) |> exclude_poll_votes(opts) |> exclude_invisible_actors(opts) |> exclude_visibility(opts) @@ -1813,4 +1814,9 @@ def fetch_direct_messages_query do |> restrict_visibility(%{visibility: "direct"}) |> order_by([activity], asc: activity.id) end + + defp maybe_restrict_deactivated_users(activity, %{type: "Flag"}), do: activity + + defp maybe_restrict_deactivated_users(activity, _opts), + do: Activity.restrict_deactivated_users(activity) end From 0022fa7d4968cb0681827d0773e1043b72338b72 Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Sat, 12 Nov 2022 18:05:58 -0500 Subject: [PATCH 053/631] Add same optimized join for excluding invisible users --- lib/pleroma/web/activity_pub/activity_pub.ex | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 5f7541b02..3a9b08cf0 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -1251,12 +1251,11 @@ defp exclude_invisible_actors(query, %{type: "Flag"}), do: query defp exclude_invisible_actors(query, %{invisible_actors: true}), do: query defp exclude_invisible_actors(query, _opts) do - invisible_ap_ids = - User.Query.build(%{invisible: true, select: [:ap_id]}) - |> Repo.all() - |> Enum.map(fn %{ap_id: ap_id} -> ap_id end) - - from([activity] in query, where: activity.actor not in ^invisible_ap_ids) + query + |> join(:inner, [activity], u in User, + as: :u, + on: activity.actor == u.ap_id and u.invisible == false + ) end defp exclude_id(query, %{exclude_id: id}) when is_binary(id) do From f90552f62e7a7b3414e57387f97741b9b253d0e1 Mon Sep 17 00:00:00 2001 From: r3g_5z Date: Sat, 19 Nov 2022 20:40:20 -0500 Subject: [PATCH 054/631] Drop XSS auditor It's deprecated, removed in some, by all modern browsers and is known to create XSS vulnerabilities in itself. Signed-off-by: r3g_5z --- docs/docs/configuration/hardening.md | 2 +- docs/docs/configuration/i2p.md | 2 +- docs/docs/configuration/onion_federation.md | 2 +- docs/docs/installation/openbsd_en.md | 2 +- lib/pleroma/web/plugs/http_security_plug.ex | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/docs/configuration/hardening.md b/docs/docs/configuration/hardening.md index 182a54422..3011812fc 100644 --- a/docs/docs/configuration/hardening.md +++ b/docs/docs/configuration/hardening.md @@ -23,7 +23,7 @@ This sets the `secure` flag on Akkoma’s session cookie. This makes sure, that This will send additional HTTP security headers to the clients, including: -* `X-XSS-Protection: "1; mode=block"` +* `X-XSS-Protection: "0"` * `X-Permitted-Cross-Domain-Policies: "none"` * `X-Frame-Options: "DENY"` * `X-Content-Type-Options: "nosniff"` diff --git a/docs/docs/configuration/i2p.md b/docs/docs/configuration/i2p.md index fecf66a84..981593366 100644 --- a/docs/docs/configuration/i2p.md +++ b/docs/docs/configuration/i2p.md @@ -155,7 +155,7 @@ server { location / { - add_header X-XSS-Protection "1; mode=block"; + add_header X-XSS-Protection "0"; add_header X-Permitted-Cross-Domain-Policies none; add_header X-Frame-Options DENY; add_header X-Content-Type-Options nosniff; diff --git a/docs/docs/configuration/onion_federation.md b/docs/docs/configuration/onion_federation.md index 499b4a693..9fc1cef06 100644 --- a/docs/docs/configuration/onion_federation.md +++ b/docs/docs/configuration/onion_federation.md @@ -99,7 +99,7 @@ server { location / { - add_header X-XSS-Protection "1; mode=block"; + add_header X-XSS-Protection "0"; add_header X-Permitted-Cross-Domain-Policies none; add_header X-Frame-Options DENY; add_header X-Content-Type-Options nosniff; diff --git a/docs/docs/installation/openbsd_en.md b/docs/docs/installation/openbsd_en.md index 581942f99..2b163df6d 100644 --- a/docs/docs/installation/openbsd_en.md +++ b/docs/docs/installation/openbsd_en.md @@ -160,7 +160,7 @@ http protocol plerup { # Protocol for upstream akkoma server match request header append "X-Forwarded-For" value "$REMOTE_ADDR" # This two header and the next one are not strictly required by akkoma but adding them won't hurt match request header append "X-Forwarded-By" value "$SERVER_ADDR:$SERVER_PORT" - match response header append "X-XSS-Protection" value "1; mode=block" + match response header append "X-XSS-Protection" value "0" match response header append "X-Permitted-Cross-Domain-Policies" value "none" match response header append "X-Frame-Options" value "DENY" match response header append "X-Content-Type-Options" value "nosniff" diff --git a/lib/pleroma/web/plugs/http_security_plug.ex b/lib/pleroma/web/plugs/http_security_plug.ex index fc2f7b268..5f36b77d1 100644 --- a/lib/pleroma/web/plugs/http_security_plug.ex +++ b/lib/pleroma/web/plugs/http_security_plug.ex @@ -42,7 +42,7 @@ def headers do custom_http_frontend_headers = custom_http_frontend_headers() headers = [ - {"x-xss-protection", "1; mode=block"}, + {"x-xss-protection", "0"}, {"x-permitted-cross-domain-policies", "none"}, {"x-frame-options", "DENY"}, {"x-content-type-options", "nosniff"}, From 0e4c201f8dd607f5f34a247e63ab968204946052 Mon Sep 17 00:00:00 2001 From: "@r3g_5z@plem.sapphic.site" Date: Sun, 20 Nov 2022 21:20:06 +0000 Subject: [PATCH 055/631] HTTP header improvements (#294) - Drop Expect-CT Expect-CT has been redundant since 2018 when Certificate Transparency became mandated and required for all CAs and browsers. This header is only implemented in Chrome and is now deprecated. HTTP header analysers do not check this anymore as this is enforced by default. See https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Expect-CT - Raise HSTS to 2 years and explicitly preload The longer age for HSTS, the better. Header analysers prefer 2 years over 1 year now as free TLS is very common using Let's Encrypt. For HSTS to be fully effective, you need to submit your root domain (domain.tld) to https://hstspreload.org. However, a requirement for this is the "preload" directive in Strict-Transport-Security. If you do not have "preload", it will reject your domain. - Drop X-Download-Options This is an IE8-era header when Adobe products used to use the IE engine for making outbound web requests to embed webpages in things like Adobe Acrobat (PDFs). Modern apps are using Microsoft Edge WebView2 or Chromium Embedded Framework. No modern browser checks or header analyser check for this. - Set base-uri to 'none' This is to specify the domain for relative links (`` HTML tag). pleroma-fe does not use this and it's an incredibly niche tag. I use all of these myself on my instance by rewriting the headers with zero problems. No breakage observed. I have not compiled my Elixr changes, but I don't see why they'd break. Co-authored-by: r3g_5z Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma/pulls/294 Co-authored-by: @r3g_5z@plem.sapphic.site Co-committed-by: @r3g_5z@plem.sapphic.site --- config/config.exs | 3 +-- config/description.exs | 9 +-------- docs/docs/configuration/cheatsheet.md | 1 - docs/docs/configuration/hardening.md | 7 +------ docs/docs/configuration/i2p.md | 1 - docs/docs/configuration/onion_federation.md | 1 - docs/docs/installation/openbsd_en.md | 5 ++--- lib/pleroma/web/plugs/http_security_plug.ex | 7 ++----- priv/gettext/ca/LC_MESSAGES/config_descriptions.po | 12 ------------ priv/gettext/config_descriptions.pot | 12 ------------ priv/gettext/es/LC_MESSAGES/config_descriptions.po | 12 ------------ priv/gettext/nl/LC_MESSAGES/config_descriptions.po | 12 ------------ test/pleroma/web/plugs/http_security_plug_test.exs | 4 ---- 13 files changed, 7 insertions(+), 79 deletions(-) diff --git a/config/config.exs b/config/config.exs index ba77d8b02..f586e3883 100644 --- a/config/config.exs +++ b/config/config.exs @@ -487,8 +487,7 @@ config :pleroma, :http_security, enabled: true, sts: false, - sts_max_age: 31_536_000, - ct_max_age: 2_592_000, + sts_max_age: 63_072_000, referrer_policy: "same-origin" config :cors_plug, diff --git a/config/description.exs b/config/description.exs index 287abb747..b605bbd19 100644 --- a/config/description.exs +++ b/config/description.exs @@ -1750,14 +1750,7 @@ label: "STS max age", type: :integer, description: "The maximum age for the Strict-Transport-Security header if sent", - suggestions: [31_536_000] - }, - %{ - key: :ct_max_age, - label: "CT max age", - type: :integer, - description: "The maximum age for the Expect-CT header if sent", - suggestions: [2_592_000] + suggestions: [63_072_000] }, %{ key: :referrer_policy, diff --git a/docs/docs/configuration/cheatsheet.md b/docs/docs/configuration/cheatsheet.md index 49c37147d..ee35d95bc 100644 --- a/docs/docs/configuration/cheatsheet.md +++ b/docs/docs/configuration/cheatsheet.md @@ -453,7 +453,6 @@ This will make Akkoma listen on `127.0.0.1` port `8080` and generate urls starti * ``enabled``: Whether the managed content security policy is enabled. * ``sts``: Whether to additionally send a `Strict-Transport-Security` header. * ``sts_max_age``: The maximum age for the `Strict-Transport-Security` header if sent. -* ``ct_max_age``: The maximum age for the `Expect-CT` header if sent. * ``referrer_policy``: The referrer policy to use, either `"same-origin"` or `"no-referrer"`. * ``report_uri``: Adds the specified url to `report-uri` and `report-to` group in CSP header. diff --git a/docs/docs/configuration/hardening.md b/docs/docs/configuration/hardening.md index 3011812fc..c5a9e160b 100644 --- a/docs/docs/configuration/hardening.md +++ b/docs/docs/configuration/hardening.md @@ -27,14 +27,13 @@ This will send additional HTTP security headers to the clients, including: * `X-Permitted-Cross-Domain-Policies: "none"` * `X-Frame-Options: "DENY"` * `X-Content-Type-Options: "nosniff"` -* `X-Download-Options: "noopen"` A content security policy (CSP) will also be set: ```csp content-security-policy: default-src 'none'; - base-uri 'self'; + base-uri 'none'; frame-ancestors 'none'; img-src 'self' data: blob: https:; media-src 'self' https:; @@ -52,10 +51,6 @@ content-security-policy: An additional “Strict transport security” header will be sent with the configured `sts_max_age` parameter. This tells the browser, that the domain should only be accessed over a secure HTTPs connection. -#### `ct_max_age` - -An additional “Expect-CT” header will be sent with the configured `ct_max_age` parameter. This enforces the use of TLS certificates that are published in the certificate transparency log. (see [Expect-CT](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Expect-CT)) - #### `referrer_policy` > Recommended value: `same-origin` diff --git a/docs/docs/configuration/i2p.md b/docs/docs/configuration/i2p.md index 981593366..ec6266ab7 100644 --- a/docs/docs/configuration/i2p.md +++ b/docs/docs/configuration/i2p.md @@ -160,7 +160,6 @@ server { add_header X-Frame-Options DENY; add_header X-Content-Type-Options nosniff; add_header Referrer-Policy same-origin; - add_header X-Download-Options noopen; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; diff --git a/docs/docs/configuration/onion_federation.md b/docs/docs/configuration/onion_federation.md index 9fc1cef06..e4ae15fd2 100644 --- a/docs/docs/configuration/onion_federation.md +++ b/docs/docs/configuration/onion_federation.md @@ -104,7 +104,6 @@ server { add_header X-Frame-Options DENY; add_header X-Content-Type-Options nosniff; add_header Referrer-Policy same-origin; - add_header X-Download-Options noopen; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; diff --git a/docs/docs/installation/openbsd_en.md b/docs/docs/installation/openbsd_en.md index 2b163df6d..9693467f2 100644 --- a/docs/docs/installation/openbsd_en.md +++ b/docs/docs/installation/openbsd_en.md @@ -165,10 +165,9 @@ http protocol plerup { # Protocol for upstream akkoma server match response header append "X-Frame-Options" value "DENY" match response header append "X-Content-Type-Options" value "nosniff" match response header append "Referrer-Policy" value "same-origin" - match response header append "X-Download-Options" value "noopen" - match response header append "Content-Security-Policy" value "default-src 'none'; base-uri 'self'; form-action 'self'; img-src 'self' data: https:; media-src 'self' https:; style-src 'self' 'unsafe-inline'; font-src 'self'; script-src 'self'; connect-src 'self' wss://CHANGEME.tld; upgrade-insecure-requests;" # Modify "CHANGEME.tld" and set your instance's domain here + match response header append "Content-Security-Policy" value "default-src 'none'; base-uri 'none'; form-action 'self'; img-src 'self' data: https:; media-src 'self' https:; style-src 'self' 'unsafe-inline'; font-src 'self'; script-src 'self'; connect-src 'self' wss://CHANGEME.tld; upgrade-insecure-requests;" # Modify "CHANGEME.tld" and set your instance's domain here match request header append "Connection" value "upgrade" - #match response header append "Strict-Transport-Security" value "max-age=31536000; includeSubDomains" # Uncomment this only after you get HTTPS working. + #match response header append "Strict-Transport-Security" value "max-age=63072000; includeSubDomains; preload" # Uncomment this only after you get HTTPS working. # If you do not want remote frontends to be able to access your Akkoma backend server, comment these lines match response header append "Access-Control-Allow-Origin" value "*" diff --git a/lib/pleroma/web/plugs/http_security_plug.ex b/lib/pleroma/web/plugs/http_security_plug.ex index 5f36b77d1..47874a980 100644 --- a/lib/pleroma/web/plugs/http_security_plug.ex +++ b/lib/pleroma/web/plugs/http_security_plug.ex @@ -47,7 +47,6 @@ def headers do {"x-frame-options", "DENY"}, {"x-content-type-options", "nosniff"}, {"referrer-policy", referrer_policy}, - {"x-download-options", "noopen"}, {"content-security-policy", csp_string()}, {"permissions-policy", "interest-cohort=()"} ] @@ -76,7 +75,7 @@ def headers do static_csp_rules = [ "default-src 'none'", - "base-uri 'self'", + "base-uri 'none'", "frame-ancestors 'none'", "style-src 'self' 'unsafe-inline'", "font-src 'self'", @@ -237,11 +236,9 @@ def warn_if_disabled do defp maybe_send_sts_header(conn, true) do max_age_sts = Config.get([:http_security, :sts_max_age]) - max_age_ct = Config.get([:http_security, :ct_max_age]) merge_resp_headers(conn, [ - {"strict-transport-security", "max-age=#{max_age_sts}; includeSubDomains"}, - {"expect-ct", "enforce, max-age=#{max_age_ct}"} + {"strict-transport-security", "max-age=#{max_age_sts}; includeSubDomains; preload"} ]) end diff --git a/priv/gettext/ca/LC_MESSAGES/config_descriptions.po b/priv/gettext/ca/LC_MESSAGES/config_descriptions.po index 3a25f067e..ad2177a9b 100644 --- a/priv/gettext/ca/LC_MESSAGES/config_descriptions.po +++ b/priv/gettext/ca/LC_MESSAGES/config_descriptions.po @@ -1936,12 +1936,6 @@ msgstr "" "What user agent to use. Must be a string or an atom `:default`. Default " "value is `:default`." -#: lib/pleroma/docs/translator.ex:5 -#, fuzzy -msgctxt "config description at :pleroma-:http_security > :ct_max_age" -msgid "The maximum age for the Expect-CT header if sent" -msgstr "The maximum age for the Expect-CT header if sent" - #: lib/pleroma/docs/translator.ex:5 #, fuzzy msgctxt "config description at :pleroma-:http_security > :enabled" @@ -4993,12 +4987,6 @@ msgctxt "config label at :pleroma-:http > :user_agent" msgid "User agent" msgstr "User agent" -#: lib/pleroma/docs/translator.ex:5 -#, fuzzy -msgctxt "config label at :pleroma-:http_security > :ct_max_age" -msgid "CT max age" -msgstr "CT max age" - #: lib/pleroma/docs/translator.ex:5 #, fuzzy msgctxt "config label at :pleroma-:http_security > :enabled" diff --git a/priv/gettext/config_descriptions.pot b/priv/gettext/config_descriptions.pot index 9021fbfab..1a55bfe68 100644 --- a/priv/gettext/config_descriptions.pot +++ b/priv/gettext/config_descriptions.pot @@ -1612,12 +1612,6 @@ msgctxt "config description at :pleroma-:http > :user_agent" msgid "What user agent to use. Must be a string or an atom `:default`. Default value is `:default`." msgstr "" -#, elixir-autogen, elixir-format -#: lib/pleroma/docs/translator.ex:5 -msgctxt "config description at :pleroma-:http_security > :ct_max_age" -msgid "The maximum age for the Expect-CT header if sent" -msgstr "" - #, elixir-autogen, elixir-format #: lib/pleroma/docs/translator.ex:5 msgctxt "config description at :pleroma-:http_security > :enabled" @@ -4048,12 +4042,6 @@ msgctxt "config label at :pleroma-:http > :user_agent" msgid "User agent" msgstr "" -#, elixir-autogen, elixir-format -#: lib/pleroma/docs/translator.ex:5 -msgctxt "config label at :pleroma-:http_security > :ct_max_age" -msgid "CT max age" -msgstr "" - #, elixir-autogen, elixir-format #: lib/pleroma/docs/translator.ex:5 msgctxt "config label at :pleroma-:http_security > :enabled" diff --git a/priv/gettext/es/LC_MESSAGES/config_descriptions.po b/priv/gettext/es/LC_MESSAGES/config_descriptions.po index 9c1acae20..f3602ce46 100644 --- a/priv/gettext/es/LC_MESSAGES/config_descriptions.po +++ b/priv/gettext/es/LC_MESSAGES/config_descriptions.po @@ -1759,12 +1759,6 @@ msgstr "" "What user agent to use. Must be a string or an atom `:default`. Default " "value is `:default`." -#: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:http_security > :ct_max_age" -msgid "The maximum age for the Expect-CT header if sent" -msgstr "The maximum age for the Expect-CT header if sent" - #: lib/pleroma/docs/translator.ex:5 #, elixir-autogen, elixir-format, fuzzy msgctxt "config description at :pleroma-:http_security > :enabled" @@ -4420,12 +4414,6 @@ msgctxt "config label at :pleroma-:http > :user_agent" msgid "User agent" msgstr "User agent" -#: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:http_security > :ct_max_age" -msgid "CT max age" -msgstr "CT max age" - #: lib/pleroma/docs/translator.ex:5 #, elixir-autogen, elixir-format, fuzzy msgctxt "config label at :pleroma-:http_security > :enabled" diff --git a/priv/gettext/nl/LC_MESSAGES/config_descriptions.po b/priv/gettext/nl/LC_MESSAGES/config_descriptions.po index 4def37366..8ce06bf38 100644 --- a/priv/gettext/nl/LC_MESSAGES/config_descriptions.po +++ b/priv/gettext/nl/LC_MESSAGES/config_descriptions.po @@ -1759,12 +1759,6 @@ msgstr "" "What user agent to use. Must be a string or an atom `:default`. Default " "value is `:default`." -#: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:http_security > :ct_max_age" -msgid "The maximum age for the Expect-CT header if sent" -msgstr "The maximum age for the Expect-CT header if sent" - #: lib/pleroma/docs/translator.ex:5 #, elixir-autogen, elixir-format, fuzzy msgctxt "config description at :pleroma-:http_security > :enabled" @@ -4420,12 +4414,6 @@ msgctxt "config label at :pleroma-:http > :user_agent" msgid "User agent" msgstr "User agent" -#: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:http_security > :ct_max_age" -msgid "CT max age" -msgstr "CT max age" - #: lib/pleroma/docs/translator.ex:5 #, elixir-autogen, elixir-format, fuzzy msgctxt "config label at :pleroma-:http_security > :enabled" diff --git a/test/pleroma/web/plugs/http_security_plug_test.exs b/test/pleroma/web/plugs/http_security_plug_test.exs index 7f85f4a11..d6d841078 100644 --- a/test/pleroma/web/plugs/http_security_plug_test.exs +++ b/test/pleroma/web/plugs/http_security_plug_test.exs @@ -17,7 +17,6 @@ test "it sends CSP headers when enabled", %{conn: conn} do refute Conn.get_resp_header(conn, "x-permitted-cross-domain-policies") == [] refute Conn.get_resp_header(conn, "x-frame-options") == [] refute Conn.get_resp_header(conn, "x-content-type-options") == [] - refute Conn.get_resp_header(conn, "x-download-options") == [] refute Conn.get_resp_header(conn, "referrer-policy") == [] refute Conn.get_resp_header(conn, "content-security-policy") == [] end @@ -28,7 +27,6 @@ test "it sends STS headers when enabled", %{conn: conn} do conn = get(conn, "/api/v1/instance") refute Conn.get_resp_header(conn, "strict-transport-security") == [] - refute Conn.get_resp_header(conn, "expect-ct") == [] end test "it does not send STS headers when disabled", %{conn: conn} do @@ -37,7 +35,6 @@ test "it does not send STS headers when disabled", %{conn: conn} do conn = get(conn, "/api/v1/instance") assert Conn.get_resp_header(conn, "strict-transport-security") == [] - assert Conn.get_resp_header(conn, "expect-ct") == [] end test "referrer-policy header reflects configured value", %{conn: conn} do @@ -155,7 +152,6 @@ test "it does not send CSP headers when disabled", %{conn: conn} do assert Conn.get_resp_header(conn, "x-permitted-cross-domain-policies") == [] assert Conn.get_resp_header(conn, "x-frame-options") == [] assert Conn.get_resp_header(conn, "x-content-type-options") == [] - assert Conn.get_resp_header(conn, "x-download-options") == [] assert Conn.get_resp_header(conn, "referrer-policy") == [] assert Conn.get_resp_header(conn, "content-security-policy") == [] end From cc75b313f32cee4ecd6d5d9e39f6fdefc5aaa7a0 Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Sun, 20 Nov 2022 21:44:32 +0000 Subject: [PATCH 056/631] Add favicon, frontend docs --- .../howto_theming_your_instance.md | 3 +-- docs/docs/configuration/static_dir.md | 7 ++++++ docs/docs/installation/migrating_to_akkoma.md | 23 +++++++++++++++++++ 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/docs/docs/configuration/howto_theming_your_instance.md b/docs/docs/configuration/howto_theming_your_instance.md index af417aee4..c226d054b 100644 --- a/docs/docs/configuration/howto_theming_your_instance.md +++ b/docs/docs/configuration/howto_theming_your_instance.md @@ -70,5 +70,4 @@ config :pleroma, :frontend_configurations, } ``` -If you added it in the back-end configuration file, you'll need to restart your instance for the changes to take effect. If you don't see the changes, it's probably because the browser has cached the previous theme. In that case you'll want to clear browser caches. Alternatively you can use a private/incognito window just to see the changes. - +If you added it in the back-end configuration file, you'll need to restart your instance for the changes to take effect. If you don't see the changes, it's probably because the browser has cached the previous theme. In that case you'll want to clear browser caches. Alternatively you can use a private/incognito window just to see the changes. \ No newline at end of file diff --git a/docs/docs/configuration/static_dir.md b/docs/docs/configuration/static_dir.md index 37e07eb0d..0653dc2a3 100644 --- a/docs/docs/configuration/static_dir.md +++ b/docs/docs/configuration/static_dir.md @@ -89,6 +89,13 @@ config :pleroma, :frontend_configurations, Terms of Service will be shown to all users on the registration page. It's the best place where to write down the rules for your instance. You can modify the rules by adding and changing `$static_dir/static/terms-of-service.html`. +## Favicon + +The favicon will display on the frontend, and in the browser tab. + +Place a PNG file at `$static_dir/favicon.png` to change the favicon. Not that this +is _one level above_ where the logo is placed, it should be on the same level as +the `frontends` directory. ## Styling rendered pages diff --git a/docs/docs/installation/migrating_to_akkoma.md b/docs/docs/installation/migrating_to_akkoma.md index b64cdd056..2df7bfad0 100644 --- a/docs/docs/installation/migrating_to_akkoma.md +++ b/docs/docs/installation/migrating_to_akkoma.md @@ -95,3 +95,26 @@ Your situation will likely be unique - you'll need the changes in the [forked pleroma-fe repository](https://akkoma.dev/AkkomaGang/pleroma-fe), and either merge or cherry-pick from there depending on how you've got things. + +## Common issues + +### The frontend doesn't show after installing it + +This may occur if you are using database configuration. + +Sometimes the config in your database will cause akkoma to still report +that there's no frontend, even when you've run the install. + +To fix this, run: + +=== "OTP" + ```sh + ./bin/pleroma_ctl config delete pleroma frontends + ``` + +=== "From Source" + ```sh + mix pleroma.config delete pleroma frontends + ``` + +which will remove the config from the database. Things should work now. \ No newline at end of file From de1bbc02811d73b08b64757b574827194aecf11d Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Sun, 20 Nov 2022 22:21:56 +0000 Subject: [PATCH 057/631] Add conversationDisplay to settings --- config/config.exs | 4 ++-- config/description.exs | 15 +++++++-------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/config/config.exs b/config/config.exs index f586e3883..5278896f1 100644 --- a/config/config.exs +++ b/config/config.exs @@ -312,7 +312,6 @@ logo: "/static/logo.svg", logoMargin: ".1em", logoMask: true, - minimalScopesMode: false, noAttachmentLinks: false, nsfwCensorImage: "", postContentType: "text/plain", @@ -324,7 +323,8 @@ showInstanceSpecificPanel: false, subjectLineBehavior: "email", theme: "pleroma-dark", - webPushNotifications: false + webPushNotifications: false, + conversationDisplay: "linear" }, masto_fe: %{ showInstanceSpecificPanel: true diff --git a/config/description.exs b/config/description.exs index b605bbd19..994bb7280 100644 --- a/config/description.exs +++ b/config/description.exs @@ -1226,6 +1226,13 @@ type: :boolean, description: "Enables green text on lines prefixed with the > character" }, + %{ + key: :conversationDisplay, + label: "Conversation display style", + type: :string, + description: "How to display conversations (linear or tree)", + suggestions: ["linear", "tree"] + }, %{ key: :hideFilteredStatuses, label: "Hide Filtered Statuses", @@ -1274,14 +1281,6 @@ "By default it assumes logo used will be monochrome with alpha channel to be compatible with both light and dark themes. " <> "If you want a colorful logo you must disable logoMask." }, - %{ - key: :minimalScopesMode, - label: "Minimal scopes mode", - type: :boolean, - description: - "Limit scope selection to Direct, User default, and Scope of post replying to. " <> - "Also prevents replying to a DM with a public post from PleromaFE." - }, %{ key: :nsfwCensorImage, label: "NSFW Censor Image", From 1fa22ab052af8c770a5793f3581acf23dc7c1f0b Mon Sep 17 00:00:00 2001 From: Francis Dinh Date: Tue, 22 Nov 2022 13:07:34 -0500 Subject: [PATCH 058/631] Remove reference to pleroma-fox-tan-shy.png in COPYING Forgot to remove this in https://akkoma.dev/AkkomaGang/akkoma/pulls/285. This image was also removed a while back. --- COPYING | 8 -------- 1 file changed, 8 deletions(-) diff --git a/COPYING b/COPYING index a2985de57..077a664ed 100644 --- a/COPYING +++ b/COPYING @@ -23,14 +23,6 @@ priv/static/images/pleroma-fox-tan-smol.png --- -The following files are copyright © 2019 shitposter.club, and are distributed -under the Creative Commons Attribution 4.0 International license, you should -have received a copy of the license file as CC-BY-4.0. - -priv/static/images/pleroma-fox-tan-shy.png - ---- - The following files are copyright © 2017-2020 Pleroma Authors , and are distributed under the Creative Commons Attribution-ShareAlike 4.0 International license, you should have received From 1c4ca20ff7c7a56e4b28b5c1e4cc21f49853bb9c Mon Sep 17 00:00:00 2001 From: ave Date: Thu, 24 Nov 2022 11:27:01 +0000 Subject: [PATCH 059/631] Change follow_operation schema to use type BooleanLike (#301) Changes follow_operation schema to use BooleanLike instead of :boolean so that strings like "0" and "1" (used by mastodon.py) can be accepted. Rest of file uses the same. For more info please see https://git.pleroma.social/pleroma/pleroma/-/issues/2999 (I'm also sending this here as I'm not hopeful about upstream not ignoring it) Co-authored-by: ave Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma/pulls/301 Co-authored-by: ave Co-committed-by: ave --- CHANGELOG.md | 7 +++- .../api_spec/operations/account_operation.ex | 4 +- .../controllers/account_controller_test.exs | 40 +++++++++++++------ 3 files changed, 35 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ac6695c36..781fbe6e5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,11 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). +## Unreleased + +## Changed +- MastoAPI: Accept BooleanLike input on `/api/v1/accounts/:id/follow` (fixes follows with mastodon.py) + ## 2022.11 ## Added @@ -12,7 +17,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Scraping of nodeinfo from remote instances to display instance info - `requested_by` in relationships when the user has requested to follow you -## Changes +## Changed - Follows no longer override domain blocks, a domain block is final - Deletes are now the lowest priority to publish and will be handled after creates - Domain blocks are now subdomain-matches by default diff --git a/lib/pleroma/web/api_spec/operations/account_operation.ex b/lib/pleroma/web/api_spec/operations/account_operation.ex index b305dc1ea..359a73ac0 100644 --- a/lib/pleroma/web/api_spec/operations/account_operation.ex +++ b/lib/pleroma/web/api_spec/operations/account_operation.ex @@ -223,12 +223,12 @@ def follow_operation do type: :object, properties: %{ reblogs: %Schema{ - type: :boolean, + allOf: [BooleanLike], description: "Receive this account's reblogs in home timeline? Defaults to true.", default: true }, notify: %Schema{ - type: :boolean, + allOf: [BooleanLike], description: "Receive notifications for all statuses posted by the account? Defaults to false.", default: false diff --git a/test/pleroma/web/mastodon_api/controllers/account_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/account_controller_test.exs index 5b4f12402..29e34546e 100644 --- a/test/pleroma/web/mastodon_api/controllers/account_controller_test.exs +++ b/test/pleroma/web/mastodon_api/controllers/account_controller_test.exs @@ -902,6 +902,12 @@ test "following without reblogs" do |> post("/api/v1/accounts/#{followed.id}/follow", %{reblogs: true}) |> json_response_and_validate_schema(200) + assert %{"showing_reblogs" => true} = + conn + |> put_req_header("content-type", "application/json") + |> post("/api/v1/accounts/#{followed.id}/follow", %{reblogs: "1"}) + |> json_response_and_validate_schema(200) + assert [%{"id" => ^reblog_id}] = conn |> get("/api/v1/timelines/home") @@ -931,6 +937,12 @@ test "following with reblogs" do |> post("/api/v1/accounts/#{followed.id}/follow", %{reblogs: false}) |> json_response_and_validate_schema(200) + assert %{"showing_reblogs" => false} = + conn + |> put_req_header("content-type", "application/json") + |> post("/api/v1/accounts/#{followed.id}/follow", %{reblogs: "0"}) + |> json_response_and_validate_schema(200) + assert [] == conn |> get("/api/v1/timelines/home") @@ -941,21 +953,23 @@ test "following with subscription and unsubscribing" do %{conn: conn} = oauth_access(["follow"]) followed = insert(:user) - ret_conn = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/accounts/#{followed.id}/follow", %{notify: true}) + assert %{"subscribing" => true} = + conn + |> put_req_header("content-type", "application/json") + |> post("/api/v1/accounts/#{followed.id}/follow", %{notify: true}) + |> json_response_and_validate_schema(200) - assert %{"id" => _id, "subscribing" => true} = - json_response_and_validate_schema(ret_conn, 200) + assert %{"subscribing" => true} = + conn + |> put_req_header("content-type", "application/json") + |> post("/api/v1/accounts/#{followed.id}/follow", %{notify: "1"}) + |> json_response_and_validate_schema(200) - ret_conn = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/accounts/#{followed.id}/follow", %{notify: false}) - - assert %{"id" => _id, "subscribing" => false} = - json_response_and_validate_schema(ret_conn, 200) + assert %{"subscribing" => false} = + conn + |> put_req_header("content-type", "application/json") + |> post("/api/v1/accounts/#{followed.id}/follow", %{notify: false}) + |> json_response_and_validate_schema(200) end test "following / unfollowing errors", %{user: user, conn: conn} do From 2fe1484ed35d4537249a28e444a1fe3e82cfa382 Mon Sep 17 00:00:00 2001 From: floatingghost Date: Thu, 24 Nov 2022 12:27:16 +0000 Subject: [PATCH 060/631] http timeout config (#307) Ref https://meta.akkoma.dev/t/increase-timeout-on-libretranslate-request-how/156/2 Co-authored-by: FloatingGhost Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma/pulls/307 --- CHANGELOG.md | 3 +++ config/config.exs | 2 ++ config/description.exs | 15 ++++++++++++++ docs/docs/configuration/cheatsheet.md | 2 ++ lib/pleroma/http/adapter_helper/default.ex | 8 +++++++- test/pleroma/http/adapter_helper_test.exs | 23 ++++++++++++++++++++-- 6 files changed, 50 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 781fbe6e5..cbf1ac832 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## Unreleased +## Added +- Config: HTTP timeout options, :pool\_timeout and :receive\_timeout + ## Changed - MastoAPI: Accept BooleanLike input on `/api/v1/accounts/:id/follow` (fixes follows with mastodon.py) diff --git a/config/config.exs b/config/config.exs index 5278896f1..04fcd4964 100644 --- a/config/config.exs +++ b/config/config.exs @@ -180,6 +180,8 @@ # Configures http settings, upstream proxy etc. config :pleroma, :http, + pool_timeout: :timer.seconds(5), + receive_timeout: :timer.seconds(15), proxy_url: nil, user_agent: :default, adapter: [] diff --git a/config/description.exs b/config/description.exs index 994bb7280..fc10cbf81 100644 --- a/config/description.exs +++ b/config/description.exs @@ -2658,6 +2658,21 @@ type: :group, description: "HTTP settings", children: [ + %{ + key: :pool_timeout, + label: "HTTP Pool Request Timeout", + type: :integer, + description: "Timeout for initiating HTTP requests (in ms, default 5000)", + suggestions: [5000] + }, + %{ + key: :receive_timeout, + label: "HTTP Receive Timeout", + type: :integer, + description: + "Timeout for waiting on remote servers to respond to HTTP requests (in ms, default 15000)", + suggestions: [15000] + }, %{ key: :proxy_url, label: "Proxy URL", diff --git a/docs/docs/configuration/cheatsheet.md b/docs/docs/configuration/cheatsheet.md index ee35d95bc..94c32f2a8 100644 --- a/docs/docs/configuration/cheatsheet.md +++ b/docs/docs/configuration/cheatsheet.md @@ -523,6 +523,8 @@ Available caches: ### :http +* `receive_timeout`: the amount of time, in ms, to wait for a remote server to respond to a request. (default: `15000`) +* `pool_timeout`: the amount of time, in ms, to wait to check out an HTTP connection from the pool. This likely does not need changing unless your instance is _very_ busy with outbound requests. (default `5000`) * `proxy_url`: an upstream proxy to fetch posts and/or media with, (default: `nil`); for example `http://127.0.0.1:3192`. Does not support SOCKS5 proxy, only http(s). * `send_user_agent`: should we include a user agent with HTTP requests? (default: `true`) * `user_agent`: what user agent should we use? (default: `:default`), must be string or `:default` diff --git a/lib/pleroma/http/adapter_helper/default.ex b/lib/pleroma/http/adapter_helper/default.ex index 630536871..fc377b376 100644 --- a/lib/pleroma/http/adapter_helper/default.ex +++ b/lib/pleroma/http/adapter_helper/default.ex @@ -10,7 +10,13 @@ defmodule Pleroma.HTTP.AdapterHelper.Default do @spec options(keyword(), URI.t()) :: keyword() def options(opts, _uri) do proxy = Pleroma.Config.get([:http, :proxy_url]) - AdapterHelper.maybe_add_proxy(opts, AdapterHelper.format_proxy(proxy)) + pool_timeout = Pleroma.Config.get([:http, :pool_timeout], 5000) + receive_timeout = Pleroma.Config.get([:http, :receive_timeout], 15_000) + + opts + |> AdapterHelper.maybe_add_proxy(AdapterHelper.format_proxy(proxy)) + |> Keyword.put(:pool_timeout, pool_timeout) + |> Keyword.put(:receive_timeout, receive_timeout) end @spec get_conn(URI.t(), keyword()) :: {:ok, keyword()} diff --git a/test/pleroma/http/adapter_helper_test.exs b/test/pleroma/http/adapter_helper_test.exs index 55ffe4921..ba09f3422 100644 --- a/test/pleroma/http/adapter_helper_test.exs +++ b/test/pleroma/http/adapter_helper_test.exs @@ -3,8 +3,7 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.HTTP.AdapterHelperTest do - use ExUnit.Case, async: true - + use Pleroma.DataCase, async: true alias Pleroma.HTTP.AdapterHelper describe "format_proxy/1" do @@ -47,4 +46,24 @@ test "should not override conn_opts if set" do ] end end + + describe "timeout settings" do + test "should default to 5000/15000" do + options = AdapterHelper.options(%URI{host: 'somewhere'}) + assert options[:pool_timeout] == 5000 + assert options[:receive_timeout] == 15_000 + end + + test "pool_timeout should be overridden by :http, :pool_timeout" do + clear_config([:http, :pool_timeout], 10_000) + options = AdapterHelper.options(%URI{host: 'somewhere'}) + assert options[:pool_timeout] == 10_000 + end + + test "receive_timeout should be overridden by :http, :receive_timeout" do + clear_config([:http, :receive_timeout], 20_000) + options = AdapterHelper.options(%URI{host: 'somewhere'}) + assert options[:receive_timeout] == 20_000 + end + end end From ca35a4c835cbb50837c8b4f39910a96c1cd4aaa3 Mon Sep 17 00:00:00 2001 From: astra akari Date: Fri, 25 Nov 2022 00:45:32 +0000 Subject: [PATCH 061/631] change default allow_relay to false relay functionality should be opt-in --- config/config.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/config.exs b/config/config.exs index 644155aeb..301c2b05c 100644 --- a/config/config.exs +++ b/config/config.exs @@ -215,7 +215,7 @@ federation_publisher_modules: [ Pleroma.Web.ActivityPub.Publisher ], - allow_relay: true, + allow_relay: false, public: true, static_dir: "instance/static/", allowed_post_formats: [ From b2411f91730bf97ffe0026ee2fa8c62077737c4a Mon Sep 17 00:00:00 2001 From: Norm Date: Fri, 25 Nov 2022 07:29:50 +0000 Subject: [PATCH 062/631] Remove reference to city.jpg in COPYING Again forgot to remove a reference to a deleted file... Hopefully this should be the last one. --- COPYING | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/COPYING b/COPYING index 077a664ed..3df29344c 100644 --- a/COPYING +++ b/COPYING @@ -29,19 +29,3 @@ Attribution-ShareAlike 4.0 International license, you should have received a copy of the license file as CC-BY-SA-4.0. priv/static/instance/thumbnail.jpeg - ---- - -All photos published on Unsplash can be used for free. You can use them for -commercial and noncommercial purposes. You do not need to ask permission from -or provide credit to the photographer or Unsplash, although it is appreciated -when possible. - -More precisely, Unsplash grants you an irrevocable, nonexclusive, worldwide -copyright license to download, copy, modify, distribute, perform, and use -photos from Unsplash for free, including for commercial purposes, without -permission from or attributing the photographer or Unsplash. This license -does not include the right to compile photos from Unsplash to replicate -a similar or competing service. - -priv/static/images/city.jpg From ec1d903f2ee1a65ae539c3258b4406e81ca73055 Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Fri, 25 Nov 2022 15:24:39 +0000 Subject: [PATCH 063/631] Note that openbsd needs erlang-wx --- docs/docs/installation/openbsd_en.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/docs/installation/openbsd_en.md b/docs/docs/installation/openbsd_en.md index 9693467f2..7b20c796a 100644 --- a/docs/docs/installation/openbsd_en.md +++ b/docs/docs/installation/openbsd_en.md @@ -12,9 +12,11 @@ For any additional information regarding commands and configuration files mentio To install them, run the following command (with doas or as root): ``` -pkg_add elixir gmake git postgresql-server postgresql-contrib cmake ffmpeg ImageMagick +pkg_add elixir gmake git postgresql-server postgresql-contrib cmake ffmpeg ImageMagick erlang-wx-25 ``` +(Note that the erlang version may change, it was 25 at the time of writing) + Akkoma requires a reverse proxy, OpenBSD has relayd in base (and is used in this guide) and packages/ports are available for nginx (www/nginx) and apache (www/apache-httpd). Independently of the reverse proxy, [acme-client(1)](https://man.openbsd.org/acme-client) can be used to get a certificate from Let's Encrypt. #### Optional software From a90c45b7e92ef5fb77e16bd103894e58cd4e17c6 Mon Sep 17 00:00:00 2001 From: "@luna@f.l4.pm" Date: Sat, 26 Nov 2022 19:22:56 +0000 Subject: [PATCH 064/631] Add Signed Fetch Statistics (#312) Close #304. Notes: - This patch was made on top of Pleroma develop, so I created a separate cachex worker for request signature actions, instead of Akkoma's instance cache. If that is a merge blocker, I can attempt to move logic around for that. - Regarding the `has_request_signatures: true -> false` state transition: I think that is a higher level thing (resetting instance state on new instance actor key) which is separate from the changes relevant to this one. Co-authored-by: Luna Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma/pulls/312 Co-authored-by: @luna@f.l4.pm Co-committed-by: @luna@f.l4.pm --- lib/pleroma/application.ex | 3 +- lib/pleroma/instances.ex | 2 + lib/pleroma/instances/instance.ex | 30 +++- lib/pleroma/web/plugs/http_signature_plug.ex | 45 +++++ ...21123221956_add_has_request_signatures.exs | 9 + test/pleroma/instances_test.exs | 18 ++ .../web/plugs/http_signature_plug_test.exs | 167 ++++++++++++------ 7 files changed, 216 insertions(+), 58 deletions(-) create mode 100644 priv/repo/migrations/20221123221956_add_has_request_signatures.exs diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex index b9bcad40c..ec8839e0f 100644 --- a/lib/pleroma/application.ex +++ b/lib/pleroma/application.ex @@ -157,7 +157,8 @@ defp cachex_children do build_cachex("failed_proxy_url", limit: 2500), build_cachex("banned_urls", default_ttl: :timer.hours(24 * 30), limit: 5_000), build_cachex("translations", default_ttl: :timer.hours(24 * 30), limit: 2500), - build_cachex("instances", default_ttl: :timer.hours(24), ttl_interval: 1000, limit: 2500) + build_cachex("instances", default_ttl: :timer.hours(24), ttl_interval: 1000, limit: 2500), + build_cachex("request_signatures", default_ttl: :timer.hours(24 * 30), limit: 3000) ] end diff --git a/lib/pleroma/instances.ex b/lib/pleroma/instances.ex index 6b57e56da..daea102db 100644 --- a/lib/pleroma/instances.ex +++ b/lib/pleroma/instances.ex @@ -43,4 +43,6 @@ def host(url_or_host) when is_binary(url_or_host) do url_or_host end end + + defdelegate set_request_signatures(url_or_host), to: Instance end diff --git a/lib/pleroma/instances/instance.ex b/lib/pleroma/instances/instance.ex index 27dbf7661..6ddfa5042 100644 --- a/lib/pleroma/instances/instance.ex +++ b/lib/pleroma/instances/instance.ex @@ -26,6 +26,7 @@ defmodule Pleroma.Instances.Instance do field(:favicon, :string) field(:metadata_updated_at, :naive_datetime) field(:nodeinfo, :map, default: %{}) + field(:has_request_signatures, :boolean) timestamps() end @@ -34,7 +35,14 @@ defmodule Pleroma.Instances.Instance do def changeset(struct, params \\ %{}) do struct - |> cast(params, [:host, :unreachable_since, :favicon, :nodeinfo, :metadata_updated_at]) + |> cast(params, [ + :host, + :unreachable_since, + :favicon, + :nodeinfo, + :metadata_updated_at, + :has_request_signatures + ]) |> validate_required([:host]) |> unique_constraint(:host) end @@ -316,4 +324,24 @@ def get_cached_by_url(url_or_host) do end) end end + + def set_request_signatures(url_or_host) when is_binary(url_or_host) do + host = host(url_or_host) + existing_record = Repo.get_by(Instance, %{host: host}) + changes = %{has_request_signatures: true} + + cond do + is_nil(existing_record) -> + %Instance{} + |> changeset(Map.put(changes, :host, host)) + |> Repo.insert() + + true -> + existing_record + |> changeset(changes) + |> Repo.update() + end + end + + def set_request_signatures(_), do: {:error, :invalid_input} end diff --git a/lib/pleroma/web/plugs/http_signature_plug.ex b/lib/pleroma/web/plugs/http_signature_plug.ex index c906a4eec..5ed3235e2 100644 --- a/lib/pleroma/web/plugs/http_signature_plug.ex +++ b/lib/pleroma/web/plugs/http_signature_plug.ex @@ -7,8 +7,12 @@ defmodule Pleroma.Web.Plugs.HTTPSignaturePlug do import Phoenix.Controller, only: [get_format: 1, text: 2] alias Pleroma.Activity alias Pleroma.Web.Router + alias Pleroma.Signature + alias Pleroma.Instances require Logger + @cachex Pleroma.Config.get([:cachex, :provider], Cachex) + def init(options) do options end @@ -57,6 +61,7 @@ defp assign_valid_signature_on_route_aliases(conn, [path | rest]) do conn |> assign(:valid_signature, HTTPSignatures.validate_conn(conn)) + |> assign(:signature_actor_id, signature_host(conn)) |> assign_valid_signature_on_route_aliases(rest) end @@ -78,6 +83,36 @@ defp has_signature_header?(conn) do conn |> get_req_header("signature") |> Enum.at(0, false) end + defp maybe_require_signature( + %{assigns: %{valid_signature: true, signature_actor_id: actor_id}} = conn + ) do + # inboxes implicitly need http signatures for authentication + # so we don't really know if the instance will have broken federation after + # we turn on authorized_fetch_mode. + # + # to "check" this is a signed fetch, verify if method is GET + if conn.method == "GET" do + actor_host = URI.parse(actor_id).host + + case @cachex.get(:request_signatures_cache, actor_host) do + {:ok, nil} -> + Logger.debug("Successful signature from #{actor_host}") + Instances.set_request_signatures(actor_host) + @cachex.put(:request_signatures_cache, actor_host, true) + + {:ok, true} -> + :noop + + any -> + Logger.warn( + "expected request signature cache to return a boolean, instead got #{inspect(any)}" + ) + end + end + + conn + end + defp maybe_require_signature(%{assigns: %{valid_signature: true}} = conn), do: conn defp maybe_require_signature(conn) do @@ -90,4 +125,14 @@ defp maybe_require_signature(conn) do conn end end + + defp signature_host(conn) do + with %{"keyId" => kid} <- HTTPSignatures.signature_for_conn(conn), + {:ok, actor_id} <- Signature.key_id_to_actor_id(kid) do + actor_id + else + e -> + {:error, e} + end + end end diff --git a/priv/repo/migrations/20221123221956_add_has_request_signatures.exs b/priv/repo/migrations/20221123221956_add_has_request_signatures.exs new file mode 100644 index 000000000..b174b6f3a --- /dev/null +++ b/priv/repo/migrations/20221123221956_add_has_request_signatures.exs @@ -0,0 +1,9 @@ +defmodule Pleroma.Repo.Migrations.AddHasRequestSignatures do + use Ecto.Migration + + def change do + alter table(:instances) do + add(:has_request_signatures, :boolean, default: false, null: false) + end + end +end diff --git a/test/pleroma/instances_test.exs b/test/pleroma/instances_test.exs index 03f9e4e97..744ee8df3 100644 --- a/test/pleroma/instances_test.exs +++ b/test/pleroma/instances_test.exs @@ -4,6 +4,7 @@ defmodule Pleroma.InstancesTest do alias Pleroma.Instances + alias Pleroma.Instances.Instance use Pleroma.DataCase @@ -121,4 +122,21 @@ test "keeps unreachable url or host unreachable" do refute Instances.reachable?(host) end end + + describe "set_request_signatures/1" do + test "sets instance has request signatures" do + host = "domain.com" + + {:ok, instance} = Instances.set_request_signatures(host) + assert instance.has_request_signatures + + {:ok, cached_instance} = Instance.get_cached_by_url(host) + assert cached_instance.has_request_signatures + end + + test "returns error status on non-binary input" do + assert {:error, _} = Instances.set_request_signatures(nil) + assert {:error, _} = Instances.set_request_signatures(1) + end + end end diff --git a/test/pleroma/web/plugs/http_signature_plug_test.exs b/test/pleroma/web/plugs/http_signature_plug_test.exs index 8ce956510..49e0b9808 100644 --- a/test/pleroma/web/plugs/http_signature_plug_test.exs +++ b/test/pleroma/web/plugs/http_signature_plug_test.exs @@ -1,34 +1,90 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2021 Pleroma Authors +# Copyright © 2017-2022 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.Plugs.HTTPSignaturePlugTest do - use Pleroma.Web.ConnCase + use Pleroma.Web.ConnCase, async: false import Pleroma.Factory alias Pleroma.Web.Plugs.HTTPSignaturePlug + alias Pleroma.Instances.Instance + alias Pleroma.Repo import Plug.Conn import Phoenix.Controller, only: [put_format: 2] import Mock - test "it call HTTPSignatures to check validity if the actor sighed it" do + setup_with_mocks([ + {HTTPSignatures, [], + [ + signature_for_conn: fn _ -> + %{"keyId" => "http://mastodon.example.org/users/admin#main-key"} + end, + validate_conn: fn conn -> + Map.get(conn.assigns, :valid_signature, true) + end + ]} + ]) do + :ok + end + + defp submit_to_plug(host), do: submit_to_plug(host, :get, "/doesntmattter") + + defp submit_to_plug(host, method, path) do + params = %{"actor" => "http://#{host}/users/admin"} + + build_conn(method, path, params) + |> put_req_header( + "signature", + "keyId=\"http://#{host}/users/admin#main-key" + ) + |> put_format("activity+json") + |> HTTPSignaturePlug.call(%{}) + end + + test "it call HTTPSignatures to check validity if the actor signed it" do params = %{"actor" => "http://mastodon.example.org/users/admin"} conn = build_conn(:get, "/doesntmattter", params) - with_mock HTTPSignatures, validate_conn: fn _ -> true end do - conn = - conn - |> put_req_header( - "signature", - "keyId=\"http://mastodon.example.org/users/admin#main-key" - ) - |> put_format("activity+json") - |> HTTPSignaturePlug.call(%{}) + conn = + conn + |> put_req_header( + "signature", + "keyId=\"http://mastodon.example.org/users/admin#main-key" + ) + |> put_format("activity+json") + |> HTTPSignaturePlug.call(%{}) - assert conn.assigns.valid_signature == true - assert conn.halted == false - assert called(HTTPSignatures.validate_conn(:_)) - end + assert conn.assigns.valid_signature == true + assert conn.assigns.signature_actor_id == params["actor"] + assert conn.halted == false + assert called(HTTPSignatures.validate_conn(:_)) + end + + test "it sets request signatures property on the instance" do + host = "mastodon.example.org" + conn = submit_to_plug(host) + assert conn.assigns.valid_signature == true + instance = Repo.get_by(Instance, %{host: host}) + assert instance.has_request_signatures + end + + test "it does not set request signatures property on the instance when using inbox" do + host = "mastodon.example.org" + conn = submit_to_plug(host, :post, "/inbox") + assert conn.assigns.valid_signature == true + + # we don't even create the instance entry if its just POST /inbox + refute Repo.get_by(Instance, %{host: host}) + end + + test "it does not set request signatures property on the instance when its cached" do + host = "mastodon.example.org" + Cachex.put(:request_signatures_cache, host, true) + conn = submit_to_plug(host) + assert conn.assigns.valid_signature == true + + # we don't even create the instance entry if it was already done + refute Repo.get_by(Instance, %{host: host}) end describe "requires a signature when `authorized_fetch_mode` is enabled" do @@ -41,40 +97,39 @@ test "it call HTTPSignatures to check validity if the actor sighed it" do [conn: conn] end - test "when signature header is present", %{conn: conn} do - with_mock HTTPSignatures, validate_conn: fn _ -> false end do - conn = - conn - |> put_req_header( - "signature", - "keyId=\"http://mastodon.example.org/users/admin#main-key" - ) - |> HTTPSignaturePlug.call(%{}) + test "and signature is present and incorrect", %{conn: conn} do + conn = + conn + |> assign(:valid_signature, false) + |> put_req_header( + "signature", + "keyId=\"http://mastodon.example.org/users/admin#main-key" + ) + |> HTTPSignaturePlug.call(%{}) - assert conn.assigns.valid_signature == false - assert conn.halted == true - assert conn.status == 401 - assert conn.state == :sent - assert conn.resp_body == "Request not signed" - assert called(HTTPSignatures.validate_conn(:_)) - end - - with_mock HTTPSignatures, validate_conn: fn _ -> true end do - conn = - conn - |> put_req_header( - "signature", - "keyId=\"http://mastodon.example.org/users/admin#main-key" - ) - |> HTTPSignaturePlug.call(%{}) - - assert conn.assigns.valid_signature == true - assert conn.halted == false - assert called(HTTPSignatures.validate_conn(:_)) - end + assert conn.assigns.valid_signature == false + assert conn.halted == true + assert conn.status == 401 + assert conn.state == :sent + assert conn.resp_body == "Request not signed" + assert called(HTTPSignatures.validate_conn(:_)) end - test "halts the connection when `signature` header is not present", %{conn: conn} do + test "and signature is correct", %{conn: conn} do + conn = + conn + |> put_req_header( + "signature", + "keyId=\"http://mastodon.example.org/users/admin#main-key" + ) + |> HTTPSignaturePlug.call(%{}) + + assert conn.assigns.valid_signature == true + assert conn.halted == false + assert called(HTTPSignatures.validate_conn(:_)) + end + + test "and halts the connection when `signature` header is not present", %{conn: conn} do conn = HTTPSignaturePlug.call(conn, %{}) assert conn.assigns[:valid_signature] == nil assert conn.halted == true @@ -82,16 +137,16 @@ test "halts the connection when `signature` header is not present", %{conn: conn assert conn.state == :sent assert conn.resp_body == "Request not signed" end + end - test "aliases redirected /object endpoints", _ do - obj = insert(:note) - act = insert(:note_activity, note: obj) - params = %{"actor" => "someparam"} - path = URI.parse(obj.data["id"]).path - conn = build_conn(:get, path, params) + test "aliases redirected /object endpoints", _ do + obj = insert(:note) + act = insert(:note_activity, note: obj) + params = %{"actor" => "someparam"} + path = URI.parse(obj.data["id"]).path + conn = build_conn(:get, path, params) - assert ["/notice/#{act.id}", "/notice/#{act.id}?actor=someparam"] == - HTTPSignaturePlug.route_aliases(conn) - end + assert ["/notice/#{act.id}", "/notice/#{act.id}?actor=someparam"] == + HTTPSignaturePlug.route_aliases(conn) end end From 565ead8397f01a57acd35142d66a5ee3985f68cf Mon Sep 17 00:00:00 2001 From: "@r3g_5z@plem.sapphic.site" Date: Sat, 26 Nov 2022 19:27:58 +0000 Subject: [PATCH 065/631] minor-changes (#313) Only real change here is making MRF rejects log as debug instead of info (https://akkoma.dev/AkkomaGang/akkoma/issues/234) I don't know if it's the best way to do it, but it seems it's just MRF using this and almost always this is intended. The rest are just minor docs changes and syncing the restricted nicknames stuff. I compiled and ran my changes with Docker and they all work. Co-authored-by: r3g_5z Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma/pulls/313 Co-authored-by: @r3g_5z@plem.sapphic.site Co-committed-by: @r3g_5z@plem.sapphic.site --- docs/docs/configuration/hardening.md | 4 ++-- docs/docs/installation/docker_en.md | 3 ++- lib/pleroma/object/fetcher.ex | 2 +- lib/pleroma/web/activity_pub/activity_pub.ex | 2 +- lib/pleroma/web/api_spec/operations/twitter_util_operation.ex | 2 +- 5 files changed, 7 insertions(+), 6 deletions(-) diff --git a/docs/docs/configuration/hardening.md b/docs/docs/configuration/hardening.md index c5a9e160b..521183f7d 100644 --- a/docs/docs/configuration/hardening.md +++ b/docs/docs/configuration/hardening.md @@ -55,11 +55,11 @@ An additional “Strict transport security” header will be sent with the confi > Recommended value: `same-origin` -If you click on a link, your browser’s request to the other site will include from where it is coming from. The “Referrer policy” header tells the browser how and if it should send this information. (see [Referrer policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy)) +If you click on a link, your browser’s request to the other site will include from where it is coming from. The “Referrer policy” header tells the browser how and if it should send this information. (see [Referrer policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy)). `no-referrer` can be used if a referrer is not needed for improved privacy. ## systemd -A systemd unit example is provided at `installation/pleroma.service`. +A systemd unit example is provided at `installation/akkoma.service`. ### PrivateTmp diff --git a/docs/docs/installation/docker_en.md b/docs/docs/installation/docker_en.md index 64169852f..2a3b3d161 100644 --- a/docs/docs/installation/docker_en.md +++ b/docs/docs/installation/docker_en.md @@ -51,7 +51,8 @@ mkdir pgdata ``` This will ask you a few questions - the defaults are fine for most things, -the database hostname is `db`, and you will want to set the ip to `0.0.0.0`. +the database hostname is `db`, the database password is `akkoma` +(not auto generated), and you will want to set the ip to `0.0.0.0`. Now we'll want to copy over the config it just created diff --git a/lib/pleroma/object/fetcher.ex b/lib/pleroma/object/fetcher.ex index aafab6643..a9dfa18e7 100644 --- a/lib/pleroma/object/fetcher.ex +++ b/lib/pleroma/object/fetcher.ex @@ -184,7 +184,7 @@ def fetch_object_from_id!(id, options \\ []) do nil {:reject, reason} -> - Logger.info("Rejected #{id} while fetching: #{inspect(reason)}") + Logger.debug("Rejected #{id} while fetching: #{inspect(reason)}") nil e -> diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 3a9b08cf0..76b99025b 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -1674,7 +1674,7 @@ def fetch_and_prepare_user_from_ap_id(ap_id, additional \\ []) do {:error, e} {:error, {:reject, reason} = e} -> - Logger.info("Rejected user #{ap_id}: #{inspect(reason)}") + Logger.debug("Rejected user #{ap_id}: #{inspect(reason)}") {:error, e} {:error, e} -> diff --git a/lib/pleroma/web/api_spec/operations/twitter_util_operation.ex b/lib/pleroma/web/api_spec/operations/twitter_util_operation.ex index c025867a2..456ab14db 100644 --- a/lib/pleroma/web/api_spec/operations/twitter_util_operation.ex +++ b/lib/pleroma/web/api_spec/operations/twitter_util_operation.ex @@ -81,7 +81,7 @@ def change_password_operation do defp change_password_request do %Schema{ title: "ChangePasswordRequest", - description: "POST body for changing the account's passowrd", + description: "POST body for changing the account's password", type: :object, required: [:password, :new_password, :new_password_confirmation], properties: %{ From e3085c495c221b52f40c95a9beab33e51f02d81b Mon Sep 17 00:00:00 2001 From: floatingghost Date: Sat, 26 Nov 2022 20:45:47 +0000 Subject: [PATCH 066/631] fix tests broken by relay defaults changing (#314) Co-authored-by: FloatingGhost Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma/pulls/314 --- .woodpecker.yml | 12 ++--- CHANGELOG.md | 2 + lib/mix/tasks/pleroma/user.ex | 8 +-- mix.exs | 2 +- mix.lock | 51 ++++++++++--------- test/pleroma/user/import_test.exs | 1 - test/pleroma/user_search_test.exs | 1 - .../activity_pub_controller_test.exs | 2 +- test/pleroma/web/federator_test.exs | 2 +- .../controllers/timeline_controller_test.exs | 4 +- .../media_proxy/invalidation/script_test.exs | 11 ++-- 11 files changed, 50 insertions(+), 46 deletions(-) diff --git a/.woodpecker.yml b/.woodpecker.yml index c97e3eb4f..fa2114337 100644 --- a/.woodpecker.yml +++ b/.woodpecker.yml @@ -53,14 +53,14 @@ services: pipeline: lint: <<: *on-pr-open - image: akkoma/ci-base:latest + image: akkoma/ci-base:1.14 commands: - mix local.hex --force - mix local.rebar --force - mix format --check-formatted build: - image: akkoma/ci-base:latest + image: akkoma/ci-base:1.14 <<: *on-pr-open environment: MIX_ENV: test @@ -75,7 +75,7 @@ pipeline: - mix compile test: - image: akkoma/ci-base:latest + image: akkoma/ci-base:1.14 <<: *on-pr-open environment: MIX_ENV: test @@ -95,7 +95,7 @@ pipeline: # Canonical amd64 ubuntu22: - image: hexpm/elixir:1.13.4-erlang-24.3.4.5-ubuntu-jammy-20220428 + image: hexpm/elixir:1.14.2-erlang-25.1.2-ubuntu-jammy-20220428 <<: *on-release environment: MIX_ENV: prod @@ -122,7 +122,7 @@ pipeline: - /bin/sh /entrypoint.sh debian-bullseye: - image: hexpm/elixir:1.13.4-erlang-24.3.4.5-debian-bullseye-20220801 + image: hexpm/elixir:1.14.2-erlang-25.1.2-debian-bullseye-20221004 <<: *on-release environment: MIX_ENV: prod @@ -151,7 +151,7 @@ pipeline: # Canonical amd64-musl musl: - image: hexpm/elixir:1.13.4-erlang-24.3.4.5-alpine-3.15.6 + image: hexpm/elixir:1.14.2-erlang-25.1.2-alpine-3.16.2 <<: *on-stable environment: MIX_ENV: prod diff --git a/CHANGELOG.md b/CHANGELOG.md index cbf1ac832..6a5402da1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,9 +8,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## Added - Config: HTTP timeout options, :pool\_timeout and :receive\_timeout +- Added statistic gathering about instances which do/don't have signed fetches when they request from us ## Changed - MastoAPI: Accept BooleanLike input on `/api/v1/accounts/:id/follow` (fixes follows with mastodon.py) +- Relays from akkoma are now off by default ## 2022.11 diff --git a/lib/mix/tasks/pleroma/user.ex b/lib/mix/tasks/pleroma/user.ex index 50c3fd7ce..278a01acc 100644 --- a/lib/mix/tasks/pleroma/user.ex +++ b/lib/mix/tasks/pleroma/user.ex @@ -113,9 +113,11 @@ def run(["reset_password", nickname]) do {:ok, token} <- Pleroma.PasswordResetToken.create_token(user) do shell_info("Generated password reset token for #{user.nickname}") - IO.puts("URL: #{Pleroma.Web.Router.Helpers.reset_password_url(Pleroma.Web.Endpoint, - :reset, - token.token)}") + IO.puts( + "URL: #{Pleroma.Web.Router.Helpers.reset_password_url(Pleroma.Web.Endpoint, + :reset, + token.token)}" + ) else _ -> shell_error("No local user #{nickname}") diff --git a/mix.exs b/mix.exs index 201299aa5..69b708572 100644 --- a/mix.exs +++ b/mix.exs @@ -134,7 +134,7 @@ defp deps do {:phoenix_html, "~> 3.1", override: true}, {:calendar, "~> 1.0"}, {:cachex, "~> 3.4"}, - {:poison, "~> 3.0", override: true}, + {:poison, "~> 5.0", override: true}, {:tesla, "~> 1.4.4", override: true}, {:castore, "~> 0.1"}, {:cowlib, "~> 2.9", override: true}, diff --git a/mix.lock b/mix.lock index d3400da7a..dda8f92ec 100644 --- a/mix.lock +++ b/mix.lock @@ -3,11 +3,11 @@ "bbcode_pleroma": {:hex, :bbcode_pleroma, "0.2.0", "d36f5bca6e2f62261c45be30fa9b92725c0655ad45c99025cb1c3e28e25803ef", [:mix], [{:nimble_parsec, "~> 0.5", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "19851074419a5fedb4ef49e1f01b30df504bb5dbb6d6adfc135238063bebd1c3"}, "bcrypt_elixir": {:hex, :bcrypt_elixir, "2.3.1", "5114d780459a04f2b4aeef52307de23de961b69e13a5cd98a911e39fda13f420", [:make, :mix], [{:comeonin, "~> 5.3", [hex: :comeonin, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "42182d5f46764def15bf9af83739e3bf4ad22661b1c34fc3e88558efced07279"}, "benchee": {:hex, :benchee, "1.1.0", "f3a43817209a92a1fade36ef36b86e1052627fd8934a8b937ac9ab3a76c43062", [:mix], [{:deep_merge, "~> 1.0", [hex: :deep_merge, repo: "hexpm", optional: false]}, {:statistex, "~> 1.0", [hex: :statistex, repo: "hexpm", optional: false]}], "hexpm", "7da57d545003165a012b587077f6ba90b89210fd88074ce3c60ce239eb5e6d93"}, - "bunt": {:hex, :bunt, "0.2.0", "951c6e801e8b1d2cbe58ebbd3e616a869061ddadcc4863d0a2182541acae9a38", [:mix], [], "hexpm", "7af5c7e09fe1d40f76c8e4f9dd2be7cebd83909f31fee7cd0e9eadc567da8353"}, + "bunt": {:hex, :bunt, "0.2.1", "e2d4792f7bc0ced7583ab54922808919518d0e57ee162901a16a1b6664ef3b14", [:mix], [], "hexpm", "a330bfb4245239787b15005e66ae6845c9cd524a288f0d141c148b02603777a5"}, "cachex": {:hex, :cachex, "3.4.0", "868b2959ea4aeb328c6b60ff66c8d5123c083466ad3c33d3d8b5f142e13101fb", [:mix], [{:eternal, "~> 1.2", [hex: :eternal, repo: "hexpm", optional: false]}, {:jumper, "~> 1.0", [hex: :jumper, repo: "hexpm", optional: false]}, {:sleeplocks, "~> 1.1", [hex: :sleeplocks, repo: "hexpm", optional: false]}, {:unsafe, "~> 1.0", [hex: :unsafe, repo: "hexpm", optional: false]}], "hexpm", "370123b1ab4fba4d2965fb18f87fd758325709787c8c5fce35b3fe80645ccbe5"}, - "calendar": {:hex, :calendar, "1.0.0", "f52073a708528482ec33d0a171954ca610fe2bd28f1e871f247dc7f1565fa807", [:mix], [{:tzdata, "~> 0.5.20 or ~> 0.1.201603 or ~> 1.0", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm", "990e9581920c82912a5ee50e62ff5ef96da6b15949a2ee4734f935fdef0f0a6f"}, + "calendar": {:hex, :calendar, "1.0.0", "f52073a708528482ec33d0a171954ca610fe2bd28f1e871f247dc7f1565fa807", [:mix], [{:tzdata, "~> 0.1.201603 or ~> 0.5.20 or ~> 1.0", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm", "990e9581920c82912a5ee50e62ff5ef96da6b15949a2ee4734f935fdef0f0a6f"}, "captcha": {:git, "https://git.pleroma.social/pleroma/elixir-libraries/elixir-captcha.git", "e0f16822d578866e186a0974d65ad58cddc1e2ab", [ref: "e0f16822d578866e186a0974d65ad58cddc1e2ab"]}, - "castore": {:hex, :castore, "0.1.18", "deb5b9ab02400561b6f5708f3e7660fc35ca2d51bfc6a940d2f513f89c2975fc", [:mix], [], "hexpm", "61bbaf6452b782ef80b33cdb45701afbcf0a918a45ebe7e73f1130d661e66a06"}, + "castore": {:hex, :castore, "0.1.19", "a2c3e46d62b7f3aa2e6f88541c21d7400381e53704394462b9fd4f06f6d42bb6", [:mix], [], "hexpm", "e96e0161a5dc82ef441da24d5fa74aefc40d920f3a6645d15e1f9f3e66bb2109"}, "certifi": {:hex, :certifi, "2.9.0", "6f2a475689dd47f19fb74334859d460a2dc4e3252a3324bd2111b8f0429e7e21", [:rebar3], [], "hexpm", "266da46bdb06d6c6d35fde799bcb28d36d985d424ad7c08b5bb48f5b5cdd4641"}, "combine": {:hex, :combine, "0.10.0", "eff8224eeb56498a2af13011d142c5e7997a80c8f5b97c499f84c841032e429f", [:mix], [], "hexpm", "1b1dbc1790073076580d0d1d64e42eae2366583e7aecd455d1215b0d16f2451b"}, "comeonin": {:hex, :comeonin, "5.3.3", "2c564dac95a35650e9b6acfe6d2952083d8a08e4a89b93a481acb552b325892e", [:mix], [], "hexpm", "3e38c9c2cb080828116597ca8807bb482618a315bfafd98c90bc22a821cc84df"}, @@ -17,26 +17,26 @@ "cowboy": {:hex, :cowboy, "2.9.0", "865dd8b6607e14cf03282e10e934023a1bd8be6f6bacf921a7e2a96d800cd452", [:make, :rebar3], [{:cowlib, "2.11.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "2c729f934b4e1aa149aff882f57c6372c15399a20d54f65c8d67bef583021bde"}, "cowboy_telemetry": {:hex, :cowboy_telemetry, "0.3.1", "ebd1a1d7aff97f27c66654e78ece187abdc646992714164380d8a041eda16754", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "3a6efd3366130eab84ca372cbd4a7d3c3a97bdfcfb4911233b035d117063f0af"}, "cowlib": {:hex, :cowlib, "2.11.0", "0b9ff9c346629256c42ebe1eeb769a83c6cb771a6ee5960bd110ab0b9b872063", [:make, :rebar3], [], "hexpm", "2b3e9da0b21c4565751a6d4901c20d1b4cc25cbb7fd50d91d2ab6dd287bc86a9"}, - "credo": {:hex, :credo, "1.6.5", "330ca591c12244ab95498d8f47994c493064b2689febf1236d43d596b4f2261d", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2.8", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "101de53e6907397c3246ccd2cc9b9f0d3fc0b7805b8e1c1c3d818471fc85bafd"}, + "credo": {:hex, :credo, "1.6.7", "323f5734350fd23a456f2688b9430e7d517afb313fbd38671b8a4449798a7854", [:mix], [{:bunt, "~> 0.2.1", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2.8", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "41e110bfb007f7eda7f897c10bf019ceab9a0b269ce79f015d54b0dcf4fc7dd3"}, "crypt": {:git, "https://github.com/msantos/crypt.git", "f75cd55325e33cbea198fb41fe41871392f8fb76", [ref: "f75cd55325e33cbea198fb41fe41871392f8fb76"]}, "custom_base": {:hex, :custom_base, "0.2.1", "4a832a42ea0552299d81652aa0b1f775d462175293e99dfbe4d7dbaab785a706", [:mix], [], "hexpm", "8df019facc5ec9603e94f7270f1ac73ddf339f56ade76a721eaa57c1493ba463"}, - "db_connection": {:hex, :db_connection, "2.4.2", "f92e79aff2375299a16bcb069a14ee8615c3414863a6fef93156aee8e86c2ff3", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "4fe53ca91b99f55ea249693a0229356a08f4d1a7931d8ffa79289b145fe83668"}, + "db_connection": {:hex, :db_connection, "2.4.3", "3b9aac9f27347ec65b271847e6baeb4443d8474289bd18c1d6f4de655b70c94d", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c127c15b0fa6cfb32eed07465e05da6c815b032508d4ed7c116122871df73c12"}, "decimal": {:hex, :decimal, "2.0.0", "a78296e617b0f5dd4c6caf57c714431347912ffb1d0842e998e9792b5642d697", [:mix], [], "hexpm", "34666e9c55dea81013e77d9d87370fe6cb6291d1ef32f46a1600230b1d44f577"}, "deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm", "ce708e5f094b9cd4e8f2be4f00d2f4250c4095be93f8cd6d018c753894885430"}, - "earmark": {:hex, :earmark, "1.4.26", "f0e3c3d5c278a6d448ad8c27ab0ecdec9c57a7710553138c56af220a6330a4fd", [:mix], [{:earmark_parser, "~> 1.4.26", [hex: :earmark_parser, repo: "hexpm", optional: false]}], "hexpm", "e1231882b56bece0692af33f0959f06c9cd580c2dc2ecb1dc9f16f2750fa78c5"}, - "earmark_parser": {:hex, :earmark_parser, "1.4.26", "f4291134583f373c7d8755566122908eb9662df4c4b63caa66a0eabe06569b0a", [:mix], [], "hexpm", "48d460899f8a0c52c5470676611c01f64f3337bad0b26ddab43648428d94aabc"}, + "earmark": {:hex, :earmark, "1.4.33", "2b33a505180583f98bfa17317f03973b52081bdb24a11be05a7f4fa6d64dd8bf", [:mix], [{:earmark_parser, "~> 1.4.29", [hex: :earmark_parser, repo: "hexpm", optional: false]}], "hexpm", "21b31363d6a0a70802cfbaf2de88355778aa76654298a072bce2e01d1858ae06"}, + "earmark_parser": {:hex, :earmark_parser, "1.4.29", "149d50dcb3a93d9f3d6f3ecf18c918fb5a2d3c001b5d3305c926cddfbd33355b", [:mix], [], "hexpm", "4902af1b3eb139016aed210888748db8070b8125c2342ce3dcae4f38dcc63503"}, "eblurhash": {:hex, :eblurhash, "1.2.2", "7da4255aaea984b31bb71155f673257353b0e0554d0d30dcf859547e74602582", [:rebar3], [], "hexpm", "8c20ca00904de023a835a9dcb7b7762fed32264c85a80c3cafa85288e405044c"}, - "ecto": {:hex, :ecto, "3.9.1", "67173b1687afeb68ce805ee7420b4261649d5e2deed8fe5550df23bab0bc4396", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c80bb3d736648df790f7f92f81b36c922d9dd3203ca65be4ff01d067f54eb304"}, + "ecto": {:hex, :ecto, "3.9.2", "017db3bc786ff64271108522c01a5d3f6ba0aea5c84912cfb0dd73bf13684108", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "21466d5177e09e55289ac7eade579a642578242c7a3a9f91ad5c6583337a9d15"}, "ecto_enum": {:hex, :ecto_enum, "1.4.0", "d14b00e04b974afc69c251632d1e49594d899067ee2b376277efd8233027aec8", [:mix], [{:ecto, ">= 3.0.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:ecto_sql, "> 3.0.0", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:mariaex, ">= 0.0.0", [hex: :mariaex, repo: "hexpm", optional: true]}, {:postgrex, ">= 0.0.0", [hex: :postgrex, repo: "hexpm", optional: true]}], "hexpm", "8fb55c087181c2b15eee406519dc22578fa60dd82c088be376d0010172764ee4"}, - "ecto_psql_extras": {:hex, :ecto_psql_extras, "0.7.4", "5d43fd088d39a158c860b17e8d210669587f63ec89ea122a4654861c8c6e2db4", [:mix], [{:ecto_sql, "~> 3.4", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:postgrex, ">= 0.15.7", [hex: :postgrex, repo: "hexpm", optional: false]}, {:table_rex, "~> 3.1.1", [hex: :table_rex, repo: "hexpm", optional: false]}], "hexpm", "311db02f1b772e3d0dc7f56a05044b5e1499d78ed6abf38885e1ca70059449e5"}, - "ecto_sql": {:hex, :ecto_sql, "3.9.0", "2bb21210a2a13317e098a420a8c1cc58b0c3421ab8e3acfa96417dab7817918c", [:mix], [{:db_connection, "~> 2.5 or ~> 2.4.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.9.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.6.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.16.0 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "a8f3f720073b8b1ac4c978be25fa7960ed7fd44997420c304a4a2e200b596453"}, + "ecto_psql_extras": {:hex, :ecto_psql_extras, "0.7.10", "e14d400930f401ca9f541b3349212634e44027d7f919bbb71224d7ac0d0e8acd", [:mix], [{:ecto_sql, "~> 3.4", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.15.7 or ~> 0.16.0", [hex: :postgrex, repo: "hexpm", optional: false]}, {:table_rex, "~> 3.1.1", [hex: :table_rex, repo: "hexpm", optional: false]}], "hexpm", "505e8cd81e4f17c090be0f99e92b1b3f0fd915f98e76965130b8ccfb891e7088"}, + "ecto_sql": {:hex, :ecto_sql, "3.9.1", "9bd5894eecc53d5b39d0c95180d4466aff00e10679e13a5cfa725f6f85c03c22", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.9.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.6.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.16.0 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "5fd470a4fff2e829bbf9dcceb7f3f9f6d1e49b4241e802f614de6b8b67c51118"}, "elasticsearch": {:git, "https://akkoma.dev/AkkomaGang/elasticsearch-elixir.git", "6cd946f75f6ab9042521a009d1d32d29a90113ca", [ref: "main"]}, "elixir_make": {:hex, :elixir_make, "0.6.3", "bc07d53221216838d79e03a8019d0839786703129599e9619f4ab74c8c096eac", [:mix], [], "hexpm", "f5cbd651c5678bcaabdbb7857658ee106b12509cd976c2c2fca99688e1daf716"}, "eternal": {:hex, :eternal, "1.2.2", "d1641c86368de99375b98d183042dd6c2b234262b8d08dfd72b9eeaafc2a1abd", [:mix], [], "hexpm", "2c9fe32b9c3726703ba5e1d43a1d255a4f3f2d8f8f9bc19f094c7cb1a7a9e782"}, "ex_aws": {:hex, :ex_aws, "2.1.9", "dc4865ecc20a05190a34a0ac5213e3e5e2b0a75a0c2835e923ae7bfeac5e3c31", [:mix], [{:configparser_ex, "~> 4.0", [hex: :configparser_ex, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: true]}, {:jsx, "~> 3.0", [hex: :jsx, repo: "hexpm", optional: true]}, {:sweet_xml, "~> 0.6", [hex: :sweet_xml, repo: "hexpm", optional: true]}], "hexpm", "3e6c776703c9076001fbe1f7c049535f042cb2afa0d2cbd3b47cbc4e92ac0d10"}, "ex_aws_s3": {:hex, :ex_aws_s3, "2.3.3", "61412e524616ea31d3f31675d8bc4c73f277e367dee0ae8245610446f9b778aa", [:mix], [{:ex_aws, "~> 2.0", [hex: :ex_aws, repo: "hexpm", optional: false]}, {:sweet_xml, ">= 0.0.0", [hex: :sweet_xml, repo: "hexpm", optional: true]}], "hexpm", "0044f0b6f9ce925666021eafd630de64c2b3404d79c85245cc7c8a9a32d7f104"}, "ex_const": {:hex, :ex_const, "0.2.4", "d06e540c9d834865b012a17407761455efa71d0ce91e5831e86881b9c9d82448", [:mix], [], "hexpm", "96fd346610cc992b8f896ed26a98be82ac4efb065a0578f334a32d60a3ba9767"}, - "ex_doc": {:hex, :ex_doc, "0.28.4", "001a0ea6beac2f810f1abc3dbf4b123e9593eaa5f00dd13ded024eae7c523298", [:mix], [{:earmark_parser, "~> 1.4.19", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "bf85d003dd34911d89c8ddb8bda1a958af3471a274a4c2150a9c01c78ac3f8ed"}, + "ex_doc": {:hex, :ex_doc, "0.29.1", "b1c652fa5f92ee9cf15c75271168027f92039b3877094290a75abcaac82a9f77", [:mix], [{:earmark_parser, "~> 1.4.19", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "b7745fa6374a36daf484e2a2012274950e084815b936b1319aeebcf7809574f6"}, "ex_machina": {:hex, :ex_machina, "2.7.0", "b792cc3127fd0680fecdb6299235b4727a4944a09ff0fa904cc639272cd92dc7", [:mix], [{:ecto, "~> 2.2 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_sql, "~> 3.0", [hex: :ecto_sql, repo: "hexpm", optional: true]}], "hexpm", "419aa7a39bde11894c87a615c4ecaa52d8f107bbdd81d810465186f783245bf8"}, "ex_syslogger": {:hex, :ex_syslogger, "1.5.2", "72b6aa2d47a236e999171f2e1ec18698740f40af0bd02c8c650bf5f1fd1bac79", [:mix], [{:poison, ">= 1.5.0", [hex: :poison, repo: "hexpm", optional: true]}, {:syslog, "~> 1.1.0", [hex: :syslog, repo: "hexpm", optional: false]}], "hexpm", "ab9fab4136dbc62651ec6f16fa4842f10cf02ab4433fa3d0976c01be99398399"}, "excoveralls": {:hex, :excoveralls, "0.12.3", "2142be7cb978a3ae78385487edda6d1aff0e482ffc6123877bb7270a8ffbcfe0", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "568a3e616c264283f5dea5b020783ae40eef3f7ee2163f7a67cbd7b35bcadada"}, @@ -45,16 +45,16 @@ "file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"}, "finch": {:hex, :finch, "0.13.0", "c881e5460ec563bf02d4f4584079e62201db676ed4c0ef3e59189331c4eddf7b", [:mix], [{:castore, "~> 0.1", [hex: :castore, repo: "hexpm", optional: false]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.3", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.2.6", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "49957dcde10dcdc042a123a507a9c5ec5a803f53646d451db2f7dea696fba6cc"}, "flake_id": {:hex, :flake_id, "0.1.0", "7716b086d2e405d09b647121a166498a0d93d1a623bead243e1f74216079ccb3", [:mix], [{:base62, "~> 1.2", [hex: :base62, repo: "hexpm", optional: false]}, {:ecto, ">= 2.0.0", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm", "31fc8090fde1acd267c07c36ea7365b8604055f897d3a53dd967658c691bd827"}, - "floki": {:hex, :floki, "0.33.1", "f20f1eb471e726342b45ccb68edb9486729e7df94da403936ea94a794f072781", [:mix], [{:html_entities, "~> 0.5.0", [hex: :html_entities, repo: "hexpm", optional: false]}], "hexpm", "461035fd125f13fdf30f243c85a0b1e50afbec876cbf1ceefe6fddd2e6d712c6"}, + "floki": {:hex, :floki, "0.34.0", "002d0cc194b48794d74711731db004fafeb328fe676976f160685262d43706a8", [:mix], [], "hexpm", "9c3a9f43f40dde00332a589bd9d389b90c1f518aef500364d00636acc5ebc99c"}, "gen_smtp": {:hex, :gen_smtp, "0.15.0", "9f51960c17769b26833b50df0b96123605a8024738b62db747fece14eb2fbfcc", [:rebar3], [], "hexpm", "29bd14a88030980849c7ed2447b8db6d6c9278a28b11a44cafe41b791205440f"}, "gettext": {:git, "https://github.com/tusooa/gettext.git", "72fb2496b6c5280ed911bdc3756890e7f38a4808", [ref: "72fb2496b6c5280ed911bdc3756890e7f38a4808"]}, "gun": {:hex, :gun, "2.0.0-rc.2", "7c489a32dedccb77b6e82d1f3c5a7dadfbfa004ec14e322cdb5e579c438632d2", [:make, :rebar3], [{:cowlib, "2.11.0", [hex: :cowlib, repo: "hexpm", optional: false]}], "hexpm", "6b9d1eae146410d727140dbf8b404b9631302ecc2066d1d12f22097ad7d254fc"}, - "hackney": {:hex, :hackney, "1.18.1", "f48bf88f521f2a229fc7bae88cf4f85adc9cd9bcf23b5dc8eb6a1788c662c4f6", [:rebar3], [{:certifi, "~>2.9.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~>6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~>1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.3.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~>1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "a4ecdaff44297e9b5894ae499e9a070ea1888c84afdd1fd9b7b2bc384950128e"}, + "hackney": {:hex, :hackney, "1.18.1", "f48bf88f521f2a229fc7bae88cf4f85adc9cd9bcf23b5dc8eb6a1788c662c4f6", [:rebar3], [{:certifi, "~> 2.9.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~> 6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~> 1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~> 1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.3.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "a4ecdaff44297e9b5894ae499e9a070ea1888c84afdd1fd9b7b2bc384950128e"}, "hpax": {:hex, :hpax, "0.1.2", "09a75600d9d8bbd064cdd741f21fc06fc1f4cf3d0fcc335e5aa19be1a7235c84", [:mix], [], "hexpm", "2c87843d5a23f5f16748ebe77969880e29809580efdaccd615cd3bed628a8c13"}, "html_entities": {:hex, :html_entities, "0.5.2", "9e47e70598da7de2a9ff6af8758399251db6dbb7eebe2b013f2bbd2515895c3c", [:mix], [], "hexpm", "c53ba390403485615623b9531e97696f076ed415e8d8058b1dbaa28181f4fdcc"}, "http_signatures": {:hex, :http_signatures, "0.1.1", "ca7ebc1b61542b163644c8c3b1f0e0f41037d35f2395940d3c6c7deceab41fd8", [:mix], [], "hexpm", "cc3b8a007322cc7b624c0c15eec49ee58ac977254ff529a3c482f681465942a3"}, - "httpoison": {:hex, :httpoison, "1.8.1", "df030d96de89dad2e9983f92b0c506a642d4b1f4a819c96ff77d12796189c63e", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "35156a6d678d6d516b9229e208942c405cf21232edd632327ecfaf4fd03e79e0"}, - "idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"}, + "httpoison": {:hex, :httpoison, "1.8.2", "9eb9c63ae289296a544842ef816a85d881d4a31f518a0fec089aaa744beae290", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "2bb350d26972e30c96e2ca74a1aaf8293d61d0742ff17f01e0279fef11599921"}, + "idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"}, "inet_cidr": {:hex, :inet_cidr, "1.0.4", "a05744ab7c221ca8e395c926c3919a821eb512e8f36547c062f62c4ca0cf3d6e", [:mix], [], "hexpm", "64a2d30189704ae41ca7dbdd587f5291db5d1dda1414e0774c29ffc81088c1bc"}, "jason": {:hex, :jason, "1.4.0", "e855647bc964a44e2f67df589ccf49105ae039d4179db7f6271dfd3843dc27e6", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "79a3791085b2a0f743ca04cec0f7be26443738779d09302e01318f97bdb82121"}, "joken": {:hex, :joken, "2.5.0", "09be497d804b8115eb6f07615cef2e60c2a1008fb89dc0aef0d4c4b4609b99aa", [:mix], [{:jose, "~> 1.11.2", [hex: :jose, repo: "hexpm", optional: false]}], "hexpm", "22b25c89617c5ed8ca7b31026340a25ea0f9ca7160f9706b79be9ed81fdf74e7"}, @@ -80,19 +80,20 @@ "oban": {:hex, :oban, "2.12.1", "f604d7e6a8be9fda4a9b0f6cebbd633deba569f85dbff70c4d25d99a6f023177", [:mix], [{:ecto_sql, "~> 3.6", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.16", [hex: :postgrex, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "9b1844c2b74e0d788b73e5144b0c9d5674cb775eae29d88a36f3c3b48d42d058"}, "open_api_spex": {:hex, :open_api_spex, "3.10.0", "94e9521ad525b3fcf6dc77da7c45f87fdac24756d4de588cb0816b413e7c1844", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}, {:poison, "~> 3.1", [hex: :poison, repo: "hexpm", optional: true]}], "hexpm", "2dbb2bde3d2b821f06936e8dfaf3284331186556291946d84eeba3750ac28765"}, "parse_trans": {:hex, :parse_trans, "3.3.1", "16328ab840cc09919bd10dab29e431da3af9e9e7e7e6f0089dd5a2d2820011d8", [:rebar3], [], "hexpm", "07cd9577885f56362d414e8c4c4e6bdf10d43a8767abb92d24cbe8b24c54888b"}, - "phoenix": {:hex, :phoenix, "1.6.11", "29f3c0fd12fa1fc4d4b05e341578e55bc78d96ea83a022587a7e276884d397e4", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 1.0", [hex: :phoenix_view, repo: "hexpm", optional: false]}, {:plug, "~> 1.10", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.2", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "1664e34f80c25ea4918fbadd957f491225ef601c0e00b4e644b1a772864bfbc2"}, + "phoenix": {:hex, :phoenix, "1.6.15", "0a1d96bbc10747fd83525370d691953cdb6f3ccbac61aa01b4acb012474b047d", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 1.0 or ~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: false]}, {:plug, "~> 1.10", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.2", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "d70ab9fbf6b394755ea88b644d34d79d8b146e490973151f248cacd122d20672"}, "phoenix_ecto": {:hex, :phoenix_ecto, "4.4.0", "0672ed4e4808b3fbed494dded89958e22fb882de47a97634c0b13e7b0b5f7720", [:mix], [{:ecto, "~> 3.3", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "09864e558ed31ee00bd48fcc1d4fc58ae9678c9e81649075431e69dbabb43cc1"}, "phoenix_html": {:hex, :phoenix_html, "3.2.0", "1c1219d4b6cb22ac72f12f73dc5fad6c7563104d083f711c3fcd8551a1f4ae11", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "36ec97ba56d25c0136ef1992c37957e4246b649d620958a1f9fa86165f8bc54f"}, "phoenix_live_dashboard": {:hex, :phoenix_live_dashboard, "0.6.5", "1495bb014be12c9a9252eca04b9af54246f6b5c1e4cd1f30210cd00ec540cf8e", [:mix], [{:ecto, "~> 3.6.2 or ~> 3.7", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_mysql_extras, "~> 0.3", [hex: :ecto_mysql_extras, repo: "hexpm", optional: true]}, {:ecto_psql_extras, "~> 0.7", [hex: :ecto_psql_extras, repo: "hexpm", optional: true]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.17.7", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "ef4fa50dd78364409039c99cf6f98ab5209b4c5f8796c17f4db118324f0db852"}, - "phoenix_live_view": {:hex, :phoenix_live_view, "0.17.11", "205f6aa5405648c76f2abcd57716f42fc07d8f21dd8ea7b262dd12b324b50c95", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.1", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7177791944b7f90ed18f5935a6a5f07f760b36f7b3bdfb9d28c57440a3c43f99"}, + "phoenix_live_view": {:hex, :phoenix_live_view, "0.17.12", "74f4c0ad02d7deac2d04f50b52827a5efdc5c6e7fac5cede145f5f0e4183aedc", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.0 or ~> 1.7.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.1", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "af6dd5e0aac16ff43571f527a8e0616d62cb80b10eb87aac82170243e50d99c8"}, "phoenix_pubsub": {:hex, :phoenix_pubsub, "2.1.1", "ba04e489ef03763bf28a17eb2eaddc2c20c6d217e2150a61e3298b0f4c2012b5", [:mix], [], "hexpm", "81367c6d1eea5878ad726be80808eb5a787a23dee699f96e72b1109c57cdd8d9"}, "phoenix_swoosh": {:hex, :phoenix_swoosh, "0.3.4", "615f8f393135de7e0cbb4bd00ba238b1e0cd324b0d90efbaee613c2f02ca5e5c", [:mix], [{:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:swoosh, "~> 1.0", [hex: :swoosh, repo: "hexpm", optional: false]}], "hexpm", "3971221846232021ab5e3c7489fd62ec5bfd6a2e01cae10a317ccf6fb350571c"}, - "phoenix_view": {:hex, :phoenix_view, "1.1.2", "1b82764a065fb41051637872c7bd07ed2fdb6f5c3bd89684d4dca6e10115c95a", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "7ae90ad27b09091266f6adbb61e1d2516a7c3d7062c6789d46a7554ec40f3a56"}, + "phoenix_template": {:hex, :phoenix_template, "1.0.0", "c57bc5044f25f007dc86ab21895688c098a9f846a8dda6bc40e2d0ddc146e38f", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "1b066f99a26fd22064c12b2600a9a6e56700f591bf7b20b418054ea38b4d4357"}, + "phoenix_view": {:hex, :phoenix_view, "2.0.2", "6bd4d2fd595ef80d33b439ede6a19326b78f0f1d8d62b9a318e3d9c1af351098", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}], "hexpm", "a929e7230ea5c7ee0e149ffcf44ce7cf7f4b6d2bfe1752dd7c084cdff152d36f"}, "plug": {:hex, :plug, "1.10.4", "41eba7d1a2d671faaf531fa867645bd5a3dce0957d8e2a3f398ccff7d2ef017f", [:mix], [{:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "ad1e233fe73d2eec56616568d260777b67f53148a999dc2d048f4eb9778fe4a0"}, - "plug_cowboy": {:hex, :plug_cowboy, "2.5.2", "62894ccd601cf9597e2c23911ff12798a8a18d237e9739f58a6b04e4988899fe", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "ea6e87f774c8608d60c8d34022a7d073bd7680a0a013f049fc62bf35efea1044"}, - "plug_crypto": {:hex, :plug_crypto, "1.2.2", "05654514ac717ff3a1843204b424477d9e60c143406aa94daf2274fdd280794d", [:mix], [], "hexpm", "87631c7ad914a5a445f0a3809f99b079113ae4ed4b867348dd9eec288cecb6db"}, + "plug_cowboy": {:hex, :plug_cowboy, "2.6.0", "d1cf12ff96a1ca4f52207c5271a6c351a4733f413803488d75b70ccf44aebec2", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "073cf20b753ce6682ed72905cd62a2d4bd9bad1bf9f7feb02a1b8e525bd94fa6"}, + "plug_crypto": {:hex, :plug_crypto, "1.2.3", "8f77d13aeb32bfd9e654cb68f0af517b371fb34c56c9f2b58fe3df1235c1251a", [:mix], [], "hexpm", "b5672099c6ad5c202c45f5a403f21a3411247f164e4a8fab056e5cd8a290f4a2"}, "plug_static_index_html": {:hex, :plug_static_index_html, "1.0.0", "840123d4d3975585133485ea86af73cb2600afd7f2a976f9f5fd8b3808e636a0", [:mix], [{:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "79fd4fcf34d110605c26560cbae8f23c603ec4158c08298bd4360fdea90bb5cf"}, - "poison": {:hex, :poison, "3.1.0", "d9eb636610e096f86f25d9a46f35a9facac35609a7591b3be3326e99a0484665", [:mix], [], "hexpm", "fec8660eb7733ee4117b85f55799fd3833eb769a6df71ccf8903e8dc5447cfce"}, + "poison": {:hex, :poison, "5.0.0", "d2b54589ab4157bbb82ec2050757779bfed724463a544b6e20d79855a9e43b24", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "11dc6117c501b80c62a7594f941d043982a1bd05a1184280c0d9166eb4d8d3fc"}, "poolboy": {:hex, :poolboy, "1.5.2", "392b007a1693a64540cead79830443abf5762f5d30cf50bc95cb2c1aaafa006b", [:rebar3], [], "hexpm", "dad79704ce5440f3d5a3681c8590b9dc25d1a561e8f5a9c995281012860901e3"}, "postgrex": {:hex, :postgrex, "0.16.5", "fcc4035cc90e23933c5d69a9cd686e329469446ef7abba2cf70f08e2c4b69810", [:mix], [{:connection, "~> 1.1", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "edead639dc6e882618c01d8fc891214c481ab9a3788dfe38dd5e37fd1d5fb2e8"}, "pot": {:hex, :pot, "1.0.2", "13abb849139fdc04ab8154986abbcb63bdee5de6ed2ba7e1713527e33df923dd", [:rebar3], [], "hexpm", "78fe127f5a4f5f919d6ea5a2a671827bd53eb9d37e5b4128c0ad3df99856c2e0"}, @@ -101,21 +102,21 @@ "recon": {:hex, :recon, "2.5.2", "cba53fa8db83ad968c9a652e09c3ed7ddcc4da434f27c3eaa9ca47ffb2b1ff03", [:mix, :rebar3], [], "hexpm", "2c7523c8dee91dff41f6b3d63cba2bd49eb6d2fe5bf1eec0df7f87eb5e230e1c"}, "remote_ip": {:git, "https://git.pleroma.social/pleroma/remote_ip.git", "b647d0deecaa3acb140854fe4bda5b7e1dc6d1c8", [ref: "b647d0deecaa3acb140854fe4bda5b7e1dc6d1c8"]}, "search_parser": {:git, "https://github.com/FloatingGhost/pleroma-contrib-search-parser.git", "08971a81e68686f9ac465cfb6661d51c5e4e1e7f", [ref: "08971a81e68686f9ac465cfb6661d51c5e4e1e7f"]}, - "sleeplocks": {:hex, :sleeplocks, "1.1.1", "3d462a0639a6ef36cc75d6038b7393ae537ab394641beb59830a1b8271faeed3", [:rebar3], [], "hexpm", "84ee37aeff4d0d92b290fff986d6a95ac5eedf9b383fadfd1d88e9b84a1c02e1"}, + "sleeplocks": {:hex, :sleeplocks, "1.1.2", "d45aa1c5513da48c888715e3381211c859af34bee9b8290490e10c90bb6ff0ca", [:rebar3], [], "hexpm", "9fe5d048c5b781d6305c1a3a0f40bb3dfc06f49bf40571f3d2d0c57eaa7f59a5"}, "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.6", "cf344f5692c82d2cd7554f5ec8fd961548d4fd09e7d22f5b62482e5aeaebd4b0", [:make, :mix, :rebar3], [], "hexpm", "bdb0d2471f453c88ff3908e7686f86f9be327d065cc1ec16fa4540197ea04680"}, "statistex": {:hex, :statistex, "1.0.0", "f3dc93f3c0c6c92e5f291704cf62b99b553253d7969e9a5fa713e5481cd858a5", [:mix], [], "hexpm", "ff9d8bee7035028ab4742ff52fc80a2aa35cece833cf5319009b52f1b5a86c27"}, "sweet_xml": {:hex, :sweet_xml, "0.7.3", "debb256781c75ff6a8c5cbf7981146312b66f044a2898f453709a53e5031b45b", [:mix], [], "hexpm", "e110c867a1b3fe74bfc7dd9893aa851f0eed5518d0d7cad76d7baafd30e4f5ba"}, - "swoosh": {:hex, :swoosh, "1.7.3", "febb47c8c3ce76747eb9e3ea25ed694c815f72069127e3bb039b7724082ec670", [:mix], [{:cowboy, "~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:ex_aws, "~> 2.1", [hex: :ex_aws, repo: "hexpm", optional: true]}, {:finch, "~> 0.6", [hex: :finch, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13 or ~> 1.0", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "76abac313f95b6825baa8ceec269d597e8395950c928742fc6451d3456ca256d"}, + "swoosh": {:hex, :swoosh, "1.8.2", "af9a22ab2c0d20b266f61acca737fa11a121902de9466a39e91bacdce012101c", [:mix], [{:cowboy, "~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:ex_aws, "~> 2.1", [hex: :ex_aws, repo: "hexpm", optional: true]}, {:finch, "~> 0.6", [hex: :finch, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13 or ~> 1.0", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "d058ba750eafadb6c09a84a352c14c5d1eeeda6e84945fcc95785b7f3067b7db"}, "syslog": {:hex, :syslog, "1.1.0", "6419a232bea84f07b56dc575225007ffe34d9fdc91abe6f1b2f254fd71d8efc2", [:rebar3], [], "hexpm", "4c6a41373c7e20587be33ef841d3de6f3beba08519809329ecc4d27b15b659e1"}, "table_rex": {:hex, :table_rex, "3.1.1", "0c67164d1714b5e806d5067c1e96ff098ba7ae79413cc075973e17c38a587caa", [:mix], [], "hexpm", "678a23aba4d670419c23c17790f9dcd635a4a89022040df7d5d772cb21012490"}, "telemetry": {:hex, :telemetry, "0.4.3", "a06428a514bdbc63293cd9a6263aad00ddeb66f608163bdec7c8995784080818", [:rebar3], [], "hexpm", "eb72b8365ffda5bed68a620d1da88525e326cb82a75ee61354fc24b844768041"}, "telemetry_metrics": {:hex, :telemetry_metrics, "0.6.1", "315d9163a1d4660aedc3fee73f33f1d355dcc76c5c3ab3d59e76e3edf80eef1f", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7be9e0871c41732c233be71e4be11b96e56177bf15dde64a8ac9ce72ac9834c6"}, "temple": {:git, "https://akkoma.dev/AkkomaGang/temple.git", "066a699ade472d8fa42a9d730b29a61af9bc8b59", [ref: "066a699ade472d8fa42a9d730b29a61af9bc8b59"]}, "tesla": {:hex, :tesla, "1.4.4", "bb89aa0c9745190930366f6a2ac612cdf2d0e4d7fff449861baa7875afd797b2", [:mix], [{:castore, "~> 0.1", [hex: :castore, repo: "hexpm", optional: true]}, {:exjsx, ">= 3.0.0", [hex: :exjsx, repo: "hexpm", optional: true]}, {:finch, "~> 0.3", [hex: :finch, repo: "hexpm", optional: true]}, {:fuse, "~> 2.4", [hex: :fuse, repo: "hexpm", optional: true]}, {:gun, "~> 1.3", [hex: :gun, repo: "hexpm", optional: true]}, {:hackney, "~> 1.6", [hex: :hackney, repo: "hexpm", optional: true]}, {:ibrowse, "4.4.0", [hex: :ibrowse, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: true]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.0", [hex: :mint, repo: "hexpm", optional: true]}, {:poison, ">= 1.0.0", [hex: :poison, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "d5503a49f9dec1b287567ea8712d085947e247cb11b06bc54adb05bfde466457"}, - "timex": {:hex, :timex, "3.7.8", "0e6e8bf7c0aba95f1e13204889b2446e7a5297b1c8e408f15ab58b2c8dc85f81", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.10", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 1.1", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm", "8f3b8edc5faab5205d69e5255a1d64a83b190bab7f16baa78aefcb897cf81435"}, + "timex": {:hex, :timex, "3.7.9", "790cdfc4acfce434e442f98c02ea6d84d0239073bfd668968f82ac63e9a6788d", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.10", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 1.1", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm", "64691582e5bb87130f721fc709acfb70f24405833998fabf35be968984860ce1"}, "trailing_format_plug": {:hex, :trailing_format_plug, "0.0.7", "64b877f912cf7273bed03379936df39894149e35137ac9509117e59866e10e45", [:mix], [{:plug, "> 0.12.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "bd4fde4c15f3e993a999e019d64347489b91b7a9096af68b2bdadd192afa693f"}, "tzdata": {:hex, :tzdata, "1.1.1", "20c8043476dfda8504952d00adac41c6eda23912278add38edc140ae0c5bcc46", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "a69cec8352eafcd2e198dea28a34113b60fdc6cb57eb5ad65c10292a6ba89787"}, - "ueberauth": {:hex, :ueberauth, "0.10.1", "6706b410ee6bd9d67eac983ed9dc7fdc1f06b18677d7b8ba71d5725e07cc8826", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "bb715b562395c4cc26b2d8e637c6bb0eb8c67d50c0ea543c0f78f06b7e8efdb1"}, + "ueberauth": {:hex, :ueberauth, "0.10.3", "4a3bd7ab7b5d93d301d264f0f6858392654ee92171f4437d067d1ae227c051d9", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "1394f36a6c64e97f2038cf95228e7e52b4cb75417962e30418fbe9902b30e6d3"}, "unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"}, "unsafe": {:hex, :unsafe, "1.0.1", "a27e1874f72ee49312e0a9ec2e0b27924214a05e3ddac90e91727bc76f8613d8", [:mix], [], "hexpm", "6c7729a2d214806450d29766abc2afaa7a2cbecf415be64f36a6691afebb50e5"}, "vex": {:hex, :vex, "0.9.0", "613ea5eb3055662e7178b83e25b2df0975f68c3d8bb67c1645f0573e1a78d606", [:mix], [], "hexpm", "c69fff44d5c8aa3f1faee71bba1dcab05dd36364c5a629df8bb11751240c857f"}, diff --git a/test/pleroma/user/import_test.exs b/test/pleroma/user/import_test.exs index a84fce337..2be2ee75b 100644 --- a/test/pleroma/user/import_test.exs +++ b/test/pleroma/user/import_test.exs @@ -3,7 +3,6 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.User.ImportTest do - alias Pleroma.Repo alias Pleroma.Tests.ObanHelpers alias Pleroma.User diff --git a/test/pleroma/user_search_test.exs b/test/pleroma/user_search_test.exs index 8634a2e2b..2af19b6de 100644 --- a/test/pleroma/user_search_test.exs +++ b/test/pleroma/user_search_test.exs @@ -3,7 +3,6 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.UserSearchTest do - alias Pleroma.Repo alias Pleroma.User use Pleroma.DataCase diff --git a/test/pleroma/web/activity_pub/activity_pub_controller_test.exs b/test/pleroma/web/activity_pub/activity_pub_controller_test.exs index 424b87b20..2008ebf04 100644 --- a/test/pleroma/web/activity_pub/activity_pub_controller_test.exs +++ b/test/pleroma/web/activity_pub/activity_pub_controller_test.exs @@ -33,7 +33,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do setup do: clear_config([:instance, :federating], true) describe "/relay" do - setup do: clear_config([:instance, :allow_relay]) + setup do: clear_config([:instance, :allow_relay], true) test "with the relay active, it returns the relay user", %{conn: conn} do res = diff --git a/test/pleroma/web/federator_test.exs b/test/pleroma/web/federator_test.exs index c32972181..c774090d5 100644 --- a/test/pleroma/web/federator_test.exs +++ b/test/pleroma/web/federator_test.exs @@ -22,7 +22,7 @@ defmodule Pleroma.Web.FederatorTest do end setup_all do: clear_config([:instance, :federating], true) - setup do: clear_config([:instance, :allow_relay]) + setup do: clear_config([:instance, :allow_relay], true) setup do: clear_config([:mrf, :policies]) setup do: clear_config([:mrf_keyword]) diff --git a/test/pleroma/web/mastodon_api/controllers/timeline_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/timeline_controller_test.exs index cf60ba93e..f609db7a4 100644 --- a/test/pleroma/web/mastodon_api/controllers/timeline_controller_test.exs +++ b/test/pleroma/web/mastodon_api/controllers/timeline_controller_test.exs @@ -1018,9 +1018,9 @@ test "with `%{local: false, federated: true}`, forbids unauthenticated access to ensure_authenticated_access(base_uri) end - test "with `%{local: true, federated: false}`, forbids unauthenticated access to public timeline" <> - "(but not to local public activities which are delivered as part of federated timeline)", + test "with `%{local: true, federated: false}`, forbids unauthenticated access to public timeline", %{conn: conn, base_uri: base_uri, error_response: error_response} do + # (but not to local public activities which are delivered as part of federated timeline) clear_config([:restrict_unauthenticated, :timelines, :local], true) clear_config([:restrict_unauthenticated, :timelines, :federated], false) diff --git a/test/pleroma/web/media_proxy/invalidation/script_test.exs b/test/pleroma/web/media_proxy/invalidation/script_test.exs index e9629b72b..a57385249 100644 --- a/test/pleroma/web/media_proxy/invalidation/script_test.exs +++ b/test/pleroma/web/media_proxy/invalidation/script_test.exs @@ -10,11 +10,12 @@ defmodule Pleroma.Web.MediaProxy.Invalidation.ScriptTest do test "it logs error when script is not found" do assert capture_log(fn -> - assert Invalidation.Script.purge( - ["http://example.com/media/example.jpg"], - script_path: "./example" - ) == {:error, "%ErlangError{original: :enoent}"} - end) =~ "Error while cache purge: %ErlangError{original: :enoent}" + assert {:error, _} = + Invalidation.Script.purge( + ["http://example.com/media/example.jpg"], + script_path: "./example" + ) + end) =~ "Error while cache purge: %ErlangError{original: :enoent" capture_log(fn -> assert Invalidation.Script.purge( From 075debe5043f9254d2a6aa741eade09b74f38872 Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Sat, 26 Nov 2022 20:46:08 +0000 Subject: [PATCH 067/631] Turn on markup normalisation by default --- lib/pleroma/web/activity_pub/mrf.ex | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/pleroma/web/activity_pub/mrf.ex b/lib/pleroma/web/activity_pub/mrf.ex index 0d4986e68..064ffc527 100644 --- a/lib/pleroma/web/activity_pub/mrf.ex +++ b/lib/pleroma/web/activity_pub/mrf.ex @@ -140,7 +140,8 @@ def get_policies do |> get_policies() |> Enum.concat([ Pleroma.Web.ActivityPub.MRF.HashtagPolicy, - Pleroma.Web.ActivityPub.MRF.InlineQuotePolicy + Pleroma.Web.ActivityPub.MRF.InlineQuotePolicy, + Pleroma.Web.ActivityPub.MRF.NormalizeMarkup ]) |> Enum.uniq() end From c379618b34403010d383588902018d08a9fad92f Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Sat, 26 Nov 2022 20:52:49 +0000 Subject: [PATCH 068/631] Add tests, changelog entry --- CHANGELOG.md | 1 + test/pleroma/web/activity_pub/mrf/normalize_markup_test.exs | 2 ++ test/pleroma/web/activity_pub/mrf_test.exs | 4 ++-- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a5402da1..4b7b7e836 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## Changed - MastoAPI: Accept BooleanLike input on `/api/v1/accounts/:id/follow` (fixes follows with mastodon.py) - Relays from akkoma are now off by default +- NormalizeMarkup MRF is now on by default ## 2022.11 diff --git a/test/pleroma/web/activity_pub/mrf/normalize_markup_test.exs b/test/pleroma/web/activity_pub/mrf/normalize_markup_test.exs index 52a23fdca..133485a86 100644 --- a/test/pleroma/web/activity_pub/mrf/normalize_markup_test.exs +++ b/test/pleroma/web/activity_pub/mrf/normalize_markup_test.exs @@ -15,6 +15,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.NormalizeMarkupTest do this is a link with not allowed "rel" attribute: example.com this is an image:
+
mean
""" @expected """ @@ -25,6 +26,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.NormalizeMarkupTest do this is a link with not allowed "rel" attribute: example.com this is an image:
alert('hacked') + mean """ test "it filter html tags" do diff --git a/test/pleroma/web/activity_pub/mrf_test.exs b/test/pleroma/web/activity_pub/mrf_test.exs index f04c69afb..86ad0ab6b 100644 --- a/test/pleroma/web/activity_pub/mrf_test.exs +++ b/test/pleroma/web/activity_pub/mrf_test.exs @@ -77,7 +77,7 @@ test "it works as expected with noop policy" do clear_config([:mrf, :policies], [Pleroma.Web.ActivityPub.MRF.NoOpPolicy]) expected = %{ - mrf_policies: ["NoOpPolicy", "HashtagPolicy", "InlineQuotePolicy"], + mrf_policies: ["NoOpPolicy", "HashtagPolicy", "InlineQuotePolicy", "NormalizeMarkup"], mrf_hashtag: %{ federated_timeline_removal: [], reject: [], @@ -93,7 +93,7 @@ test "it works as expected with mock policy" do clear_config([:mrf, :policies], [MRFModuleMock]) expected = %{ - mrf_policies: ["MRFModuleMock", "HashtagPolicy", "InlineQuotePolicy"], + mrf_policies: ["MRFModuleMock", "HashtagPolicy", "InlineQuotePolicy", "NormalizeMarkup"], mrf_module_mock: "some config data", mrf_hashtag: %{ federated_timeline_removal: [], From 2fd45e0cb68c60769bf4a6c63ca0213536cfe79e Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Sat, 26 Nov 2022 21:05:04 +0000 Subject: [PATCH 069/631] document normalizemarkup and inlinequote MRFs --- docs/docs/configuration/cheatsheet.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/docs/configuration/cheatsheet.md b/docs/docs/configuration/cheatsheet.md index 94c32f2a8..517fd1993 100644 --- a/docs/docs/configuration/cheatsheet.md +++ b/docs/docs/configuration/cheatsheet.md @@ -120,6 +120,8 @@ To add configuration to your config file, you can copy it from the base config. * `Pleroma.Web.ActivityPub.MRF.FollowBotPolicy`: Automatically follows newly discovered users from the specified bot account. Local accounts, locked accounts, and users with "#nobot" in their bio are respected and excluded from being followed. * `Pleroma.Web.ActivityPub.MRF.AntiFollowbotPolicy`: Drops follow requests from followbots. Users can still allow bots to follow them by first following the bot. * `Pleroma.Web.ActivityPub.MRF.KeywordPolicy`: Rejects or removes from the federated timeline or replaces keywords. (See [`:mrf_keyword`](#mrf_keyword)). + * `Pleroma.Web.ActivityPub.MRF.NormalizeMarkup`: Pass inbound HTML through a scrubber to make sure it doesn't have anything unusual in it. On by default, cannot be turned off. + * `Pleroma.Web.ActivityPub.MRF.InlineQuotePolicy`: Append a link to a post that quotes another post with the link to the quoted post, to ensure that software that does not understand quotes can have full context. On by default, cannot be turned off. * `transparency`: Make the content of your Message Rewrite Facility settings public (via nodeinfo). * `transparency_exclusions`: Exclude specific instance names from MRF transparency. The use of the exclusions feature will be disclosed in nodeinfo as a boolean value. * `transparency_obfuscate_domains`: Show domains with `*` in the middle, to censor them if needed. For example, `ridingho.me` will show as `rid*****.me` From 98a21debf93e1d7cc7bd258efb43496fe501e176 Mon Sep 17 00:00:00 2001 From: floatingghost Date: Sat, 26 Nov 2022 21:06:20 +0000 Subject: [PATCH 070/631] normalise markup by default (#316) why was this _not_ default? honestly i'm surprised pleroma hasn't exploded yet Co-authored-by: FloatingGhost Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma/pulls/316 --- CHANGELOG.md | 1 + docs/docs/configuration/cheatsheet.md | 2 ++ lib/pleroma/web/activity_pub/mrf.ex | 3 ++- test/pleroma/web/activity_pub/mrf/normalize_markup_test.exs | 2 ++ test/pleroma/web/activity_pub/mrf_test.exs | 4 ++-- 5 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a5402da1..4b7b7e836 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## Changed - MastoAPI: Accept BooleanLike input on `/api/v1/accounts/:id/follow` (fixes follows with mastodon.py) - Relays from akkoma are now off by default +- NormalizeMarkup MRF is now on by default ## 2022.11 diff --git a/docs/docs/configuration/cheatsheet.md b/docs/docs/configuration/cheatsheet.md index 94c32f2a8..517fd1993 100644 --- a/docs/docs/configuration/cheatsheet.md +++ b/docs/docs/configuration/cheatsheet.md @@ -120,6 +120,8 @@ To add configuration to your config file, you can copy it from the base config. * `Pleroma.Web.ActivityPub.MRF.FollowBotPolicy`: Automatically follows newly discovered users from the specified bot account. Local accounts, locked accounts, and users with "#nobot" in their bio are respected and excluded from being followed. * `Pleroma.Web.ActivityPub.MRF.AntiFollowbotPolicy`: Drops follow requests from followbots. Users can still allow bots to follow them by first following the bot. * `Pleroma.Web.ActivityPub.MRF.KeywordPolicy`: Rejects or removes from the federated timeline or replaces keywords. (See [`:mrf_keyword`](#mrf_keyword)). + * `Pleroma.Web.ActivityPub.MRF.NormalizeMarkup`: Pass inbound HTML through a scrubber to make sure it doesn't have anything unusual in it. On by default, cannot be turned off. + * `Pleroma.Web.ActivityPub.MRF.InlineQuotePolicy`: Append a link to a post that quotes another post with the link to the quoted post, to ensure that software that does not understand quotes can have full context. On by default, cannot be turned off. * `transparency`: Make the content of your Message Rewrite Facility settings public (via nodeinfo). * `transparency_exclusions`: Exclude specific instance names from MRF transparency. The use of the exclusions feature will be disclosed in nodeinfo as a boolean value. * `transparency_obfuscate_domains`: Show domains with `*` in the middle, to censor them if needed. For example, `ridingho.me` will show as `rid*****.me` diff --git a/lib/pleroma/web/activity_pub/mrf.ex b/lib/pleroma/web/activity_pub/mrf.ex index 0d4986e68..064ffc527 100644 --- a/lib/pleroma/web/activity_pub/mrf.ex +++ b/lib/pleroma/web/activity_pub/mrf.ex @@ -140,7 +140,8 @@ def get_policies do |> get_policies() |> Enum.concat([ Pleroma.Web.ActivityPub.MRF.HashtagPolicy, - Pleroma.Web.ActivityPub.MRF.InlineQuotePolicy + Pleroma.Web.ActivityPub.MRF.InlineQuotePolicy, + Pleroma.Web.ActivityPub.MRF.NormalizeMarkup ]) |> Enum.uniq() end diff --git a/test/pleroma/web/activity_pub/mrf/normalize_markup_test.exs b/test/pleroma/web/activity_pub/mrf/normalize_markup_test.exs index 52a23fdca..133485a86 100644 --- a/test/pleroma/web/activity_pub/mrf/normalize_markup_test.exs +++ b/test/pleroma/web/activity_pub/mrf/normalize_markup_test.exs @@ -15,6 +15,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.NormalizeMarkupTest do this is a link with not allowed "rel" attribute: example.com this is an image:
+
mean
""" @expected """ @@ -25,6 +26,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.NormalizeMarkupTest do this is a link with not allowed "rel" attribute: example.com this is an image:
alert('hacked') + mean """ test "it filter html tags" do diff --git a/test/pleroma/web/activity_pub/mrf_test.exs b/test/pleroma/web/activity_pub/mrf_test.exs index f04c69afb..86ad0ab6b 100644 --- a/test/pleroma/web/activity_pub/mrf_test.exs +++ b/test/pleroma/web/activity_pub/mrf_test.exs @@ -77,7 +77,7 @@ test "it works as expected with noop policy" do clear_config([:mrf, :policies], [Pleroma.Web.ActivityPub.MRF.NoOpPolicy]) expected = %{ - mrf_policies: ["NoOpPolicy", "HashtagPolicy", "InlineQuotePolicy"], + mrf_policies: ["NoOpPolicy", "HashtagPolicy", "InlineQuotePolicy", "NormalizeMarkup"], mrf_hashtag: %{ federated_timeline_removal: [], reject: [], @@ -93,7 +93,7 @@ test "it works as expected with mock policy" do clear_config([:mrf, :policies], [MRFModuleMock]) expected = %{ - mrf_policies: ["MRFModuleMock", "HashtagPolicy", "InlineQuotePolicy"], + mrf_policies: ["MRFModuleMock", "HashtagPolicy", "InlineQuotePolicy", "NormalizeMarkup"], mrf_module_mock: "some config data", mrf_hashtag: %{ federated_timeline_removal: [], From 5bb95256ee2cd0609b6c821820f165a9e6b6c57f Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Sat, 26 Nov 2022 21:15:10 +0000 Subject: [PATCH 071/631] weirdly no, images should not have classes --- priv/scrubbers/default.ex | 1 - test/pleroma/web/activity_pub/mrf/normalize_markup_test.exs | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/priv/scrubbers/default.ex b/priv/scrubbers/default.ex index 950b6c21e..771f27ac1 100644 --- a/priv/scrubbers/default.ex +++ b/priv/scrubbers/default.ex @@ -98,7 +98,6 @@ defmodule Pleroma.HTML.Scrubber.Default do Meta.allow_tag_with_these_attributes(:img, [ "width", "height", - "class", "title", "alt" ]) diff --git a/test/pleroma/web/activity_pub/mrf/normalize_markup_test.exs b/test/pleroma/web/activity_pub/mrf/normalize_markup_test.exs index 133485a86..739d9b49c 100644 --- a/test/pleroma/web/activity_pub/mrf/normalize_markup_test.exs +++ b/test/pleroma/web/activity_pub/mrf/normalize_markup_test.exs @@ -16,6 +16,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.NormalizeMarkupTest do this is an image:
mean
+ """ @expected """ @@ -27,6 +28,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.NormalizeMarkupTest do this is an image:
alert('hacked') mean + """ test "it filter html tags" do From 8557188cedeb0c956016af4ed27f376afc3b07b0 Mon Sep 17 00:00:00 2001 From: Norm Date: Sun, 27 Nov 2022 00:27:48 +0000 Subject: [PATCH 072/631] Delete 'installation/download-mastofe-build.sh' AFAIK, this isn't being used anymore, and it's outdated anyways. --- installation/download-mastofe-build.sh | 48 -------------------------- 1 file changed, 48 deletions(-) delete mode 100755 installation/download-mastofe-build.sh diff --git a/installation/download-mastofe-build.sh b/installation/download-mastofe-build.sh deleted file mode 100755 index ee353c48c..000000000 --- a/installation/download-mastofe-build.sh +++ /dev/null @@ -1,48 +0,0 @@ -#!/bin/sh -# Pleroma: A lightweight social networking server -# Copyright © 2017-2021 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only -project_id="74" -project_branch="rebase/glitch-soc" -static_dir="instance/static" -# For bundling: -# project_branch="pleroma" -# static_dir="priv/static" - -if [ ! -d "${static_dir}" ] -then - echo "Error: ${static_dir} directory is missing, are you sure you are running this script at the root of pleroma’s repository?" - exit 1 -fi - -last_modified="$(curl --fail -s -I 'https://git.pleroma.social/api/v4/projects/'${project_id}'/jobs/artifacts/'${project_branch}'/download?job=build' | grep '^Last-Modified:' | cut -d: -f2-)" - -echo "branch:${project_branch}" -echo "Last-Modified:${last_modified}" - -artifact="mastofe.zip" - -if [ "${last_modified}x" = "x" ] -then - echo "ERROR: Couldn't get the modification date of the latest build archive, maybe it expired, exiting..." - exit 1 -fi - -if [ -e mastofe.timestamp ] && [ "$(cat mastofe.timestamp)" = "${last_modified}" ] -then - echo "MastoFE is up-to-date, exiting..." - exit 0 -fi - -curl --fail -c - "https://git.pleroma.social/api/v4/projects/${project_id}/jobs/artifacts/${project_branch}/download?job=build" -o "${artifact}" || exit - -# TODO: Update the emoji as well -rm -fr "${static_dir}/sw.js" "${static_dir}/packs" || exit -unzip -q "${artifact}" || exit - -cp public/assets/sw.js "${static_dir}/sw.js" || exit -cp -r public/packs "${static_dir}/packs" || exit - -echo "${last_modified}" > mastofe.timestamp -rm -fr public -rm -i "${artifact}" From ee7059c9cf128b5460af7ecf50f5738e2328827d Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Sun, 27 Nov 2022 21:45:41 +0000 Subject: [PATCH 073/631] Spin off imports into n oban jobs --- CHANGELOG.md | 1 + lib/pleroma/user/import.ex | 83 ++++++++----------- lib/pleroma/workers/background_worker.ex | 4 +- test/pleroma/emoji/formatter_test.exs | 2 +- test/pleroma/user/import_test.exs | 33 +++++--- .../user_import_controller_test.exs | 30 +++---- 6 files changed, 74 insertions(+), 79 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b7b7e836..b6eb928c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - MastoAPI: Accept BooleanLike input on `/api/v1/accounts/:id/follow` (fixes follows with mastodon.py) - Relays from akkoma are now off by default - NormalizeMarkup MRF is now on by default +- Follow/Block/Mute imports now spin off into *n* tasks to avoid the oban timeout ## 2022.11 diff --git a/lib/pleroma/user/import.ex b/lib/pleroma/user/import.ex index 60cd18041..95c4ef34e 100644 --- a/lib/pleroma/user/import.ex +++ b/lib/pleroma/user/import.ex @@ -12,47 +12,32 @@ defmodule Pleroma.User.Import do require Logger @spec perform(atom(), User.t(), list()) :: :ok | list() | {:error, any()} - def perform(:mutes_import, %User{} = user, [_ | _] = identifiers) do - Enum.map( - identifiers, - fn identifier -> - with {:ok, %User{} = muted_user} <- User.get_or_fetch(identifier), - {:ok, _} <- User.mute(user, muted_user) do - muted_user - else - error -> handle_error(:mutes_import, identifier, error) - end - end - ) + def perform(:mutes_import, %User{} = user, identifier) do + with {:ok, %User{} = muted_user} <- User.get_or_fetch(identifier), + {:ok, _} <- User.mute(user, muted_user) do + muted_user + else + error -> handle_error(:mutes_import, identifier, error) + end end - def perform(:blocks_import, %User{} = blocker, [_ | _] = identifiers) do - Enum.map( - identifiers, - fn identifier -> - with {:ok, %User{} = blocked} <- User.get_or_fetch(identifier), - {:ok, _block} <- CommonAPI.block(blocker, blocked) do - blocked - else - error -> handle_error(:blocks_import, identifier, error) - end - end - ) + def perform(:blocks_import, %User{} = blocker, identifier) do + with {:ok, %User{} = blocked} <- User.get_or_fetch(identifier), + {:ok, _block} <- CommonAPI.block(blocker, blocked) do + blocked + else + error -> handle_error(:blocks_import, identifier, error) + end end - def perform(:follow_import, %User{} = follower, [_ | _] = identifiers) do - Enum.map( - identifiers, - fn identifier -> - with {:ok, %User{} = followed} <- User.get_or_fetch(identifier), - {:ok, follower, followed} <- User.maybe_direct_follow(follower, followed), - {:ok, _, _, _} <- CommonAPI.follow(follower, followed) do - followed - else - error -> handle_error(:follow_import, identifier, error) - end - end - ) + def perform(:follow_import, %User{} = follower, identifier) do + with {:ok, %User{} = followed} <- User.get_or_fetch(identifier), + {:ok, follower, followed} <- User.maybe_direct_follow(follower, followed), + {:ok, _, _, _} <- CommonAPI.follow(follower, followed) do + followed + else + error -> handle_error(:follow_import, identifier, error) + end end def perform(_, _, _), do: :ok @@ -62,24 +47,24 @@ defp handle_error(op, user_id, error) do error end - def blocks_import(%User{} = blocker, [_ | _] = identifiers) do - BackgroundWorker.enqueue( - "blocks_import", - %{"user_id" => blocker.id, "identifiers" => identifiers} + defp enqueue_many(op, user, identifiers) do + Enum.map( + identifiers, + fn identifier -> + BackgroundWorker.enqueue(op, %{"user_id" => user.id, "identifier" => identifier}) + end ) end + def blocks_import(%User{} = blocker, [_ | _] = identifiers) do + enqueue_many("blocks_import", blocker, identifiers) + end + def follow_import(%User{} = follower, [_ | _] = identifiers) do - BackgroundWorker.enqueue( - "follow_import", - %{"user_id" => follower.id, "identifiers" => identifiers} - ) + enqueue_many("follow_import", follower, identifiers) end def mutes_import(%User{} = user, [_ | _] = identifiers) do - BackgroundWorker.enqueue( - "mutes_import", - %{"user_id" => user.id, "identifiers" => identifiers} - ) + enqueue_many("mutes_import", user, identifiers) end end diff --git a/lib/pleroma/workers/background_worker.ex b/lib/pleroma/workers/background_worker.ex index 4db077232..9bd9899db 100644 --- a/lib/pleroma/workers/background_worker.ex +++ b/lib/pleroma/workers/background_worker.ex @@ -25,10 +25,10 @@ def perform(%Job{args: %{"op" => "force_password_reset", "user_id" => user_id}}) User.perform(:force_password_reset, user) end - def perform(%Job{args: %{"op" => op, "user_id" => user_id, "identifiers" => identifiers}}) + def perform(%Job{args: %{"op" => op, "user_id" => user_id, "identifier" => identifier}}) when op in ["blocks_import", "follow_import", "mutes_import"] do user = User.get_cached_by_id(user_id) - {:ok, User.Import.perform(String.to_atom(op), user, identifiers)} + {:ok, User.Import.perform(String.to_atom(op), user, identifier)} end def perform(%Job{ diff --git a/test/pleroma/emoji/formatter_test.exs b/test/pleroma/emoji/formatter_test.exs index 3942f609f..eafdd5a43 100644 --- a/test/pleroma/emoji/formatter_test.exs +++ b/test/pleroma/emoji/formatter_test.exs @@ -11,7 +11,7 @@ test "it adds cool emoji" do text = "I love :firefox:" expected_result = - "I love \"firefox\"" + "I love \"firefox\"" assert Formatter.emojify(text) == expected_result end diff --git a/test/pleroma/user/import_test.exs b/test/pleroma/user/import_test.exs index 2be2ee75b..19d022529 100644 --- a/test/pleroma/user/import_test.exs +++ b/test/pleroma/user/import_test.exs @@ -25,11 +25,14 @@ test "it imports user followings from list" do user3.nickname ] - {:ok, job} = User.Import.follow_import(user1, identifiers) + [{:ok, job1}, {:ok, job2}] = User.Import.follow_import(user1, identifiers) + + assert {:ok, result} = ObanHelpers.perform(job1) + assert result == refresh_record(user2) + + assert {:ok, result} = ObanHelpers.perform(job2) + assert result == refresh_record(user3) - assert {:ok, result} = ObanHelpers.perform(job) - assert is_list(result) - assert result == [refresh_record(user2), refresh_record(user3)] assert User.following?(user1, user2) assert User.following?(user1, user3) end @@ -44,11 +47,14 @@ test "it imports user blocks from list" do user3.nickname ] - {:ok, job} = User.Import.blocks_import(user1, identifiers) + [{:ok, job1}, {:ok, job2}] = User.Import.blocks_import(user1, identifiers) + + assert {:ok, result} = ObanHelpers.perform(job1) + assert result == user2 + + assert {:ok, result} = ObanHelpers.perform(job2) + assert result == user3 - assert {:ok, result} = ObanHelpers.perform(job) - assert is_list(result) - assert result == [user2, user3] assert User.blocks?(user1, user2) assert User.blocks?(user1, user3) end @@ -63,11 +69,14 @@ test "it imports user mutes from list" do user3.nickname ] - {:ok, job} = User.Import.mutes_import(user1, identifiers) + [{:ok, job1}, {:ok, job2}] = User.Import.mutes_import(user1, identifiers) + + assert {:ok, result} = ObanHelpers.perform(job1) + assert result == user2 + + assert {:ok, result} = ObanHelpers.perform(job2) + assert result == user3 - assert {:ok, result} = ObanHelpers.perform(job) - assert is_list(result) - assert result == [user2, user3] assert User.mutes?(user1, user2) assert User.mutes?(user1, user3) end diff --git a/test/pleroma/web/pleroma_api/controllers/user_import_controller_test.exs b/test/pleroma/web/pleroma_api/controllers/user_import_controller_test.exs index d977bc3a2..f9175058d 100644 --- a/test/pleroma/web/pleroma_api/controllers/user_import_controller_test.exs +++ b/test/pleroma/web/pleroma_api/controllers/user_import_controller_test.exs @@ -47,8 +47,8 @@ test "it imports follow lists from file", %{conn: conn} do |> json_response_and_validate_schema(200) assert [{:ok, job_result}] = ObanHelpers.perform_all() - assert job_result == [refresh_record(user2)] - assert [%Pleroma.User{follower_count: 1}] = job_result + assert job_result == refresh_record(user2) + assert %Pleroma.User{follower_count: 1} = job_result end end @@ -108,8 +108,8 @@ test "it imports follows with different nickname variations", %{conn: conn} do |> post("/api/pleroma/follow_import", %{"list" => identifiers}) |> json_response_and_validate_schema(200) - assert [{:ok, job_result}] = ObanHelpers.perform_all() - assert job_result == Enum.map(users, &refresh_record/1) + job_results = Enum.map(ObanHelpers.perform_all(), fn {:ok, result} -> result end) + assert job_results == Enum.map(users, &refresh_record/1) end end @@ -141,8 +141,8 @@ test "it imports blocks users from file", %{conn: conn} do }) |> json_response_and_validate_schema(200) - assert [{:ok, job_result}] = ObanHelpers.perform_all() - assert job_result == users + job_results = Enum.map(ObanHelpers.perform_all(), fn {:ok, result} -> result end) + assert job_results == users end end @@ -165,8 +165,8 @@ test "it imports blocks with different nickname variations", %{conn: conn} do |> post("/api/pleroma/blocks_import", %{"list" => identifiers}) |> json_response_and_validate_schema(200) - assert [{:ok, job_result}] = ObanHelpers.perform_all() - assert job_result == users + job_results = Enum.map(ObanHelpers.perform_all(), fn {:ok, result} -> result end) + assert job_results == users end end @@ -183,12 +183,12 @@ test "it returns HTTP 200", %{user: user, conn: conn} do |> post("/api/pleroma/mutes_import", %{"list" => "#{user2.ap_id}"}) |> json_response_and_validate_schema(200) - assert [{:ok, job_result}] = ObanHelpers.perform_all() - assert job_result == [user2] + job_results = Enum.map(ObanHelpers.perform_all(), fn {:ok, result} -> result end) + assert job_results == [user2] assert Pleroma.User.mutes?(user, user2) end - test "it imports mutes users from file", %{user: user, conn: conn} do + test "it imports muted users from file", %{user: user, conn: conn} do users = [user2, user3] = insert_list(2, :user) with_mocks([ @@ -202,8 +202,8 @@ test "it imports mutes users from file", %{user: user, conn: conn} do }) |> json_response_and_validate_schema(200) - assert [{:ok, job_result}] = ObanHelpers.perform_all() - assert job_result == users + job_results = Enum.map(ObanHelpers.perform_all(), fn {:ok, result} -> result end) + assert job_results == users assert Enum.all?(users, &Pleroma.User.mutes?(user, &1)) end end @@ -227,8 +227,8 @@ test "it imports mutes with different nickname variations", %{user: user, conn: |> post("/api/pleroma/mutes_import", %{"list" => identifiers}) |> json_response_and_validate_schema(200) - assert [{:ok, job_result}] = ObanHelpers.perform_all() - assert job_result == users + job_results = Enum.map(ObanHelpers.perform_all(), fn {:ok, result} -> result end) + assert job_results == users assert Enum.all?(users, &Pleroma.User.mutes?(user, &1)) end end From 0cfd5b4e89b02688342345755577e58eece3db0f Mon Sep 17 00:00:00 2001 From: floatingghost Date: Mon, 28 Nov 2022 13:34:54 +0000 Subject: [PATCH 074/631] Add ability to set a default post expiry (#321) Co-authored-by: FloatingGhost Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma/pulls/321 --- CHANGELOG.md | 1 + lib/pleroma/user.ex | 5 +++- .../api_spec/operations/account_operation.ex | 11 +++++-- lib/pleroma/web/api_spec/schemas/account.ex | 6 ++++ .../controllers/account_controller.ex | 7 +++++ .../controllers/status_controller.ex | 10 +++++++ .../web/mastodon_api/views/account_view.ex | 3 +- .../web/mastodon_api/views/status_view.ex | 2 +- ...0220905011454_generate_unset_user_keys.exs | 6 ++-- ...0221128103145_add_per_user_post_expiry.exs | 9 ++++++ .../controllers/status_controller_test.exs | 29 +++++++++++++++++++ .../mastodon_api/update_credentials_test.exs | 20 +++++++++++++ .../mastodon_api/views/account_view_test.exs | 9 ++++-- 13 files changed, 107 insertions(+), 11 deletions(-) create mode 100644 priv/repo/migrations/20221128103145_add_per_user_post_expiry.exs diff --git a/CHANGELOG.md b/CHANGELOG.md index b6eb928c6..b49f77428 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## Added - Config: HTTP timeout options, :pool\_timeout and :receive\_timeout - Added statistic gathering about instances which do/don't have signed fetches when they request from us +- Ability to set a default post expiry time, after which the post will be deleted. If used in concert with ActivityExpiration MRF, the expiry which comes _sooner_ will be applied. ## Changed - MastoAPI: Accept BooleanLike input on `/api/v1/accounts/:id/follow` (fixes follows with mastodon.py) diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index eb907a2d8..b0ab9d0cd 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -151,6 +151,7 @@ defmodule Pleroma.User do field(:is_suggested, :boolean, default: false) field(:last_status_at, :naive_datetime) field(:language, :string) + field(:status_ttl_days, :integer, default: nil) embeds_one( :notification_settings, @@ -516,7 +517,8 @@ def update_changeset(struct, params \\ %{}) do :pleroma_settings_store, :is_discoverable, :actor_type, - :disclose_client + :disclose_client, + :status_ttl_days ] ) |> unique_constraint(:nickname) @@ -524,6 +526,7 @@ def update_changeset(struct, params \\ %{}) do |> validate_length(:bio, max: bio_limit) |> validate_length(:name, min: 1, max: name_limit) |> validate_inclusion(:actor_type, ["Person", "Service"]) + |> validate_number(:status_ttl_days, greater_than: 0) |> put_fields() |> put_emoji() |> put_change_if_present(:bio, &{:ok, parse_bio(&1, struct)}) diff --git a/lib/pleroma/web/api_spec/operations/account_operation.ex b/lib/pleroma/web/api_spec/operations/account_operation.ex index 359a73ac0..e20f57fec 100644 --- a/lib/pleroma/web/api_spec/operations/account_operation.ex +++ b/lib/pleroma/web/api_spec/operations/account_operation.ex @@ -700,7 +700,13 @@ defp update_credentials_request do description: "Discovery (listing, indexing) of this account by external services (search bots etc.) is allowed." }, - actor_type: ActorType + actor_type: ActorType, + status_ttl_days: %Schema{ + type: :integer, + nullable: true, + description: + "Number of days after which statuses will be deleted. Set to -1 to disable." + } }, example: %{ bot: false, @@ -720,7 +726,8 @@ defp update_credentials_request do allow_following_move: false, also_known_as: ["https://foo.bar/users/foo"], discoverable: false, - actor_type: "Person" + actor_type: "Person", + status_ttl_days: 30 } } end diff --git a/lib/pleroma/web/api_spec/schemas/account.ex b/lib/pleroma/web/api_spec/schemas/account.ex index 5d3ac9cd0..2693eaceb 100644 --- a/lib/pleroma/web/api_spec/schemas/account.ex +++ b/lib/pleroma/web/api_spec/schemas/account.ex @@ -109,6 +109,12 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Account do } } }, + akkoma: %Schema{ + type: :object, + properties: %{ + note_ttl_days: %Schema{type: :integer} + } + }, source: %Schema{ type: :object, properties: %{ diff --git a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex index 946c8544f..80497a252 100644 --- a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex @@ -175,6 +175,11 @@ def update_credentials(%{assigns: %{user: user}, body_params: params} = conn, _p value -> {:ok, value} end + status_ttl_days_value = fn + -1 -> {:ok, nil} + value -> {:ok, value} + end + user_params = [ :no_rich_text, @@ -215,7 +220,9 @@ def update_credentials(%{assigns: %{user: user}, body_params: params} = conn, _p # Note: param name is indeed :discoverable (not an error) |> Maps.put_if_present(:is_discoverable, params[:discoverable]) |> Maps.put_if_present(:language, Pleroma.Web.Gettext.normalize_locale(params[:language])) + |> Maps.put_if_present(:status_ttl_days, params[:status_ttl_days], status_ttl_days_value) + IO.inspect(user_params) # What happens here: # # We want to update the user through the pipeline, but the ActivityPub diff --git a/lib/pleroma/web/mastodon_api/controllers/status_controller.ex b/lib/pleroma/web/mastodon_api/controllers/status_controller.ex index 31f3b3a8d..338a35052 100644 --- a/lib/pleroma/web/mastodon_api/controllers/status_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/status_controller.ex @@ -171,6 +171,16 @@ def create(%{assigns: %{user: user}, body_params: %{status: _} = params} = conn, Map.put(params, :in_reply_to_status_id, params[:in_reply_to_id]) |> put_application(conn) + expires_in_seconds = + if is_nil(user.status_ttl_days), + do: nil, + else: 60 * 60 * 24 * user.status_ttl_days + + params = + if is_nil(expires_in_seconds), + do: params, + else: Map.put(params, :expires_in, expires_in_seconds) + with {:ok, activity} <- CommonAPI.post(user, params) do try_render(conn, "show.json", activity: activity, diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex index a04ffaaf3..653a50e20 100644 --- a/lib/pleroma/web/mastodon_api/views/account_view.ex +++ b/lib/pleroma/web/mastodon_api/views/account_view.ex @@ -287,7 +287,8 @@ defp do_render("show.json", %{user: user} = opts) do }, last_status_at: user.last_status_at, akkoma: %{ - instance: render("instance.json", %{instance: instance}) + instance: render("instance.json", %{instance: instance}), + status_ttl_days: user.status_ttl_days }, # Pleroma extensions # Note: it's insecure to output :email but fully-qualified nickname may serve as safe stub diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex index 929641b84..cc58f803e 100644 --- a/lib/pleroma/web/mastodon_api/views/status_view.ex +++ b/lib/pleroma/web/mastodon_api/views/status_view.ex @@ -65,7 +65,7 @@ defp get_replied_to_activities(activities) do # This should be removed in a future version of Pleroma. Pleroma-FE currently # depends on this field, as well. defp get_context_id(%{data: %{"context" => context}}) when is_binary(context) do - use Bitwise + import Bitwise :erlang.crc32(context) |> band(bnot(0x8000_0000)) diff --git a/priv/repo/migrations/20220905011454_generate_unset_user_keys.exs b/priv/repo/migrations/20220905011454_generate_unset_user_keys.exs index 43bc7100b..3b04bb4f3 100644 --- a/priv/repo/migrations/20220905011454_generate_unset_user_keys.exs +++ b/priv/repo/migrations/20220905011454_generate_unset_user_keys.exs @@ -14,14 +14,14 @@ def change do from(u in User, where: u.local == true, where: is_nil(u.keys), - select: u + select: u.id ) Repo.stream(query) |> Enum.each(fn user -> with {:ok, pem} <- Keys.generate_rsa_pem() do - Ecto.Changeset.cast(user, %{keys: pem}, [:keys]) - |> Repo.update() + Ecto.Changeset.cast(%User{id: user}, %{keys: pem}, [:keys]) + |> Repo.update(returning: false) end end) end diff --git a/priv/repo/migrations/20221128103145_add_per_user_post_expiry.exs b/priv/repo/migrations/20221128103145_add_per_user_post_expiry.exs new file mode 100644 index 000000000..95c585cf4 --- /dev/null +++ b/priv/repo/migrations/20221128103145_add_per_user_post_expiry.exs @@ -0,0 +1,9 @@ +defmodule Pleroma.Repo.Migrations.AddPerUserPostExpiry do + use Ecto.Migration + + def change do + alter table(:users) do + add(:status_ttl_days, :integer, null: true) + end + end +end diff --git a/test/pleroma/web/mastodon_api/controllers/status_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/status_controller_test.exs index ea6ace69f..cda4c9e03 100644 --- a/test/pleroma/web/mastodon_api/controllers/status_controller_test.exs +++ b/test/pleroma/web/mastodon_api/controllers/status_controller_test.exs @@ -126,6 +126,35 @@ test "posting a status", %{conn: conn} do ) end + test "automatically setting a post expiry if status_ttl_days is set" do + user = insert(:user, status_ttl_days: 1) + %{user: _user, token: _token, conn: conn} = oauth_access(["write:statuses"], user: user) + + conn = + conn + |> put_req_header("content-type", "application/json") + |> post("api/v1/statuses", %{ + "status" => "aa chikichiki banban" + }) + + assert %{"id" => id} = json_response_and_validate_schema(conn, 200) + + activity = Activity.get_by_id_with_object(id) + {:ok, expires_at, _} = DateTime.from_iso8601(activity.data["expires_at"]) + + assert Timex.diff( + expires_at, + DateTime.utc_now(), + :hours + ) == 23 + + assert_enqueued( + worker: Pleroma.Workers.PurgeExpiredActivity, + args: %{activity_id: id}, + scheduled_at: DateTime.add(DateTime.utc_now(), 1 * 60 * 60 * 24) + ) + end + test "it fails to create a status if `expires_in` is less or equal than an hour", %{ conn: conn } do diff --git a/test/pleroma/web/mastodon_api/update_credentials_test.exs b/test/pleroma/web/mastodon_api/update_credentials_test.exs index 606467fa9..435782d0a 100644 --- a/test/pleroma/web/mastodon_api/update_credentials_test.exs +++ b/test/pleroma/web/mastodon_api/update_credentials_test.exs @@ -209,6 +209,26 @@ test "updates the user's name", %{conn: conn} do assert update_activity.data["object"]["name"] == "markorepairs" end + test "updates the user's default post expiry", %{conn: conn} do + conn = patch(conn, "/api/v1/accounts/update_credentials", %{"status_ttl_days" => "1"}) + + assert user_data = json_response_and_validate_schema(conn, 200) + assert user_data["akkoma"]["status_ttl_days"] == 1 + end + + test "resets the user's default post expiry", %{conn: conn} do + conn = patch(conn, "/api/v1/accounts/update_credentials", %{"status_ttl_days" => "-1"}) + + assert user_data = json_response_and_validate_schema(conn, 200) + assert is_nil(user_data["akkoma"]["status_ttl_days"]) + end + + test "does not allow negative integers other than -1 for TTL", %{conn: conn} do + conn = patch(conn, "/api/v1/accounts/update_credentials", %{"status_ttl_days" => "-2"}) + + assert user_data = json_response_and_validate_schema(conn, 403) + end + test "updates the user's AKAs", %{conn: conn} do conn = patch(conn, "/api/v1/accounts/update_credentials", %{ diff --git a/test/pleroma/web/mastodon_api/views/account_view_test.exs b/test/pleroma/web/mastodon_api/views/account_view_test.exs index f4a5f4d50..c9036d67d 100644 --- a/test/pleroma/web/mastodon_api/views/account_view_test.exs +++ b/test/pleroma/web/mastodon_api/views/account_view_test.exs @@ -37,7 +37,8 @@ test "Represent a user account" do inserted_at: ~N[2017-08-15 15:47:06.597036], emoji: %{"karjalanpiirakka" => "/file.png"}, raw_bio: "valid html. a\nb\nc\nd\nf '&<>\"", - also_known_as: ["https://shitposter.zone/users/shp"] + also_known_as: ["https://shitposter.zone/users/shp"], + status_ttl_days: 5 }) insert(:instance, %{host: "example.com", nodeinfo: %{version: "2.1"}}) @@ -61,7 +62,8 @@ test "Represent a user account" do "version" => "2.1" }, favicon: nil - } + }, + status_ttl_days: 5 }, avatar: "http://localhost:4001/images/avi.png", avatar_static: "http://localhost:4001/images/avi.png", @@ -243,7 +245,8 @@ test "Represent a Service(bot) account" do name: "localhost", favicon: "http://localhost:4001/favicon.png", nodeinfo: %{version: "2.0"} - } + }, + status_ttl_days: nil }, pleroma: %{ ap_id: user.ap_id, From b188ac3f21497ecf6be79cd54cf047e3ec46184d Mon Sep 17 00:00:00 2001 From: Norm Date: Tue, 29 Nov 2022 18:31:24 +0000 Subject: [PATCH 075/631] docs: Remove quarantine section Quarantining was deprecated back in 2022.08. Also added that SimplePolicy's `reject` also prevents outbound federation to servers listed there. --- docs/docs/configuration/mrf.md | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/docs/docs/configuration/mrf.md b/docs/docs/configuration/mrf.md index f5727290a..a74cfa90d 100644 --- a/docs/docs/configuration/mrf.md +++ b/docs/docs/configuration/mrf.md @@ -15,18 +15,6 @@ The MRF provides user-configurable policies. The default policy is `NoOpPolicy`, It is possible to use multiple, active MRF policies at the same time. -## Quarantine Instances - -You have the ability to prevent from private / followers-only messages from federating with specific instances. Which means they will only get the public or unlisted messages from your instance. - -If, for example, you're using `MIX_ENV=prod` aka using production mode, you would open your configuration file located in `config/prod.secret.exs` and edit or add the option under your `:instance` config object. Then you would specify the instance within quotes. - -```elixir -config :pleroma, :instance, - [...] - quarantined_instances: ["instance.example", "other.example"] -``` - ## Using `SimplePolicy` `SimplePolicy` is capable of handling most common admin tasks. @@ -41,7 +29,7 @@ config :pleroma, :mrf, Once `SimplePolicy` is enabled, you can configure various groups in the `:mrf_simple` config object. These groups are: -* `reject`: Servers in this group will have their messages rejected. +* `reject`: Servers in this group will have their messages rejected. Also outbound messages will not be sent to these servers. * `accept`: If not empty, only messages from these instances will be accepted (whitelist federation). * `media_nsfw`: Servers in this group will have the #nsfw tag and sensitive setting injected into incoming messages which contain media. * `media_removal`: Servers in this group will have media stripped from incoming messages. From db60640c5b91cd1ce2756565835673fa57afe082 Mon Sep 17 00:00:00 2001 From: floatingghost Date: Thu, 1 Dec 2022 15:00:53 +0000 Subject: [PATCH 076/631] Fixing up deletes a bit (#327) Co-authored-by: FloatingGhost Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma/pulls/327 --- CHANGELOG.md | 6 ++ config/config.exs | 9 ++- .../docs/administration/CLI_tasks/database.md | 20 +++++++ lib/mix/tasks/pleroma/database.ex | 8 +++ lib/pleroma/activity/pruner.ex | 41 ++++++++++++++ lib/pleroma/object/pruner.ex | 31 ++++++++++ lib/pleroma/web/activity_pub/activity_pub.ex | 17 ++++++ lib/pleroma/web/activity_pub/side_effects.ex | 1 - .../controllers/account_controller.ex | 1 - .../workers/cron/database_prune_worker.ex | 32 +++++++++++ lib/pleroma/workers/search_indexing_worker.ex | 5 +- ...331_add_notification_activity_id_index.exs | 7 +++ ...110627_add_bookmarks_activity_id_index.exs | 7 +++ ...727_add_report_notes_activity_id_index.exs | 7 +++ ...ade_to_report_notes_on_activity_delete.exs | 19 +++++++ priv/static/logo-512.png | Bin 0 -> 18688 bytes priv/static/logo.svg | 53 ++++++++++++++++++ test/pleroma/activity/pruner_test.exs | 27 +++++++++ test/pleroma/object/pruner_test.exs | 41 ++++++++++++++ .../web/activity_pub/activity_pub_test.exs | 25 +++++++++ .../mastodon_api/update_credentials_test.exs | 2 +- test/support/factory.ex | 40 ++++++++++++- 22 files changed, 389 insertions(+), 10 deletions(-) create mode 100644 lib/pleroma/activity/pruner.ex create mode 100644 lib/pleroma/object/pruner.ex create mode 100644 lib/pleroma/workers/cron/database_prune_worker.ex create mode 100644 priv/repo/migrations/20221129105331_add_notification_activity_id_index.exs create mode 100644 priv/repo/migrations/20221129110627_add_bookmarks_activity_id_index.exs create mode 100644 priv/repo/migrations/20221129110727_add_report_notes_activity_id_index.exs create mode 100644 priv/repo/migrations/20221129112022_add_cascade_to_report_notes_on_activity_delete.exs create mode 100755 priv/static/logo-512.png create mode 100755 priv/static/logo.svg create mode 100644 test/pleroma/activity/pruner_test.exs create mode 100644 test/pleroma/object/pruner_test.exs diff --git a/CHANGELOG.md b/CHANGELOG.md index b49f77428..136c7e65f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,12 +10,18 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Config: HTTP timeout options, :pool\_timeout and :receive\_timeout - Added statistic gathering about instances which do/don't have signed fetches when they request from us - Ability to set a default post expiry time, after which the post will be deleted. If used in concert with ActivityExpiration MRF, the expiry which comes _sooner_ will be applied. +- Regular task to prune local transient activities +- Task to manually run the transient prune job (pleroma.database prune\_task) ## Changed - MastoAPI: Accept BooleanLike input on `/api/v1/accounts/:id/follow` (fixes follows with mastodon.py) - Relays from akkoma are now off by default - NormalizeMarkup MRF is now on by default - Follow/Block/Mute imports now spin off into *n* tasks to avoid the oban timeout +- Transient activities recieved from remote servers are no longer persisted in the database + +## Upgrade Notes +- If you have an old instance, you will probably want to run `mix pleroma.database prune_task` in the foreground to catch it up with the history of your instance. ## 2022.11 diff --git a/config/config.exs b/config/config.exs index c98a18d39..8e0104400 100644 --- a/config/config.exs +++ b/config/config.exs @@ -569,7 +569,8 @@ new_users_digest: 1, mute_expire: 5, search_indexing: 10, - nodeinfo_fetcher: 1 + nodeinfo_fetcher: 1, + database_prune: 1 ], plugins: [ Oban.Plugins.Pruner, @@ -577,7 +578,8 @@ ], crontab: [ {"0 0 * * 0", Pleroma.Workers.Cron.DigestEmailsWorker}, - {"0 0 * * *", Pleroma.Workers.Cron.NewUsersDigestWorker} + {"0 0 * * *", Pleroma.Workers.Cron.NewUsersDigestWorker}, + {"0 3 * * *", Pleroma.Workers.Cron.PruneDatabaseWorker} ] config :pleroma, :workers, @@ -605,7 +607,8 @@ new_users_digest: :timer.seconds(10), mute_expire: :timer.seconds(5), search_indexing: :timer.seconds(5), - nodeinfo_fetcher: :timer.seconds(10) + nodeinfo_fetcher: :timer.seconds(10), + database_prune: :timer.minutes(10) ] config :pleroma, Pleroma.Formatter, diff --git a/docs/docs/administration/CLI_tasks/database.md b/docs/docs/administration/CLI_tasks/database.md index 8b2ab93e6..73419dc81 100644 --- a/docs/docs/administration/CLI_tasks/database.md +++ b/docs/docs/administration/CLI_tasks/database.md @@ -159,3 +159,23 @@ Change `default_text_search_config` for database and (if necessary) text_search_ ``` See [PostgreSQL documentation](https://www.postgresql.org/docs/current/textsearch-configuration.html) and `docs/configuration/howto_search_cjk.md` for more detail. + +## Pruning old activities + +Over time, transient `Delete` activities and `Tombstone` objects +can accumulate in your database, inflating its size. This is not ideal. +There is a periodic task to prune these transient objects, +but on first run this may take a while on older instances to catch up +to the current day. + +=== "OTP" + + ```sh + ./bin/pleroma_ctl database prune_task + ``` + +=== "From Source" + + ```sh + mix pleroma.database prune_task + ``` \ No newline at end of file diff --git a/lib/mix/tasks/pleroma/database.ex b/lib/mix/tasks/pleroma/database.ex index 99897e83e..0881974ee 100644 --- a/lib/mix/tasks/pleroma/database.ex +++ b/lib/mix/tasks/pleroma/database.ex @@ -110,6 +110,14 @@ def run(["prune_objects" | args]) do end end + def run(["prune_task"]) do + start_pleroma() + + nil + |> Pleroma.Workers.Cron.PruneDatabaseWorker.perform() + |> IO.inspect() + end + def run(["fix_likes_collections"]) do start_pleroma() diff --git a/lib/pleroma/activity/pruner.ex b/lib/pleroma/activity/pruner.ex new file mode 100644 index 000000000..054ee514a --- /dev/null +++ b/lib/pleroma/activity/pruner.ex @@ -0,0 +1,41 @@ +defmodule Pleroma.Activity.Pruner do + @moduledoc """ + Prunes activities from the database. + """ + @cutoff 30 + + alias Pleroma.Activity + alias Pleroma.Repo + import Ecto.Query + + def prune_deletes do + before_time = cutoff() + + from(a in Activity, + where: fragment("?->>'type' = ?", a.data, "Delete") and a.inserted_at < ^before_time + ) + |> Repo.delete_all(timeout: :infinity) + end + + def prune_undos do + before_time = cutoff() + + from(a in Activity, + where: fragment("?->>'type' = ?", a.data, "Undo") and a.inserted_at < ^before_time + ) + |> Repo.delete_all(timeout: :infinity) + end + + def prune_removes do + before_time = cutoff() + + from(a in Activity, + where: fragment("?->>'type' = ?", a.data, "Remove") and a.inserted_at < ^before_time + ) + |> Repo.delete_all(timeout: :infinity) + end + + defp cutoff do + DateTime.utc_now() |> Timex.shift(days: -@cutoff) + end +end diff --git a/lib/pleroma/object/pruner.ex b/lib/pleroma/object/pruner.ex new file mode 100644 index 000000000..991d8b0eb --- /dev/null +++ b/lib/pleroma/object/pruner.ex @@ -0,0 +1,31 @@ +defmodule Pleroma.Object.Pruner do + @moduledoc """ + Prunes objects from the database. + """ + @cutoff 30 + + alias Pleroma.Object + alias Pleroma.Delivery + alias Pleroma.Repo + import Ecto.Query + + def prune_tombstoned_deliveries do + from(d in Delivery) + |> join(:inner, [d], o in Object, on: d.object_id == o.id) + |> where([d, o], fragment("?->>'type' = ?", o.data, "Tombstone")) + |> Repo.delete_all(timeout: :infinity) + end + + def prune_tombstones do + before_time = cutoff() + + from(o in Object, + where: fragment("?->>'type' = ?", o.data, "Tombstone") and o.inserted_at < ^before_time + ) + |> Repo.delete_all(timeout: :infinity, on_delete: :delete_all) + end + + defp cutoff do + DateTime.utc_now() |> Timex.shift(days: -@cutoff) + end +end diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 76b99025b..db5dbc815 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -105,6 +105,23 @@ def persist(%{"type" => type} = object, meta) when type in @object_types do end end + @unpersisted_activity_types ~w[Undo Delete Remove] + @impl true + def persist(%{"type" => type} = object, [local: false] = meta) + when type in @unpersisted_activity_types do + {:ok, object, meta} + {recipients, _, _} = get_recipients(object) + + unpersisted = %Activity{ + data: object, + local: false, + recipients: recipients, + actor: object["actor"] + } + + {:ok, unpersisted, meta} + end + @impl true def persist(object, meta) do with local <- Keyword.fetch!(meta, :local), diff --git a/lib/pleroma/web/activity_pub/side_effects.ex b/lib/pleroma/web/activity_pub/side_effects.ex index 18643662e..34617a218 100644 --- a/lib/pleroma/web/activity_pub/side_effects.ex +++ b/lib/pleroma/web/activity_pub/side_effects.ex @@ -288,7 +288,6 @@ def handle(%{data: %{"type" => "EmojiReact"}} = object, meta) do # Tasks this handles: # - Delete and unpins the create activity - # - Replace object with Tombstone # - Set up notification # - Reduce the user note count # - Reduce the reply count diff --git a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex index 80497a252..a3648c458 100644 --- a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex @@ -222,7 +222,6 @@ def update_credentials(%{assigns: %{user: user}, body_params: params} = conn, _p |> Maps.put_if_present(:language, Pleroma.Web.Gettext.normalize_locale(params[:language])) |> Maps.put_if_present(:status_ttl_days, params[:status_ttl_days], status_ttl_days_value) - IO.inspect(user_params) # What happens here: # # We want to update the user through the pipeline, but the ActivityPub diff --git a/lib/pleroma/workers/cron/database_prune_worker.ex b/lib/pleroma/workers/cron/database_prune_worker.ex new file mode 100644 index 000000000..99ea2e836 --- /dev/null +++ b/lib/pleroma/workers/cron/database_prune_worker.ex @@ -0,0 +1,32 @@ +defmodule Pleroma.Workers.Cron.PruneDatabaseWorker do + @moduledoc """ + The worker to prune old data from the database. + """ + require Logger + use Oban.Worker, queue: "database_prune" + + alias Pleroma.Activity.Pruner, as: ActivityPruner + alias Pleroma.Object.Pruner, as: ObjectPruner + + @impl Oban.Worker + def perform(_job) do + Logger.info("Pruning old data from the database") + + Logger.info("Pruning old deletes") + ActivityPruner.prune_deletes() + + Logger.info("Pruning old undos") + ActivityPruner.prune_undos() + + Logger.info("Pruning old removes") + ActivityPruner.prune_removes() + + Logger.info("Pruning old tombstone delivery entries") + ObjectPruner.prune_tombstoned_deliveries() + + Logger.info("Pruning old tombstones") + ObjectPruner.prune_tombstones() + + :ok + end +end diff --git a/lib/pleroma/workers/search_indexing_worker.ex b/lib/pleroma/workers/search_indexing_worker.ex index 70a8d42d0..518a44c0a 100644 --- a/lib/pleroma/workers/search_indexing_worker.ex +++ b/lib/pleroma/workers/search_indexing_worker.ex @@ -14,11 +14,10 @@ def perform(%Job{args: %{"op" => "add_to_index", "activity" => activity_id}}) do end def perform(%Job{args: %{"op" => "remove_from_index", "object" => object_id}}) do - object = Pleroma.Object.get_by_id(object_id) - search_module = Pleroma.Config.get([Pleroma.Search, :module]) - search_module.remove_from_index(object) + # Fake the object so we can remove it from the index without having to keep it in the DB + search_module.remove_from_index(%Pleroma.Object{id: object_id}) :ok end diff --git a/priv/repo/migrations/20221129105331_add_notification_activity_id_index.exs b/priv/repo/migrations/20221129105331_add_notification_activity_id_index.exs new file mode 100644 index 000000000..b1eb71f72 --- /dev/null +++ b/priv/repo/migrations/20221129105331_add_notification_activity_id_index.exs @@ -0,0 +1,7 @@ +defmodule Pleroma.Repo.Migrations.AddNotificationActivityIdIndex do + use Ecto.Migration + + def change do + create(index(:notifications, [:activity_id])) + end +end diff --git a/priv/repo/migrations/20221129110627_add_bookmarks_activity_id_index.exs b/priv/repo/migrations/20221129110627_add_bookmarks_activity_id_index.exs new file mode 100644 index 000000000..f7b7911f8 --- /dev/null +++ b/priv/repo/migrations/20221129110627_add_bookmarks_activity_id_index.exs @@ -0,0 +1,7 @@ +defmodule Pleroma.Repo.Migrations.AddBookmarksActivityIdIndex do + use Ecto.Migration + + def change do + create(index(:bookmarks, [:activity_id])) + end +end diff --git a/priv/repo/migrations/20221129110727_add_report_notes_activity_id_index.exs b/priv/repo/migrations/20221129110727_add_report_notes_activity_id_index.exs new file mode 100644 index 000000000..dfe74c191 --- /dev/null +++ b/priv/repo/migrations/20221129110727_add_report_notes_activity_id_index.exs @@ -0,0 +1,7 @@ +defmodule Pleroma.Repo.Migrations.AddReportNotesActivityIdIndex do + use Ecto.Migration + + def change do + create(index(:report_notes, [:activity_id])) + end +end diff --git a/priv/repo/migrations/20221129112022_add_cascade_to_report_notes_on_activity_delete.exs b/priv/repo/migrations/20221129112022_add_cascade_to_report_notes_on_activity_delete.exs new file mode 100644 index 000000000..960554a49 --- /dev/null +++ b/priv/repo/migrations/20221129112022_add_cascade_to_report_notes_on_activity_delete.exs @@ -0,0 +1,19 @@ +defmodule Pleroma.Repo.Migrations.AddCascadeToReportNotesOnActivityDelete do + use Ecto.Migration + + def up do + drop(constraint(:report_notes, "report_notes_activity_id_fkey")) + + alter table(:report_notes) do + modify(:activity_id, references(:activities, type: :uuid, on_delete: :delete_all)) + end + end + + def down do + drop(constraint(:report_notes, "report_notes_activity_id_fkey")) + + alter table(:report_notes) do + modify(:activity_id, references(:activities, type: :uuid)) + end + end +end diff --git a/priv/static/logo-512.png b/priv/static/logo-512.png new file mode 100755 index 0000000000000000000000000000000000000000..02d36e7ab91556da3572e2cf2879e61ec3bc79f7 GIT binary patch literal 18688 zcmYIw2{_c>_y2pwHblry%tR=Jl(HMyvdfYrOJykvWnX73B~eI-EK}L{2w8_pltT7> z-?y-u=3z2Lv%^9Dl)>-mzVRAQYsdp=Rcrx;jelX>Cqg*s#r>6M5L}iMxQf zY^=-UX4(u76=rOZ)`juhHe-NKnM!Y$V7ypyXv>!;{i$c!0oxp%_wjc;|LIJK0LLK>|dEAuNaB#{Vo$Zx@i1SyaC zzvbhE2X2(MA2l_42m7_2Byn)e^qS$E}*J--Gd5Tz zyUKSnq%nq2qxafH!G`1|kc?eNf$6wg4*VMEJ^ zuny(JJI>c0uVx6wwZ;YF!>MY)LY+?haqn}L=FHu;vXk{QQ&A3cf0SqQmrFVxu3MP> zoXF;LlZez1)Ryz2M!>vb5V|xk1mox6FdJbLyrEgW)vh>8&LBM+@FLyG^@nK-RX~$y zFz==w?x^PArISY%)?Qgk#M+j?T2>>@5JvR%Qm`CNT@Nh#x&=2i0<4B3%itwYt}u zDNQgJhCG#8wK?mYVOc)X(fNB%PtKSc0TFXODhHJRjgHo5h^;HmtbdPE*%zndcgNjI z>{W+Y1c30k2*;eb4nOBK%x6AMr+s_JV3eRgGJ42s_2Azel;d%J#H5 z!NU3C^j^v(7q>mn#_@+9H(GgsyzCLWds1w1Qa(ODIg&N&9-9;23n~K7&uM*HtM#`* zm3=z}+N2LxQQCaQylYQy{!`cWF*vTVR|Ej`1*?Cv-G5r za?%exP{?92^6-~MgPk>H=l*LOC5VHcV74<6LGDIg1_poo8;IryO)zTJ7 zuXgA8U?dHXemrsA7_XuVVB==f#6q#v&tLC)SA4~^bsH5Ic~|W|Yo5}K66TEZQWRwq z%xncl=D6})B`7E;&x0$Ct#yg~FE}^MqPMkhERI_W(orgR?@k!Tnjb#5cDO$4#uP^fofifC*tg zln3`me4=Z6V$f1hfiWaqLhwM4$R+({aZhg5Eivsif3uQSsXv$C@0^LkUNsz`$OThE@35qWQMTPCgtQRV7`td zZGI2NFbWHot>nPbuxp=XW91bsk_S= zlR%XSG1+B2QPrv{yIuaU@Dwe1JGTf^zBjrz3If7tsC)f7Gf=IXsT%+{=XH!-ubBMI zrwHl&9Gx^`P9^!toNBlr8iJMoC@UNmio3p39n~I3hjgT~65&kW)Y8Kg7)DK26vW>v|17vF_Zt2nqTOk|BgE>+!qW0r zpDH8J7}k|{dSkx?1crS*$%b3OfrR=xwEV|?=I?jGL&KGNlGrTemr?pPBt^+RilU&X zNC38LeR`ko+897|G@aL2Jt_YaG7J-Z+G~b&cRsJEC`fwWCoE8q3c?Mnyv1m0(wxU2 zkLKcfH$Mxh8qTY(g!4jBv%SRu9{-pRJo=MdQFXfCvyS+~=h^C5tYRVnu`q=y3Z`eG zg!eFZbFW25G<_!6<|U<+4S?7)$BYRJYg3Ppph>tXSJyy`XcU)J;xRsIWXit1`XUv` zg^NwRRbTJ3-7+0#Y9wzdKpMTT6qs>rPyqz|3-@*A=bE$-`a>a0T!s>w^Lu#c9sLwDxdPzvTIT;Kae0TSa*Z*4uo-__B(M0L$uf2E#c%pkaJh@Bw@f zq7yH&8ZiI3s_km=qq}YxsQH4P^>&frDsAi)0Kk_9R|5~HH`wcs!t{zLiq|PZ_kr>p zKUeKluLd$7ESwQ$BsVn^RiCN>K>jqiv`RAd@!1Ooi{IipulK>W)US{7kP;Prg9-|_ zt#`0gHRm8Z2iR_PWu2a4JJn94C<~VT09yNV+`y{b!LlEiv~xv$3x8v6Lu=2;`I)8&d8A16Nree? zWb?hzgoK0@iuO$aJ(K_BzI@AQQmr#oIkgT=vWDB%rlzEdl3?@T^-suu-^ZmrK6#A7(Y(+Z7XVQ1 zxq^7bd>7|k%*=;~nVRLK?#>qDa;J`u5R1GJNM$Vg2M7JMA3t9GSX?amp_REsmS2h; z611R(S}irte$4OWQ_65!7`J|PKd{K3H90xQB2(z^&cC>qx!y#=lQuD}CUXx7PAeNL zE32))%f<10t_{ha_(>&EsEmS?KLa(EiV4QiI-&MX&aGiQ#xrs^x=s7N&3KVlyISrj zZ>ySV2&z-MpPz{+^`#2G*&(&C`_;iArI`Q!6UpD>S5-15bI{y>->Hn&izh;{00z~~ zH3WCsqlfu>MhE>A!bE8Q@Nb^h3iM8&xEn7jeTzVkTA7&q`t#EmW}+!0$U5tAusddQ zrDoZ64Fk;B5CL6lk56~=q&@PdJ@}ZiXgRmuaMB{fYv@|_K_Ukr5#ok5_;63v=O)^a zkGHq$jd4-5BzP%X@YF+3+C$oTqlUhoNw$jYfPUt+GR4|F&IYr+`s8h>t;yZb^lLzTqj}x9M{J{nJfQ@^DrLJkI{=a{1E)dSG{9G7-VFS-V2;9r- z_8%@SNcGgQFn>1=8d1eeK70E8)zu-2X<9di(h;oXrTQ~7REv%Y8+!?k#k#-TP0_Tc z4-0m$UOobt%hFp*vAQ~jB0L&&Cf-*|Iqp^v>P#)q#z$`lmtFwaUwtrVMcaSiX7l94 zFfsOXkmKK{6nY+LCb}Dv&Fb3~7i6uFU7@F?OqkFFtJWX7`W;1vaKfC^DBWCl8Yf~3 z_1{U~IxwPze6vleD=UMEXi+10fkb2{G$1m&AU|q6T@J#a`6Kf8$$evM;4=<%XSz=VZd5%a;9y+X^bvA*51{4=npnh*|*Y-dVEk#|Zz z-+w3I0!{GxUyxsxG~g?@!sD2!A>ysS6G(m0;3>K4x?qN*2~l$mh2OB7XsvVb z9<=7!vhZv8i5pZDj}9fFn4_isvV&2d*?~`d=hvxNxb30s(#~xfM*(D{t{BI~}T?4NCj# z&fQ3QZ0s4R^E*Q~5^D$;fxC$QxOu)%?dq0xmt>4`NS-CsL?HbwUON~V4xHf zO!4JD;FFJ$}J}=>SGYinL`Kps4!DfgT9DS}p|=gtJv6?kOy_3axlI`o1hoAnb_`^pszBV}npc%c?y%ul3(?rKB0i$*N#FBUsKvRrvI@&J?Y{K4gwDh7xe zsxehVkCbtiDK=vAJ1Eb+mhCq_Hs8gYLnsKr;N;VIkgZCGAN8A0d%8Q-yn7xCu{csg zuv1lq34%{A^HY&LfE$TeU2#jy`kNH7!wGBDf>@-Vw3&#~^_iYth*=x6sV3$ZtVlG5 zerG;0eF2Vr1);F1HCS5K>Yv+AlXPAuvH3K&yv9kp2N1-f1^VW!Ds+&b-=7{a%5ZU` zKWbX7irCnNun=lNNe}*rQL}4TG*dgHZOZv@=OV z9P4==oUGL76TQ9W(|*FSQq<6y*pF;BimrAJGQVM|-sbV?c(092uxL&G5h^PTZV9;2t(ZTjW>fo54 zb2V&h9vqPNegQ9|BWSUlTkb0IIa%WV$={822$8ts zMcR3~bYAp0d25@Fp`@2n8B4Hf&N#zi_AjAE_jdZQo%U)tHJrzP+b8Ci8l3>@{dkat z0OnqiME$l&BK1VUhODemkUwZ24nb>WSOp7Q2od`yud)dwPtn#~?f_cL&O)|FLDO5i zIcdrP;!gT$xoKy$1ZzXsY=aeza{Ev-@_AO zo+l6)$%32lFRy1NprP*|)ENQ?8OvkF8B41(tJK{-W`zL-6O?*F@WJA!PaB8%HmAW+bNUtTO?q{mFEZ{eJwBxys&P z2km6nhw2JErCvW>>HKh%lCCVfCmiOFz(UY{)5p)I6U_-L+$fgo@d^gU90(Qs-TFXE zaqZ02n8NHUko={OtbZLQ}}sVD|BX5^{IL^E0E+mKq0x%1RI2<#m(yArK_LvCVQU z?NCQh>tw`m8~jzvX(7zPa`|r4wH40BTa`XOhooq;pvD?t9yB|!No@#Q$9)QM$M99- zKu=j?DrqmNBxt7qG=G1k{vm-ArveH2&GupjDNZ)umGBw=lG2D+N1Nz%K>)7uA&m?# zX}Ul0B1Vtu3BUd%2Mq1NoU5?;%qW&d_ntjHSRN5;1$fHNHZwvL4(&g;rdr(Uqsy%y zb48)AsxemF9j$qk0-L>8+^vdz9Ck(>g2tKXsjsa6(9T|>QUMG;ECjnGvJWRK8(Z@ESUWPI5Wh2yN=o8q4O zrwq0jS6+vzyHJ~<8h6#$;{sNsHA7*5w0_(=tzO4fPpx(Jix!#&?tF*}qBhpJlqT5J zYflyW41$K-fdSEHHZf86+*Kd1TdQeOf#;V`0O;!`6Ipe06f{F0S<@rn&;zG;HgI;v z*J%DLp1nK$!$H($>SuZ_*EdA_Or&4jOJ4ZGZu2+pJ5dP2_NAs#ftG4Jtj0{w%$(GE z@7)5Q_w_H}uf|0To1)hXXJ)%jwf_sP=%o}ZMqw`^BR zmC&j%_Sj(^_X~rNast@Y?#_V0GtUp1^t;w?Ri*DA2JDH9B@_`Trv8T~h6H5YdsZl^ zocVpg$pI>{m-7Hb*=^%TcKH=fnE^>hi0yAr{o*q#17 zKJRpUqd18ezroL0Su}I=;qt?T%Hj)k@9rD(V4I^j+Xkb!hLQVVceQM(!F+S38zbSF z;b*@Hl3>O1Pq(${V)N%MbC&{rNl`Hn6yn|kOVX-psU-O=Ob`-cZ5}QM8B|u{o1zqG zuZoxYZrn>&bW2a;_<9(j`nDHO%&Pwm`5*6*`b{FGhP(uv^F(oGSL}2~%HRQ1cR{+d z${#c_izIxhRQZ>&BCa=oJN^_`B3)NbB~$QH^rhJow#1Jlx1PI~3T_tNi$tsIN!6RV ze%;Ut=+{Qryw^@eV;`a8SRk}Z@=3D#XQfz`3WxPvp_o`b{B~B;&GO?t#UuM!T|c4` zMv(iQ%nmWvnm-@*b_vFM>U}E8uBf`?(FSvveMwqIi1aqF=`iBQ#(ED z0w+({mL?&>?QjbtgZL#l&o_q@tLen%#3nc}g~Uzy{eZk#nD_y5uxwQmh@IJ&W~8u@ z+2jv9!+q{6vo>=g{%FUtdaH6c?DkR8YbL`hcJ<^W-jmc&=WE+Aig8fhmBlY)gMW6k zS`4(o(6lD%2auRlLZESG0ANj*K?q$Y#D$1c-1YIqZP}? z7&!IyKAj8g2>jc8dce(e|G5rWHCs?#6J>sH+(~sjHk+({EyNB6Cdk*!eH3A$8OGm- zcd%+14!m!V?qxiE@Hys}sL{cUT?|Y!t1yE+jl3n+8tSvI3S4tl=mS&vuSK55H&`PC zgrni7#YmZ79^l7B6rwptMyVtIs+viDT@b82#4-LldGwe>%gg-gTG0VzGYMaok@g`B z-#-gzLl^{U<_u4$vRj6Xond18c(DU`D?RQ}t#a47rq)M~Rz9 z&2?ZlqNp_$@9CgAj^Sf#PgynP`VXzggaYy7*B$GS58o+1LgNw{$=fZegR;~V|J904 z&PG4FV6P6nBpXB6>_WRmOZakN2slu{e&k-X%fOuxkHt8X0s!15^QDRBV3wkrc;QdV zs5{6zmVT4Xm;tpW@e;ClY`J}f#M3qTC|Z}ZJ&l-NbBmOQzKqBKjm%`>kP#LLH!-*7 z-tfWWY>ZHSVoBIE90fLpS1fUSJZ=Nr5+@{SQWbWuXV?pLEi zYjJDqwA-|_O9H$fZ`4X}f|Ce=l@B;?og?qRZruCjb`-QmAhmHRjE<7Bv}U7Tr4R_|*EK5}p5s??gZ zieRI5PegM9y%|TWY$a2;jBaH}&*rt5T6f)jJjECazmd0-lENE6e|PFf{!%z-uyt@AVyEsQv&=j;eqqBP`6vR~Z`tJ9iOy28FH`*HR7T6tk zFKzHI@#kOb5~aISY(5>Rg$2L&@$^v|9H-lp>tjgGd&#nTBKo-%;}&fUHe*FEKivpB zY%`3q*|6ua3EIghtFL|E)Ucj=q80c9!^iVO;AGFGYNtW|qO0%i)Ng8ySMw!taVV5B zHMDMR`X$Sdi7e)lqAToRMR?zp@nU1*{Auc=&Pi(6_6ctFygrMFQsV&c`TT(M=g%jc zHxJO&^uzg3W(_huQ}l}zuI~=-_~vDhS(CYwx!)*Kz0@MH6crsar&H0d8KJ;l_Q#eY zf)>nsvi?&9J&Q;0a|6wXgP` zzjfnvqRHc~JcW~GQBZ52@{=|}K50e}lfPN+xp{Rxxxb{heckDicm+(z-G|lF(&~XK zqy3srjxE$20#2#cHBG;0a*+5F7U$Pi39-ck0dMqox4uQ=1mDD#U5|L=KhH7Pw~?OM zk9hEcAFj>Fjk<75Z-$^y2zM}`n~e2dhejb@ud-$Mnx(|oLjlv7h5M>vdJXQ+_0w)9C3X0b zD*As<1G0BC*>PI@1fx0)>~A(wTpw_thc7F^$*d_U@MHe1(yL=<>NnaO@$TBE{cx#) z#EVa-9-at1!&y(*I9S)DrHkcR8V1l>KH9_mJ`(Y5scMC!Ml@eSgT_@$J_tNL0 z(R&xd58Dr7?*vRc&>;6C)HhJ2R6_qXl^DK&Imlk##OBZ8_c0k~q9o-k!wLp@njpJc zSy#)yBFYS)!?Q>$@}|KB`t9ASw%vxxj|72z+ZLptZSCBapZMAqpCY}T+@~7aQxM9f zofW_A864XDn<3YdVo@SD-VayBvobas|D=Wi9(vpKi$i_D?~FBuWDeti1N;`LgwC-q zG^i%=E{1+%c%Z0W(&OzG(P6Ni2*ji>MNQ|F{@JhAldb_li!zLEF% zna_xKgwlGWvma^ILOmb@ORomOAelKc5}tKiG=~-={!dtW<8>+@qq+I3cqxoST;;Ri z;C*7&_#4}!O^egU;nF8|p7{0fQNR)Nf3*PLfPn8L%_#?&L~!vFY#LFaGg>7u^i3jvqz^uS3{q_L@nfi(j9GElRNFUTL^GN*=$xvMQCR zjSSWWnIv7;@UW9DtO>ey?(MOBU2{$)82(ok8aP@?Krp$;nB&l4IXUM_>ugeBfHcCr zx(RKx5;WLXsdGxWX=w=I8!m|e1Zari-?FWRb0nJodJh}ni{eR{eZr$mRAZa2Yr^X1 zB5Eqc$Ii54alXtPz8goqZwRO;{JN(nE=Bq;m9VuH^_ABi| zNpcg$Zryfwv_pD7Ms4-E9Oc`eN_8#WoL`y0<;(gdTYjzZyeeCs3ChZ^%STu+N9&Lz z?^v-$QU{Y_7$Gf=L}ki>d-JRL*3j&*P>c}Glq>5WO{HGpAe{uB2MH$&gpQb*)K2Yd zso6u)oI)MH1eQYEUf*Bu=$ucId?WN)Njj(F#tj)Y=ij?;nGJ5EJiL_+9Sz@$$BXDo zeH(=oNl`0>NyY^G?OwMEsv5Q7~Xb|tRwYR)&<{oD+$@% z^*JY~agm?Ds<1*WkOuMJTY3eHE)?WYx#1dl$KvwWHxvGDF14v6`_0iW;g@FD&Mgcz zBnw_+za3%9KEV4$wBr=?eD?J2{q2d8m*m?GTRcp~X9vtm!V8KibtQYamx!F3{9n{r zCx5(PCFL6jF7Z9~VzH%@fd(QU@>8^)TDFPKW|q$_`#phuSrH#kh`?+_gxdIC^KaHY z(ynZ&{FlfbeC&!L`Sd7|x2Al&kiSk)iqBwNCX?4c381X=UD2!Oa0e`b?79A6byslz z1(ap|U@_C|zE*zK+P5UKim^ecq`X@-XaC1aZdXEpw!eR6X*0{g$A-A2u&%Q&cp*lP zq4JV$uQlNonf*fzS$c)l=optL7o4L$IIGOKUIe6yHCg6~4^uHC?8?RKRyn^QI~EdI z^CNOl-SsFEPvdfK%>=FRz##f`8fTTn>Ite}P-ELdwrc(o<>mYK-U;1rgs3E`KB7Q< zQRFDChCN+u2#4AO4t)r+0+0~7I7~K_U;dOyJ~8v7n{#GFxYYP}=I=EvxqAQf)1}Mj z%l5X_2jx0Q059`@M7Xt_Es2*%1$nY{Nm4;Tgu4pgahxLNI!;u zB42Nrd7}~^#itJ(Zu3jOudIi)Lb$>0*BGauHEyQjZ~FNL?w#e3(2c>6rLNHx&Snp9 z#b2&B{ycoH)m8b4n+FQJc<8iS5+>~g)0%db&18*Z{ZdE+#;WA_Lrx}fS-mTVK0T@8 z&DYX6T=lQBR+TPtmGb5ak55#Dw?f?c|3SCgyCcSTq-Avn*lXo&!EWStlp6`sJ{|Eb z`>R9mvbT^u^e4;9%lS;;5k~VnCLZ>o3{qP>VT>3f!m4=w*<6~-J2%0aGp-cs;HY`F zD|eWK4dQN1Ch-LgWen|McApKAlz3M!aiuvDg}CDw5c#^^B?|U)PJKTw==HAsVT)@6 zxgOf}Xl zFsxs62C0CJvT#t6b4evAbTP(GKZvAki(J0nlUNRhh_>oGWrW7{-E!rKV`|2q5PDcO z4K|igV5rOK(nb+&jnZZp?Y`GpDy7`m7Cp@F$OsyfPd?%kMco2!J@?f?_Q!<+4X<3b zI2Vl>oh8H{Ggl&&bo53!#%qS40CrjK;gZ(;>K$82fgv0-_RPSZ>O?8cVXJJ_!{KB$!LEkKwW&edRkTP= zz!&aC+I%L~o=skvXO+(v6G`2k$BdD3Z8OH@JI44}E~kviNoez#?P}(n5Tvp@x!RE} z8Gdl$B!Xf^^T$R1TD4M<7}f^st{mF*mMe&84xAiQAo;~FJZH*==8dCa!B67{mxpMc>L zF~yNp%6%;?J^v~Q&}z`4X5Nu76NSRst@DXxekG|KKxyB^vWcIz6y_Ie-)ZZw(k?CY8Ibd1G zX%4UQD&_(M9J~H$zr&K^_70y!YZ2l@r6Tn zXAPa}yxuk9+T$;{hlMKq4Wp{)!{64psW2>20d}YF0k$Umyrh=t9!b?V+i-8s2Y9zJ zZ`{($5ImhM>V;@wYbcdu{Zbwm-lvE*DgJ7DbW^EP&T_TeDDUt{gThGZ0I)7!XsD?{;OWZ&G$C7X&{rKtHE=9%-LAHG)Gc zB~zDpo;X);tIo79CTB^YJ|Ch9v6ujvv>Yi&WAj-=;=&nqj0IOBAIl3imanqZVyMo? zNouy3j_vFRdf!uCwN+TVNz$hEk9(mZ7Mnk0W$%)4&G#;9{+^1Zi($N>A@~B}giuy3m{x!l`lKTg+)(E<5->!k-I*$-6zQRK-B-<=E)A(c$m?torde zeXW&yHB=s}Yh`K)^H&S%@7VRT{WzN*eNgGi66MAfIZzwCf1rIE?9%^ChH+zNN-Vr~ zm|x&z5@4)*Pwsa+!ZmL*lii1ghN_MJ8T3X;#?pR>2U)5B~K(6@+k*9f~4 zsL*fi?78Z}_TNe^RyYM}e(Q>_O#L|1LpbJFk%EmZA2yg-TwNzW96G&gvX%dRo|;w* ztcTe!J%3 zhFkiqfH$v1G3=Wqx;@CxL7nYtVIn-e8$=`DWD!) zPPCqM^G3;_3tWhj-%%ksdFa(PeK{X5`kgGNyf-FiXmwLo_R8MXG zffhp;s^?wNP8lsQ3obU_uUW3F)HSc*ha}FPfZ$lWyT4PkeK30$593*>*%QU~T@JpD zZZ5Tv87sxo2<>YD(`mcGzDc)hW3q;o$0K0bRylzk-YlHB3$K#fnb99?&Xh7jTrjk|`x-tb zn6!oe_1^7Kg1D=K#Zq=O^J)-hm~(^YRsyqq+NK2+*?oC$?WR&eiGhDW6>m~|2PYW! zGc^m;ej`2A(G)W8owi?;&1nP4+ciwdv-NrxWM#l%j^Z*>4v`ZuuxM-Bz8J?XGG*7Aoy{H^ZOtESxyGRLVkvdt(ac6`xR^xc(WgX z))_(DD@C)*865t@#i0LK#R;d*z zDPBtlKKJq0yAUw27SR?XCN8}ftL#7yrMkw)n43&au|3kXIcOQ)B=S)N2Hy0mx;H3O z1($wiw7UX_Ud54_1rm4$2ouV)LfUIw140qKSV~onZDLXe#+1BqSOczE(pu zL#sT&7(tc&Cu3}z-0R=N9H4SgGw^a7BUi1~BoJT_zm%e@C~f>PqUW&kJDO?Jt%|HY z7PPEfJNtRbcVL)5KFOB2_ab7>cW~oYzks>g!2RHA~lC&36TlqPN&T<{=m5BP*5k^ zB4(v=_^wese@(CvbI{DkPsu=*TPnRN^hHyk*MCc zHd?>;2ax@)Hzp@(WvF3T8(sqpq&8_VyEo`Gj_G`$-DO$p5-}_$Jvs>uc<}YGoU_&84e-y z;L5VCF>ikwxs=jf`zT>9R%@VWoZq$^`{vE5!7N89pLL(l9Gws-e{!#(WckdA|I9Sm z|7Aa7I9U*)lD;tf0o_sS*kQ-qoqG=-nGm4&P)Flug0{VGuRfp(d_;ComVt(FbdD5D zZiNC1tM$6`fg5JiqNnN$2fsfM8&%EoN9LW&i|=}KD%ou3Oyt}C*W1@~b!5;wV$H8( z?zw<{;v86KYaLa+KcCU|btTsE$?5v@fdNt~k3C?+Z-+)5?)9ecHrfgb%bbxhcNP<2 zzPgNbmRf?oy<$Yi$q!SwkJ5_$sOTo6l{%y5w-tM}uJ(;L6$)@)E7~wh{xWZuulhY? zyjcd_$_lY(+*rg^ZQ498*VFA%Im%Y$89wg?cuX%kLw|R8F`%HzW52>*YyQ>)o2b3adMzN_uOZz2wW_|k?3Gb9o1%_A(SR(~xPis{y{Hn} zfP@;0oQaE{=wv=Q9@gro3(HP>Cv3ji*u}pxGi%#_QhVLO(m>KEUI82Xi5AxiY<5*` z7&g&9Wx6{&K=<%a<55JB7c#I;nEtc(yT78-7yA}MB&yGomwrDqv6Sg0pLMRZwW^NN z5OdBd%oMbZNmRhH2vHep)VNYihZop=XbJ6ey~C5VzEApQS24@Uzb>^>9b6j0mE6SV z|1@|D5)sDHmJBHgs&H-?`U%J7=DCwA&M|=)XWUoAtoc=ZjLg^Cw& zJ%RO(2VueH2jTxJH)i#yq}+Ug9xV)ESVdfvQ>Ek@E`2GoY<0l=b@7>L>htZ`dli+MQ7;c435~noYVIw@cUtJ{Uwhl{X=Y2 zF00PFY5F4Csab?|Kcz5#yua!{7d+wQ%C|rKoiB$9Y^~*W1hZ-fhIfBhc9#fPh{kQw zS95O7I(LEOZTR3dJyHhJG!fif2^f9<^Jr>qsAkHbsVx?kHmJaIdQAfFKO*TJCeZ)2 zOgFDMH~z`2Y;e({llld!!r5W*Km_y>{gxzakvCOe6Ir|Zw$H-l zAc3Rz)cNwnu#YIq&u&+`m^ylR#wa8*;RjjroJ zxV=Qzhsl;>JM@$EMl}XXnZn#^= z7?m)~CM@In#;kRpzi+L+{BX1Eh0fy9qZ>r`^rMKs1_Bf(dw1$4HdQDXTRAYA;7F@8DQVTjvvDtcVGL^)NR4uxH*Ka}IP1vC({(^)})4{nCD}XV^2>AY+uUps27(;#u7{S|d__X0q4Ce+zvt z?k_0v*)41+{9XK0N{U}Q#HO_8JsJ8I4&l%yf)PJVR<%aNzjY`USe!rl5U`T)vWy|m zn8|Cv2`O@#=`^7GH0~g~*(Kt8_ksu9IL=HL_r}N;NJ$Ajb3=H;!x1p_-GLh(e?ZAJ z@oCj?UeMO}qTV*?a(~_>Zl`^=fw5cGSBaju2!(Wm)V4J9O)>-g!|=WN$k!SQvO*L3y7ZxyuM0$3Od zH98qm;m&^!?xL)>xG!(38&$J)H2BMQ#y4o69H3`8MGcXsA=J#PAxDeJ?JDG&oYh8Q zcfkekM-^er=cpO!;Sgm|RU$2o@DD;fB=mnIMH#Xzw=dnDl9+<=(m0uTQ z*86(saI7{XJyhwz+5&JNQv|oWJrp=|1zL*o0A#w3#&1cZmQ|e4_LE7#^E)~Q`p6;; zE*c&=&_VU}R_cLKb5HvhM?IFb^Xn`)_Aa-p0doq6U|9SLKXe&lxI$1MwbJ;_ntY)3 zKUp2Z1EvH6Q8(-C6JHEqgvOb}XWVcy_~)TY?+RaAr~=gnnh81_{sftH%?9Vpzcb9O zzi%j2PTc3h8l}P;y&m^Pl~vTszTL~M{X*xTgNixnht?8#a?ZFk4z?asuf=J!9lpK0 z9oLSQ0&}WT7obv(WoxHK$N@bLn3p}aUV&P<%%d%C-;kd}8;Re+p#bO}KkO+G!p6zF z@r}g2+!*Pp_tEM=Gqb<_4HeGC(Q(1Bm?e|*aBQ4!_imQ+iBZJi!swdsF4V!RjAQeM zQJ;okjdb;XlLb%7d+CBbsiLh_UigNg*ev`5LQyN2gP08YntH?lSu(;ozuptO~FR*e(~sg$38O z^U_B|wF^~ZSRyW7R9e-Spu1>CO#f1UY?^rM7p2wP zB?|03SbVu3I{MOogK^E(fpqK@ty<`)2YTXArE}~tu$=vIs`sLF@=6ledA~;*bfO<= z8kub$NSO2=2*~?Q+$?)~{z6`<)B4L=fes0kFA8NmM-C{yPEe;9OE1k;55c3MMpZ@j z*4!qKZ(prfRKbq4vwg#@yFiP_nu9)vPZ2GgJExRRBXWpeW)?WRd>tKkYe zx$%$nidy<$?T0dfBjuDdcoR4p)klF1wWCW@#CHs|zkiF{f35z?aFQ4wWNFJDCNI-j z=QzE&Q>`S;p>$c(D)B`to06}P>>C)O*aQ@RBU8UTxM}8&tHe7TMl>NG);Iyw5#QP< zO|_=lTb~HAI|HrLIXS31y-)24Qjt~EV~{@azZoEpjL}XfwyeQ*ng))#rJs{N)>u|( zKMcvRu#|GApQQacR03i-4FClNVP9V<9Q+!XY}-F;58E`cz&6@dUupzGgKD(V+~k8d z@H=cE5lMbPq(aERAxx(bUybG5{UuCnx7a&=7}(?m9SaP0{)z|oDK+y4Gut!+KlTzXw))b7=$#JMlvmwL9Z}<8c)Ou9mj)!$;Qph<2UCho!9jxz zt!4*I6WqK#l19_f7?A?xEh9t^45i`tEjZY(r0n0to_v`=-22GQ(h08rvZ%zcU)&)y z%YfVyjy?K>U}-k%>A@#;^Q^Nr@Lh{3bV7rx@RMa{$LUBjFC@_Wz+u?IYXV|BCBs-f z2xOa}(}kDM?sba%uNx`Q&9plsyZTtieuq#Qgnf>HuoJbt5Ag-!aIE_$4tLPw%nj2o z&ydvYDNEIaVIIoCguTcE26mg%!JNj_i=XNrf-96M$Nw(?bO7!#F&NDE;JGXz^rhqL zIo75xE|IrDjdCX=kVAh7hb#g!H?*2!B7!RV|D^rv@w_8nfUZfVLN;jIGFBXilgT)DqyTaIOb@OyC!Qw`ey#c+ISv23SnnzcP?< zAT@+-SbIX-Ce0A2OvT~}{!H&l#LuzduSifqn&3{-!ufMKM-EXCbPkvYS~ZDo;Vr&U zuIaB3tj-g48394{xfd|vjD7~Ka7Yu}4_r_;|0#8OVFv|4FJAyHXb<$0d>UoY58N9~ zkJrlot1M$ta5;&I20prHG_b~dQ0YJS=4`z4xA1Vj1+f19GGSx4z!Ew>7*_Q` z^xbSL`EgZ3D}2EP++jg29Akmmqjb^!M|aw5FzNCz4ogV+;y-#23o$IvJ546z69yP? z5O4w~8r(qxqLJ!;le9M7-{2!nPPElg`U%hwDHjIAm;OQjv%MQj)5$!(2LrJN87%iL z<|7_{<^(S7q#=w^1q9bll+cL4hlP>}IWrxkzWX&Sz+;ddRD?9;uBSFYo^(A_`0?XU zMGH?vaB5TcF2tXZzK1-_*vGcz9F{y&(diQ`9;6JME(7pPo6k z51-3tvTytr0yWx#PM^qgQ2gC#k(D%@%=rFe2BzKq=>KivTJM9$Z~mKA7{|}W)ZNUW zpaS&&aenU&D-X`^s<#akh+qNbjodrF?IMf~z~YE=9WRg3uOg$I>ofkzaP=H|CIBp# zXA0{EZxFGOp3_y|HP>Vtu$WJk@s18iF>wYqQ4LNov2ZunZ_rUZp(jx{y%p5l46v1x zG5N(Qk*?Vg%lPlM1Ak9}B7+9Q@>b2=j9;!hE}oxIRK~i&?ybI>5vV(2@#n*fv$B6O zzX->8uVDWm`ttt-pmG`Dt{=l6?G2lAoNXKIco^H1^7p1v=+ zz*O>I5!l;`NMZc4=+aSMo_`M?yk6Y||E%|NV#e!IlCwjuWz*|APb#HUU?(R{b_N_#wS`=3GY0o$Wf2pq?#z zWW%E!Q=4ngJYuQpWnqkbTprp16mFc%x**dtaqj-K$3=YK3%LB3wRJ`MZ22RcOd)^STN^WXPQ6+G1F}xs zF%VdvTzOz}{ek;~>DhA@CpFFmRzD$bFKp(W*r(2c0%wVhU zIi|^GJHOpz4RD)jngX!cQn&TJzUfcJk(Y0_oAH=4*ISk#U5dH{QQvLN9Q#bMEEW|1=KEE3B+PJc027yZg+v=V9sB&I7m2SsZQ5 zYCmAwW`D31XoVv4f{8%odplOBHg+zv?>4b{dFI#35AOGX#!Ah(wtboCvw7#kB0mF% z5|904-7-xf!DY$shr5C6j*OOvw{zOJf4`u3*#|hRq{JaHP3p&VLvP207Lq$f71y6l z{9rD@*szR)iOulC;uXL#kY2y=JsU(hjebb?F*qdq2`mV@Ys|Z+cI&bIlN#lBaYQN< zXs0JPFgO&S6I;5qO+>ZSg7G|8*Y5?Z8`zm-{T9n-WdJL55#S))Rg@>vB7VINn>V+bb9k5fTQ%F;{!3J508V#2+i0ZX%_KX|asEv^rnQ>47Bw}r&JyDZ za&Jxq*0VjERW8U}(DlmesyEg2Xqou=^Ui?D2@Q?%i-8k|8tQ*{ocZaxxL9GsNy#tQ zjb0o!@w?{tx5rFmMcM)0P2ojqY{!6Gq6*ISBzI00ypWi=;IL*?%xj)sOTII<1E=#X z>R){p5ZPg$|9b8jDf@g6VE44c;x=2T!G(wevCOk=_BTj;XymbUtZDwd{>trLhIY-i zo73C+fmLkFl+WHr=jNJNZSIXRVp$cm|L)JHi|?&_E-t{p0&Kr0&bifCbw0K_UH;w+k0T$Z~1_EH!NqMRbQGB`M#D8{&x`_uj TF}&OabR2`HtDnm{r-UW|@S{GM literal 0 HcmV?d00001 diff --git a/priv/static/logo.svg b/priv/static/logo.svg new file mode 100755 index 000000000..fbd5c6ec1 --- /dev/null +++ b/priv/static/logo.svg @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/pleroma/activity/pruner_test.exs b/test/pleroma/activity/pruner_test.exs new file mode 100644 index 000000000..312d4f5e4 --- /dev/null +++ b/test/pleroma/activity/pruner_test.exs @@ -0,0 +1,27 @@ +defmodule Pleroma.Activity.PrunerTest do + use Pleroma.DataCase, async: true + + alias Pleroma.Activity + alias Pleroma.Activity.Pruner + + import Pleroma.Factory + + describe "prune_deletes" do + test "it prunes old delete objects" do + user = insert(:user) + + new_delete = insert(:delete_activity, type: "Delete", user: user) + + old_delete = + insert(:delete_activity, + type: "Delete", + user: user, + inserted_at: DateTime.utc_now() |> DateTime.add(-31 * 24, :hour) + ) + + Pruner.prune_deletes() + assert Activity.get_by_id(new_delete.id) + refute Activity.get_by_id(old_delete.id) + end + end +end diff --git a/test/pleroma/object/pruner_test.exs b/test/pleroma/object/pruner_test.exs new file mode 100644 index 000000000..73c574b4b --- /dev/null +++ b/test/pleroma/object/pruner_test.exs @@ -0,0 +1,41 @@ +defmodule Pleroma.Object.PrunerTest do + use Pleroma.DataCase, async: true + + alias Pleroma.Delivery + alias Pleroma.Object + alias Pleroma.Object.Pruner + + import Pleroma.Factory + + describe "prune_deletes" do + test "it prunes old delete objects" do + new_tombstone = insert(:tombstone) + + old_tombstone = + insert(:tombstone, + inserted_at: DateTime.utc_now() |> DateTime.add(-31 * 24, :hour) + ) + + Pruner.prune_tombstones() + assert Object.get_by_id(new_tombstone.id) + refute Object.get_by_id(old_tombstone.id) + end + end + + describe "prune_tombstoned_deliveries" do + test "it prunes old tombstone deliveries" do + user = insert(:user) + + tombstone = insert(:tombstone) + tombstoned = insert(:delivery, object: tombstone, user: user) + + note = insert(:note) + not_tombstoned = insert(:delivery, object: note, user: user) + + Pruner.prune_tombstoned_deliveries() + + refute Repo.get(Delivery, tombstoned.id) + assert Repo.get(Delivery, not_tombstoned.id) + end + end +end diff --git a/test/pleroma/web/activity_pub/activity_pub_test.exs b/test/pleroma/web/activity_pub/activity_pub_test.exs index c7b3334f3..8d39b1076 100644 --- a/test/pleroma/web/activity_pub/activity_pub_test.exs +++ b/test/pleroma/web/activity_pub/activity_pub_test.exs @@ -8,6 +8,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do alias Pleroma.Activity alias Pleroma.Builders.ActivityBuilder + alias Pleroma.Web.ActivityPub.Builder alias Pleroma.Config alias Pleroma.Notification alias Pleroma.Object @@ -2613,4 +2614,28 @@ test "allow fetching of accounts with an empty string name field" do {:ok, user} = ActivityPub.make_user_from_ap_id("https://princess.cat/users/mewmew") assert user.name == " " end + + describe "persist/1" do + test "should not persist remote delete activities" do + poster = insert(:user, local: false) + {:ok, post} = CommonAPI.post(poster, %{status: "hhhhhh"}) + + {:ok, delete_data, meta} = Builder.delete(poster, post) + local_opts = Keyword.put(meta, :local, false) + {:ok, act, _meta} = ActivityPub.persist(delete_data, local_opts) + refute act.inserted_at + end + + test "should not persist remote undo activities" do + poster = insert(:user, local: false) + liker = insert(:user, local: false) + {:ok, post} = CommonAPI.post(poster, %{status: "hhhhhh"}) + {:ok, like} = CommonAPI.favorite(liker, post.id) + + {:ok, undo_data, meta} = Builder.undo(liker, like) + local_opts = Keyword.put(meta, :local, false) + {:ok, act, _meta} = ActivityPub.persist(undo_data, local_opts) + refute act.inserted_at + end + end end diff --git a/test/pleroma/web/mastodon_api/update_credentials_test.exs b/test/pleroma/web/mastodon_api/update_credentials_test.exs index 435782d0a..a5403f360 100644 --- a/test/pleroma/web/mastodon_api/update_credentials_test.exs +++ b/test/pleroma/web/mastodon_api/update_credentials_test.exs @@ -226,7 +226,7 @@ test "resets the user's default post expiry", %{conn: conn} do test "does not allow negative integers other than -1 for TTL", %{conn: conn} do conn = patch(conn, "/api/v1/accounts/update_credentials", %{"status_ttl_days" => "-2"}) - assert user_data = json_response_and_validate_schema(conn, 403) + assert json_response_and_validate_schema(conn, 403) end test "updates the user's AKAs", %{conn: conn} do diff --git a/test/support/factory.ex b/test/support/factory.ex index bd9d7fe42..904987aaf 100644 --- a/test/support/factory.ex +++ b/test/support/factory.ex @@ -233,7 +233,7 @@ def article_factory do %Pleroma.Object{data: Map.merge(data, %{"type" => "Article"})} end - def tombstone_factory do + def tombstone_factory(attrs) do data = %{ "type" => "Tombstone", "id" => Pleroma.Web.ActivityPub.Utils.generate_object_id(), @@ -244,6 +244,7 @@ def tombstone_factory do %Pleroma.Object{ data: data } + |> merge_attributes(attrs) end def question_factory(attrs \\ %{}) do @@ -520,6 +521,33 @@ def question_activity_factory(attrs \\ %{}) do |> Map.merge(attrs) end + def delete_activity_factory(attrs \\ %{}) do + user = attrs[:user] || insert(:user) + note_activity = attrs[:note_activity] || insert(:note_activity, user: user) + + data_attrs = attrs[:data_attrs] || %{} + attrs = Map.drop(attrs, [:user, :data_attrs]) + + data = + %{ + "id" => Pleroma.Web.ActivityPub.Utils.generate_activity_id(), + "type" => "Delete", + "actor" => note_activity.data["actor"], + "to" => note_activity.data["to"], + "object" => note_activity.data["id"], + "published" => DateTime.utc_now() |> DateTime.to_iso8601(), + "context" => note_activity.data["context"] + } + |> Map.merge(data_attrs) + + %Pleroma.Activity{ + data: data, + actor: data["actor"], + recipients: data["to"] + } + |> Map.merge(attrs) + end + def oauth_app_factory do %Pleroma.Web.OAuth.App{ client_name: sequence(:client_name, &"Some client #{&1}"), @@ -676,4 +704,14 @@ def frontend_setting_profile_factory(params \\ %{}) do } |> Map.merge(params) end + + def delivery_factory(params \\ %{}) do + object = Map.get(params, :object, build(:note)) + user = Map.get(params, :user, build(:user)) + + %Pleroma.Delivery{ + object: object, + user: user + } + end end From bbf2e3f4451d41fa3c1a52000bab97b583ebd957 Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Mon, 28 Nov 2022 22:44:20 +0000 Subject: [PATCH 077/631] Add PWA info --- config/config.exs | 8 +------- lib/pleroma/web/views/manifest_view.ex | 14 ++++++++++++-- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/config/config.exs b/config/config.exs index 8e0104400..90dcc057f 100644 --- a/config/config.exs +++ b/config/config.exs @@ -313,7 +313,7 @@ loginMethod: "password", logo: "/static/logo.svg", logoMargin: ".1em", - logoMask: true, + logoMask: false, noAttachmentLinks: false, nsfwCensorImage: "", postContentType: "text/plain", @@ -346,12 +346,6 @@ default_mascot: :pleroma_fox_tan config :pleroma, :manifest, - icons: [ - %{ - src: "/static/logo.svg", - type: "image/svg+xml" - } - ], theme_color: "#282c37", background_color: "#191b22" diff --git a/lib/pleroma/web/views/manifest_view.ex b/lib/pleroma/web/views/manifest_view.ex index cc78ea347..1d78b594e 100644 --- a/lib/pleroma/web/views/manifest_view.ex +++ b/lib/pleroma/web/views/manifest_view.ex @@ -11,7 +11,17 @@ def render("manifest.json", _params) do %{ name: Config.get([:instance, :name]), description: Config.get([:instance, :description]), - icons: Config.get([:manifest, :icons]), + icons: [ + %{ + src: "/static/logo.svg", + type: "image/svg+xml" + }, + %{ + src: "/static/logo-512.png", + sizes: "512x512", + type: "image/png" + } + ], theme_color: Config.get([:manifest, :theme_color]), background_color: Config.get([:manifest, :background_color]), display: "standalone", @@ -21,7 +31,7 @@ def render("manifest.json", _params) do "social" ], serviceworker: %{ - src: "/sw.js" + src: "/sw-pleroma.js" } } end From b33e548e8d5df8cd00657b8f6966cfe31390a2bf Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Fri, 2 Dec 2022 11:09:55 +0000 Subject: [PATCH 078/631] still use mask --- config/config.exs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/config/config.exs b/config/config.exs index 90dcc057f..8e0104400 100644 --- a/config/config.exs +++ b/config/config.exs @@ -313,7 +313,7 @@ loginMethod: "password", logo: "/static/logo.svg", logoMargin: ".1em", - logoMask: false, + logoMask: true, noAttachmentLinks: false, nsfwCensorImage: "", postContentType: "text/plain", @@ -346,6 +346,12 @@ default_mascot: :pleroma_fox_tan config :pleroma, :manifest, + icons: [ + %{ + src: "/static/logo.svg", + type: "image/svg+xml" + } + ], theme_color: "#282c37", background_color: "#191b22" From 8d6cc6cb65d8216d9f8d75e274e23fc78b75639c Mon Sep 17 00:00:00 2001 From: floatingghost Date: Fri, 2 Dec 2022 11:12:37 +0000 Subject: [PATCH 079/631] Resolve follow activity from accept/reject without ID (#328) Co-authored-by: FloatingGhost Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma/pulls/328 --- lib/pleroma/activity.ex | 8 ++ lib/pleroma/web/activity_pub/activity_pub.ex | 2 +- .../accept_reject_validator.ex | 32 +++++++- .../transmogrifier/reject_handling_test.exs | 76 +++++++++++++++++++ test/support/factory.ex | 7 +- 5 files changed, 120 insertions(+), 5 deletions(-) diff --git a/lib/pleroma/activity.ex b/lib/pleroma/activity.ex index b01a838d8..c5b514742 100644 --- a/lib/pleroma/activity.ex +++ b/lib/pleroma/activity.ex @@ -367,6 +367,14 @@ def following_requests_for_actor(%User{ap_id: ap_id}) do |> Repo.all() end + def follow_activity(%User{ap_id: ap_id}, %User{ap_id: followed_ap_id}) do + Queries.by_type("Follow") + |> where([a], a.actor == ^ap_id) + |> where([a], fragment("?->>'object' = ?", a.data, ^followed_ap_id)) + |> where([a], fragment("?->>'state'", a.data) in ["pending", "accept"]) + |> Repo.one() + end + def restrict_deactivated_users(query) do query |> join( diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index db5dbc815..a4f1c7041 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -105,7 +105,7 @@ def persist(%{"type" => type} = object, meta) when type in @object_types do end end - @unpersisted_activity_types ~w[Undo Delete Remove] + @unpersisted_activity_types ~w[Undo Delete Remove Accept Reject] @impl true def persist(%{"type" => type} = object, [local: false] = meta) when type in @unpersisted_activity_types do diff --git a/lib/pleroma/web/activity_pub/object_validators/accept_reject_validator.ex b/lib/pleroma/web/activity_pub/object_validators/accept_reject_validator.ex index 7c3c8d0fa..847d0be62 100644 --- a/lib/pleroma/web/activity_pub/object_validators/accept_reject_validator.ex +++ b/lib/pleroma/web/activity_pub/object_validators/accept_reject_validator.ex @@ -6,6 +6,8 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AcceptRejectValidator do use Ecto.Schema alias Pleroma.Activity + alias Pleroma.Object + alias Pleroma.User import Ecto.Changeset import Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations @@ -29,7 +31,7 @@ def cast_data(data) do defp validate_data(cng) do cng - |> validate_required([:id, :type, :actor, :to, :cc, :object]) + |> validate_required([:type, :actor, :to, :cc, :object]) |> validate_inclusion(:type, ["Accept", "Reject"]) |> validate_actor_presence() |> validate_object_presence(allowed_types: ["Follow"]) @@ -38,6 +40,7 @@ defp validate_data(cng) do def cast_and_validate(data) do data + |> maybe_fetch_object() |> cast_data |> validate_data end @@ -53,4 +56,31 @@ def validate_accept_reject_rights(cng) do |> add_error(:actor, "can't accept or reject the given activity") end end + + defp maybe_fetch_object(%{"object" => %{} = object} = activity) do + # If we don't have an ID, we may have to fetch the object + if Map.has_key?(object, "id") do + # Do nothing + activity + else + Map.put(activity, "object", fetch_transient_object(object)) + end + end + + defp maybe_fetch_object(activity), do: activity + + defp fetch_transient_object( + %{"actor" => actor, "object" => target, "type" => "Follow"} = object + ) do + with %User{} = actor <- User.get_cached_by_ap_id(actor), + %User{local: true} = target <- User.get_cached_by_ap_id(target), + %Activity{} = activity <- Activity.follow_activity(actor, target) do + activity.data + else + _e -> + object + end + end + + defp fetch_transient_object(_), do: {:error, "not a supported transient object"} end diff --git a/test/pleroma/web/activity_pub/transmogrifier/reject_handling_test.exs b/test/pleroma/web/activity_pub/transmogrifier/reject_handling_test.exs index 355e664d4..52a61f310 100644 --- a/test/pleroma/web/activity_pub/transmogrifier/reject_handling_test.exs +++ b/test/pleroma/web/activity_pub/transmogrifier/reject_handling_test.exs @@ -8,6 +8,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.RejectHandlingTest do alias Pleroma.Activity alias Pleroma.User alias Pleroma.Web.ActivityPub.Transmogrifier + alias Pleroma.Web.ActivityPub.Utils alias Pleroma.Web.CommonAPI import Pleroma.Factory @@ -53,6 +54,81 @@ test "it works for incoming rejects which are referenced by IRI only" do assert User.following?(follower, followed) == false end + describe "when accept/reject references a transient activity" do + test "it handles accept activities that do not contain an ID key" do + follower = insert(:user) + followed = insert(:user, is_locked: true) + + pending_follow = + insert(:follow_activity, follower: follower, followed: followed, state: "pending") + + refute User.following?(follower, followed) + + without_id = Map.delete(pending_follow.data, "id") + + reject_data = + File.read!("test/fixtures/mastodon-reject-activity.json") + |> Jason.decode!() + |> Map.put("actor", followed.ap_id) + |> Map.delete("id") + |> Map.put("object", without_id) + + {:ok, %Activity{data: _}} = Transmogrifier.handle_incoming(reject_data) + + follower = User.get_cached_by_id(follower.id) + + refute User.following?(follower, followed) + assert Utils.fetch_latest_follow(follower, followed).data["state"] == "reject" + end + + test "it handles reject activities that do not contain an ID key" do + follower = insert(:user) + followed = insert(:user) + {:ok, follower, followed} = User.follow(follower, followed) + {:ok, _, _, follow_activity} = CommonAPI.follow(follower, followed) + assert Utils.fetch_latest_follow(follower, followed).data["state"] == "accept" + assert User.following?(follower, followed) + + without_id = Map.delete(follow_activity.data, "id") + + reject_data = + File.read!("test/fixtures/mastodon-reject-activity.json") + |> Jason.decode!() + |> Map.put("actor", followed.ap_id) + |> Map.delete("id") + |> Map.put("object", without_id) + + {:ok, %Activity{data: _}} = Transmogrifier.handle_incoming(reject_data) + + follower = User.get_cached_by_id(follower.id) + + refute User.following?(follower, followed) + assert Utils.fetch_latest_follow(follower, followed).data["state"] == "reject" + end + + test "it does not accept follows that are not in pending or accepted" do + follower = insert(:user) + followed = insert(:user, is_locked: true) + + rejected_follow = + insert(:follow_activity, follower: follower, followed: followed, state: "reject") + + refute User.following?(follower, followed) + + without_id = Map.delete(rejected_follow.data, "id") + + accept_data = + File.read!("test/fixtures/mastodon-accept-activity.json") + |> Jason.decode!() + |> Map.put("actor", followed.ap_id) + |> Map.put("object", without_id) + + {:error, _} = Transmogrifier.handle_incoming(accept_data) + + refute User.following?(follower, followed) + end + end + test "it rejects activities without a valid ID" do user = insert(:user) diff --git a/test/support/factory.ex b/test/support/factory.ex index 904987aaf..3e426c565 100644 --- a/test/support/factory.ex +++ b/test/support/factory.ex @@ -452,15 +452,16 @@ def like_activity_factory(attrs \\ %{}) do } end - def follow_activity_factory do - follower = insert(:user) - followed = insert(:user) + def follow_activity_factory(attrs \\ %{}) do + follower = attrs[:follower] || insert(:user) + followed = attrs[:followed] || insert(:user) data = %{ "id" => Pleroma.Web.ActivityPub.Utils.generate_activity_id(), "actor" => follower.ap_id, "type" => "Follow", "object" => followed.ap_id, + "state" => attrs[:state] || "pending", "published_at" => DateTime.utc_now() |> DateTime.to_iso8601() } From 1409f91d504f9fd891044b30c8c3082565f0a8d5 Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Fri, 2 Dec 2022 12:00:56 +0000 Subject: [PATCH 080/631] Add maskable to logo --- lib/pleroma/web/views/manifest_view.ex | 3 ++- priv/static/logo.svg | 35 ++++++-------------------- 2 files changed, 10 insertions(+), 28 deletions(-) diff --git a/lib/pleroma/web/views/manifest_view.ex b/lib/pleroma/web/views/manifest_view.ex index 1d78b594e..d8c736cef 100644 --- a/lib/pleroma/web/views/manifest_view.ex +++ b/lib/pleroma/web/views/manifest_view.ex @@ -19,7 +19,8 @@ def render("manifest.json", _params) do %{ src: "/static/logo-512.png", sizes: "512x512", - type: "image/png" + type: "image/png", + purpose: "maskable" } ], theme_color: Config.get([:manifest, :theme_color]), diff --git a/priv/static/logo.svg b/priv/static/logo.svg index fbd5c6ec1..01ddbadb8 100755 --- a/priv/static/logo.svg +++ b/priv/static/logo.svg @@ -1,53 +1,34 @@ - + - - - - - - - + - + - + - - + \ No newline at end of file From 04b5c711be549e3976c75f16109350224c3ffc2f Mon Sep 17 00:00:00 2001 From: r3g_5z Date: Sat, 3 Dec 2022 14:17:54 -0500 Subject: [PATCH 081/631] Manually define PATH for Arch Linux users in systemd unit Signed-off-by: r3g_5z --- installation/akkoma.service | 3 +++ 1 file changed, 3 insertions(+) diff --git a/installation/akkoma.service b/installation/akkoma.service index caddf7c4b..2b2e3d568 100644 --- a/installation/akkoma.service +++ b/installation/akkoma.service @@ -7,6 +7,9 @@ ExecReload=/bin/kill $MAINPID KillMode=process Restart=on-failure +; Uncomment this if you're on Arch Linux +; Evironment="PATH=/usr/local/sbin:/usr/local/bin:/usr/bin:/usr/bin/site_perl:/usr/bin/vendor_perl:/usr/bin/core_perl" + ; Name of the user that runs the Akkoma service. User=akkoma ; Declares that Akkoma runs in production mode. From 6b882a2c0b98bdf94bc557f86c2d16460d90f44e Mon Sep 17 00:00:00 2001 From: floatingghost Date: Sat, 3 Dec 2022 23:17:43 +0000 Subject: [PATCH 082/631] Purge Rejected Follow requests in daily task (#334) Co-authored-by: FloatingGhost Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma/pulls/334 --- config/description.exs | 21 ++++++----- docs/docs/configuration/cheatsheet.md | 22 +++++++++--- lib/mix/tasks/pleroma/instance.ex | 2 +- lib/pleroma/activity/pruner.ex | 11 ++++++ .../accept_reject_validator.ex | 1 - lib/pleroma/web/views/manifest_view.ex | 12 +++---- .../workers/cron/database_prune_worker.ex | 3 ++ test/pleroma/activity/pruner_test.exs | 36 +++++++++++++++++++ .../emoji_file_controller_test.exs | 2 +- .../remote_follow_controller_test.exs | 2 +- test/support/factory.ex | 1 + 11 files changed, 87 insertions(+), 26 deletions(-) diff --git a/config/description.exs b/config/description.exs index fc10cbf81..001a21cba 100644 --- a/config/description.exs +++ b/config/description.exs @@ -691,8 +691,8 @@ key: :public, type: :boolean, description: - "Makes the client API in authenticated mode-only except for user-profiles." <> - " Useful for disabling the Local Timeline and The Whole Known Network. " <> + "Switching this on will allow unauthenticated users access to all public resources on your instance" <> + " Switching it off is useful for disabling the Local Timeline and The Whole Known Network. " <> " Note: when setting to `false`, please also check `:restrict_unauthenticated` setting." }, %{ @@ -2998,8 +2998,7 @@ key: :restrict_unauthenticated, label: "Restrict Unauthenticated", type: :group, - description: - "Disallow viewing timelines, user profiles and statuses for unauthenticated users.", + description: "Disallow unauthenticated viewing of timelines, user profiles and statuses.", children: [ %{ key: :timelines, @@ -3009,12 +3008,12 @@ %{ key: :local, type: :boolean, - description: "Disallow view public timeline." + description: "Disallow viewing the public timeline." }, %{ key: :federated, type: :boolean, - description: "Disallow view federated timeline." + description: "Disallow viewing the whole known network timeline." } ] }, @@ -3026,29 +3025,29 @@ %{ key: :local, type: :boolean, - description: "Disallow view local user profiles." + description: "Disallow viewing local user profiles." }, %{ key: :remote, type: :boolean, - description: "Disallow view remote user profiles." + description: "Disallow viewing remote user profiles." } ] }, %{ key: :activities, type: :map, - description: "Settings for statuses.", + description: "Settings for posts.", children: [ %{ key: :local, type: :boolean, - description: "Disallow view local statuses." + description: "Disallow viewing local posts." }, %{ key: :remote, type: :boolean, - description: "Disallow view remote statuses." + description: "Disallow viewing remote posts." } ] } diff --git a/docs/docs/configuration/cheatsheet.md b/docs/docs/configuration/cheatsheet.md index 517fd1993..12c044d67 100644 --- a/docs/docs/configuration/cheatsheet.md +++ b/docs/docs/configuration/cheatsheet.md @@ -33,7 +33,8 @@ To add configuration to your config file, you can copy it from the base config. * `federation_incoming_replies_max_depth`: Max. depth of reply-to activities fetching on incoming federation, to prevent out-of-memory situations while fetching very long threads. If set to `nil`, threads of any depth will be fetched. Lower this value if you experience out-of-memory crashes. * `federation_reachability_timeout_days`: Timeout (in days) of each external federation target being unreachable prior to pausing federating to it. * `allow_relay`: Permits remote instances to subscribe to all public posts of your instance. This may increase the visibility of your instance. -* `public`: Makes the client API in authenticated mode-only except for user-profiles. Useful for disabling the Local Timeline and The Whole Known Network. Note that there is a dependent setting restricting or allowing unauthenticated access to specific resources, see `restrict_unauthenticated` for more details. +* `public`: Allows unauthenticated access to public resources on your instance. This is essentially used as the default value for `:restrict_unauthenticated`. + See `restrict_unauthenticated` for more details. * `quarantined_instances`: *DEPRECATED* ActivityPub instances where activities will not be sent. They can still reach there via other means, we just won't send them. * `allowed_post_formats`: MIME-type list of formats allowed to be posted (transformed into HTML). * `extended_nickname_format`: Set to `true` to use extended local nicknames format (allows underscores/dashes). This will break federation with @@ -1094,7 +1095,7 @@ config :pleroma, :database_config_whitelist, [ ### :restrict_unauthenticated -Restrict access for unauthenticated users to timelines (public and federated), user profiles and statuses. +Restrict access for unauthenticated users to timelines (public and federated), user profiles and posts. * `timelines`: public and federated timelines * `local`: public timeline @@ -1102,13 +1103,24 @@ Restrict access for unauthenticated users to timelines (public and federated), u * `profiles`: user profiles * `local` * `remote` -* `activities`: statuses +* `activities`: posts * `local` * `remote` -Note: when `:instance, :public` is set to `false`, all `:restrict_unauthenticated` items be effectively set to `true` by default. If you'd like to allow unauthenticated access to specific API endpoints on a private instance, please explicitly set `:restrict_unauthenticated` to non-default value in `config/prod.secret.exs`. +#### When :instance, :public is `true` -Note: setting `restrict_unauthenticated/timelines/local` to `true` has no practical sense if `restrict_unauthenticated/timelines/federated` is set to `false` (since local public activities will still be delivered to unauthenticated users as part of federated timeline). +When your instance is in "public" mode, all public resources (users, posts, timelines) are accessible to unauthenticated users. + +Turning any of the `:restrict_unauthenticated` options to `true` will restrict access to the corresponding resources. + +#### When :instance, :public is `false` + +When `:instance, :public` is set to `false`, all of the `:restrict_unauthenticated` options will effectively be set to `true` by default, +meaning that only authenticated users will be able to access the corresponding resources. + +If you'd like to allow unauthenticated access to specific resources, you can turn these settings to `false`. + +**Note**: setting `restrict_unauthenticated/timelines/local` to `true` has no practical sense if `restrict_unauthenticated/timelines/federated` is set to `false` (since local public activities will still be delivered to unauthenticated users as part of federated timeline). ## Pleroma.Web.ApiSpec.CastAndValidate diff --git a/lib/mix/tasks/pleroma/instance.ex b/lib/mix/tasks/pleroma/instance.ex index 8954b3b7c..0647c330f 100644 --- a/lib/mix/tasks/pleroma/instance.ex +++ b/lib/mix/tasks/pleroma/instance.ex @@ -59,7 +59,7 @@ def run(["gen" | rest]) do get_option( options, :domain, - "What domain will your instance use? (e.g pleroma.soykaf.com)" + "What domain will your instance use? (e.g akkoma.example.com)" ), ":" ) ++ [443] diff --git a/lib/pleroma/activity/pruner.ex b/lib/pleroma/activity/pruner.ex index 054ee514a..7f561ebae 100644 --- a/lib/pleroma/activity/pruner.ex +++ b/lib/pleroma/activity/pruner.ex @@ -35,6 +35,17 @@ def prune_removes do |> Repo.delete_all(timeout: :infinity) end + def prune_stale_follow_requests do + before_time = cutoff() + + from(a in Activity, + where: + fragment("?->>'type' = ?", a.data, "Follow") and a.inserted_at < ^before_time and + fragment("?->>'state' = ?", a.data, "reject") + ) + |> Repo.delete_all(timeout: :infinity) + end + defp cutoff do DateTime.utc_now() |> Timex.shift(days: -@cutoff) end diff --git a/lib/pleroma/web/activity_pub/object_validators/accept_reject_validator.ex b/lib/pleroma/web/activity_pub/object_validators/accept_reject_validator.ex index 847d0be62..0561a9ddf 100644 --- a/lib/pleroma/web/activity_pub/object_validators/accept_reject_validator.ex +++ b/lib/pleroma/web/activity_pub/object_validators/accept_reject_validator.ex @@ -6,7 +6,6 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AcceptRejectValidator do use Ecto.Schema alias Pleroma.Activity - alias Pleroma.Object alias Pleroma.User import Ecto.Changeset diff --git a/lib/pleroma/web/views/manifest_view.ex b/lib/pleroma/web/views/manifest_view.ex index d8c736cef..5177b0eba 100644 --- a/lib/pleroma/web/views/manifest_view.ex +++ b/lib/pleroma/web/views/manifest_view.ex @@ -13,14 +13,14 @@ def render("manifest.json", _params) do description: Config.get([:instance, :description]), icons: [ %{ - src: "/static/logo.svg", - type: "image/svg+xml" + src: "/static/logo.svg", + type: "image/svg+xml" }, %{ - src: "/static/logo-512.png", - sizes: "512x512", - type: "image/png", - purpose: "maskable" + src: "/static/logo-512.png", + sizes: "512x512", + type: "image/png", + purpose: "maskable" } ], theme_color: Config.get([:manifest, :theme_color]), diff --git a/lib/pleroma/workers/cron/database_prune_worker.ex b/lib/pleroma/workers/cron/database_prune_worker.ex index 99ea2e836..58995c69a 100644 --- a/lib/pleroma/workers/cron/database_prune_worker.ex +++ b/lib/pleroma/workers/cron/database_prune_worker.ex @@ -15,6 +15,9 @@ def perform(_job) do Logger.info("Pruning old deletes") ActivityPruner.prune_deletes() + Logger.info("Pruning old follow requests") + ActivityPruner.prune_stale_follow_requests() + Logger.info("Pruning old undos") ActivityPruner.prune_undos() diff --git a/test/pleroma/activity/pruner_test.exs b/test/pleroma/activity/pruner_test.exs index 312d4f5e4..e8d4b30aa 100644 --- a/test/pleroma/activity/pruner_test.exs +++ b/test/pleroma/activity/pruner_test.exs @@ -24,4 +24,40 @@ test "it prunes old delete objects" do refute Activity.get_by_id(old_delete.id) end end + + describe "prune_stale_follow_requests" do + test "it prunes old follow requests" do + follower = insert(:user) + followee = insert(:user) + + new_follow_request = + insert( + :follow_activity, + follower: follower, + followed: followee, + state: "reject" + ) + + old_not_rejected_request = + insert(:follow_activity, + follower: follower, + followed: followee, + state: "pending", + inserted_at: DateTime.utc_now() |> DateTime.add(-31 * 24, :hour) + ) + + old_follow_request = + insert(:follow_activity, + follower: follower, + followed: followee, + inserted_at: DateTime.utc_now() |> DateTime.add(-31 * 24, :hour), + state: "reject" + ) + + Pruner.prune_stale_follow_requests() + assert Activity.get_by_id(new_follow_request.id) + assert Activity.get_by_id(old_not_rejected_request.id) + refute Activity.get_by_id(old_follow_request.id) + end + end end diff --git a/test/pleroma/web/pleroma_api/controllers/emoji_file_controller_test.exs b/test/pleroma/web/pleroma_api/controllers/emoji_file_controller_test.exs index 547391249..61a44b8ba 100644 --- a/test/pleroma/web/pleroma_api/controllers/emoji_file_controller_test.exs +++ b/test/pleroma/web/pleroma_api/controllers/emoji_file_controller_test.exs @@ -3,7 +3,7 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.PleromaAPI.EmojiFileControllerTest do - use Pleroma.Web.ConnCase + use Pleroma.Web.ConnCase, async: false import Mock import Tesla.Mock diff --git a/test/pleroma/web/twitter_api/remote_follow_controller_test.exs b/test/pleroma/web/twitter_api/remote_follow_controller_test.exs index 15e9b5884..e7c496eb0 100644 --- a/test/pleroma/web/twitter_api/remote_follow_controller_test.exs +++ b/test/pleroma/web/twitter_api/remote_follow_controller_test.exs @@ -3,7 +3,7 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.TwitterAPI.RemoteFollowControllerTest do - use Pleroma.Web.ConnCase, async: true + use Pleroma.Web.ConnCase, async: false alias Pleroma.MFA alias Pleroma.MFA.TOTP diff --git a/test/support/factory.ex b/test/support/factory.ex index 3e426c565..6ce4decbc 100644 --- a/test/support/factory.ex +++ b/test/support/factory.ex @@ -469,6 +469,7 @@ def follow_activity_factory(attrs \\ %{}) do data: data, actor: follower.ap_id } + |> Map.merge(attrs) end def report_activity_factory(attrs \\ %{}) do From d923cb96b1c1270389b95138c3f7f13dae6286bb Mon Sep 17 00:00:00 2001 From: timorl Date: Sun, 4 Dec 2022 16:37:49 +0100 Subject: [PATCH 083/631] Small improvements to the Gentoo installation isntructions --- docs/docs/installation/gentoo_en.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/docs/docs/installation/gentoo_en.md b/docs/docs/installation/gentoo_en.md index 9450c9b38..76069f645 100644 --- a/docs/docs/installation/gentoo_en.md +++ b/docs/docs/installation/gentoo_en.md @@ -18,6 +18,12 @@ dev-db/postgresql uuid You could opt to add `USE="uuid"` to `/etc/portage/make.conf` if you'd rather set this as a global USE flags, but this flags does unrelated things in other packages, so keep that in mind if you elect to do so. +If you are planning to use `nginx`, as this guide suggests, you should also add the following flag to the same file. + +```text +www-servers/nginx NGINX_MODULES_HTTP: slice +``` + Double check your compiler flags in `/etc/portage/make.conf`. If you require any special compilation flags or would like to set up remote builds, now is the time to do so. Be sure that your CFLAGS and MAKEOPTS make sense for the platform you are using. It is not recommended to use above `-O2` or risky optimization flags for a production server. ### Installing a cron daemon @@ -262,7 +268,7 @@ Even if you are using S3, Akkoma needs someplace to store media posted on your i ```shell akkoma$ mkdir -p ~/akkoma/uploads - ``` +``` #### init.d service @@ -272,7 +278,9 @@ Even if you are using S3, Akkoma needs someplace to store media posted on your i # cp /home/akkoma/akkoma/installation/init.d/akkoma /etc/init.d/ ``` -* Be sure to take a look at this service file and make sure that all paths fit your installation +* Change the `/opt/akkoma` path in this file to `/home/akkoma/akkoma` + +* Be sure to take a look at this service file and make sure that all other paths fit your installation * Enable and start `akkoma`: From 4a94c9a31ef11f63ea71ad9c1f085c18cf8ef083 Mon Sep 17 00:00:00 2001 From: floatingghost Date: Sun, 4 Dec 2022 17:36:59 +0000 Subject: [PATCH 084/631] Add ability to follow hashtags (#336) Co-authored-by: FloatingGhost Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma/pulls/336 --- lib/mix/tasks/pleroma/user.ex | 7 ++ lib/pleroma/hashtag.ex | 27 ++++++ lib/pleroma/user.ex | 58 +++++++++++ lib/pleroma/user/hashtag_follow.ex | 49 ++++++++++ lib/pleroma/web/activity_pub/activity_pub.ex | 25 ++++- .../web/api_spec/operations/tag_operation.ex | 65 +++++++++++++ lib/pleroma/web/api_spec/schemas/tag.ex | 7 +- .../controllers/tag_controller.ex | 47 +++++++++ .../controllers/timeline_controller.ex | 6 ++ .../web/mastodon_api/views/tag_view.ex | 21 ++++ lib/pleroma/web/router.ex | 4 + lib/pleroma/web/streamer.ex | 13 ++- ...0221203232118_add_user_follows_hashtag.exs | 12 +++ test/pleroma/user_test.exs | 70 +++++++++++++ .../web/activity_pub/activity_pub_test.exs | 18 ++++ .../controllers/tag_controller_test.exs | 97 +++++++++++++++++++ test/pleroma/web/streamer_test.exs | 30 ++++++ test/support/factory.ex | 7 ++ 18 files changed, 560 insertions(+), 3 deletions(-) create mode 100644 lib/pleroma/user/hashtag_follow.ex create mode 100644 lib/pleroma/web/api_spec/operations/tag_operation.ex create mode 100644 lib/pleroma/web/mastodon_api/controllers/tag_controller.ex create mode 100644 lib/pleroma/web/mastodon_api/views/tag_view.ex create mode 100644 priv/repo/migrations/20221203232118_add_user_follows_hashtag.exs create mode 100644 test/pleroma/web/mastodon_api/controllers/tag_controller_test.exs diff --git a/lib/mix/tasks/pleroma/user.ex b/lib/mix/tasks/pleroma/user.ex index 278a01acc..dd1cdca5b 100644 --- a/lib/mix/tasks/pleroma/user.ex +++ b/lib/mix/tasks/pleroma/user.ex @@ -471,9 +471,15 @@ def run(["blocking", nickname]) do def run(["timeline_query", nickname]) do start_pleroma() + params = %{local: true} with %User{local: true} = user <- User.get_cached_by_nickname(nickname) do + followed_hashtags = + user + |> User.followed_hashtags() + |> Enum.map(& &1.id) + params = params |> Map.put(:type, ["Create", "Announce"]) @@ -484,6 +490,7 @@ def run(["timeline_query", nickname]) do |> Map.put(:announce_filtering_user, user) |> Map.put(:user, user) |> Map.put(:local_only, params[:local]) + |> Map.put(:hashtags, followed_hashtags) |> Map.delete(:local) _activities = diff --git a/lib/pleroma/hashtag.ex b/lib/pleroma/hashtag.ex index 53e2e9c89..9030ee4e9 100644 --- a/lib/pleroma/hashtag.ex +++ b/lib/pleroma/hashtag.ex @@ -10,6 +10,7 @@ defmodule Pleroma.Hashtag do alias Ecto.Multi alias Pleroma.Hashtag + alias Pleroma.User.HashtagFollow alias Pleroma.Object alias Pleroma.Repo @@ -27,6 +28,14 @@ def normalize_name(name) do |> String.trim() end + def get_by_id(id) do + Repo.get(Hashtag, id) + end + + def get_by_name(name) do + Repo.get_by(Hashtag, name: normalize_name(name)) + end + def get_or_create_by_name(name) do changeset = changeset(%Hashtag{}, %{name: name}) @@ -103,4 +112,22 @@ def delete_unreferenced(ids) do {:ok, deleted_count} end end + + def get_followers(%Hashtag{id: hashtag_id}) do + from(hf in HashtagFollow) + |> where([hf], hf.hashtag_id == ^hashtag_id) + |> join(:inner, [hf], u in assoc(hf, :user)) + |> select([hf, u], u.id) + |> Repo.all() + end + + def get_recipients_for_activity(%Pleroma.Activity{object: %{hashtags: tags}}) + when is_list(tags) do + tags + |> Enum.map(&get_followers/1) + |> List.flatten() + |> Enum.uniq() + end + + def get_recipients_for_activity(_activity), do: [] end diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index b0ab9d0cd..c8262b37b 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -18,6 +18,8 @@ defmodule Pleroma.User do alias Pleroma.Emoji alias Pleroma.FollowingRelationship alias Pleroma.Formatter + alias Pleroma.Hashtag + alias Pleroma.User.HashtagFollow alias Pleroma.HTML alias Pleroma.Keys alias Pleroma.MFA @@ -168,6 +170,12 @@ defmodule Pleroma.User do has_many(:frontend_profiles, Pleroma.Akkoma.FrontendSettingsProfile) + many_to_many(:followed_hashtags, Hashtag, + on_replace: :delete, + on_delete: :delete_all, + join_through: HashtagFollow + ) + for {relationship_type, [ {outgoing_relation, outgoing_relation_target}, @@ -2550,4 +2558,54 @@ def update_last_status_at(user) do _ -> {:error, user} end end + + defp maybe_load_followed_hashtags(%User{followed_hashtags: follows} = user) + when is_list(follows), + do: user + + defp maybe_load_followed_hashtags(%User{} = user) do + followed_hashtags = HashtagFollow.get_by_user(user) + %{user | followed_hashtags: followed_hashtags} + end + + def followed_hashtags(%User{followed_hashtags: follows}) + when is_list(follows), + do: follows + + def followed_hashtags(%User{} = user) do + {:ok, user} = + user + |> maybe_load_followed_hashtags() + |> set_cache() + + user.followed_hashtags + end + + def follow_hashtag(%User{} = user, %Hashtag{} = hashtag) do + Logger.debug("Follow hashtag #{hashtag.name} for user #{user.nickname}") + user = maybe_load_followed_hashtags(user) + + with {:ok, _} <- HashtagFollow.new(user, hashtag), + follows <- HashtagFollow.get_by_user(user), + %User{} = user <- user |> Map.put(:followed_hashtags, follows) do + user + |> set_cache() + end + end + + def unfollow_hashtag(%User{} = user, %Hashtag{} = hashtag) do + Logger.debug("Unfollow hashtag #{hashtag.name} for user #{user.nickname}") + user = maybe_load_followed_hashtags(user) + + with {:ok, _} <- HashtagFollow.delete(user, hashtag), + follows <- HashtagFollow.get_by_user(user), + %User{} = user <- user |> Map.put(:followed_hashtags, follows) do + user + |> set_cache() + end + end + + def following_hashtag?(%User{} = user, %Hashtag{} = hashtag) do + not is_nil(HashtagFollow.get(user, hashtag)) + end end diff --git a/lib/pleroma/user/hashtag_follow.ex b/lib/pleroma/user/hashtag_follow.ex new file mode 100644 index 000000000..43ed93f4d --- /dev/null +++ b/lib/pleroma/user/hashtag_follow.ex @@ -0,0 +1,49 @@ +defmodule Pleroma.User.HashtagFollow do + use Ecto.Schema + import Ecto.Query + import Ecto.Changeset + + alias Pleroma.User + alias Pleroma.Hashtag + alias Pleroma.Repo + + schema "user_follows_hashtag" do + belongs_to(:user, User, type: FlakeId.Ecto.CompatType) + belongs_to(:hashtag, Hashtag) + end + + def changeset(%__MODULE__{} = user_hashtag_follow, attrs) do + user_hashtag_follow + |> cast(attrs, [:user_id, :hashtag_id]) + |> unique_constraint(:hashtag_id, + name: :user_hashtag_follows_user_id_hashtag_id_index, + message: "already following" + ) + |> validate_required([:user_id, :hashtag_id]) + end + + def new(%User{} = user, %Hashtag{} = hashtag) do + %__MODULE__{} + |> changeset(%{user_id: user.id, hashtag_id: hashtag.id}) + |> Repo.insert(on_conflict: :nothing) + end + + def delete(%User{} = user, %Hashtag{} = hashtag) do + with %__MODULE__{} = user_hashtag_follow <- get(user, hashtag) do + Repo.delete(user_hashtag_follow) + else + _ -> {:ok, nil} + end + end + + def get(%User{} = user, %Hashtag{} = hashtag) do + from(hf in __MODULE__) + |> where([hf], hf.user_id == ^user.id and hf.hashtag_id == ^hashtag.id) + |> Repo.one() + end + + def get_by_user(%User{} = user) do + Ecto.assoc(user, :followed_hashtags) + |> Repo.all() + end +end diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index a4f1c7041..8233bcbf8 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -933,6 +933,29 @@ defp restrict_recipients(query, recipients, user) do ) end + # Essentially, either look for activities addressed to `recipients`, _OR_ ones + # that reference a hashtag that the user follows + # Firstly, two fallbacks in case there's no hashtag constraint, or the user doesn't + # follow any + defp restrict_recipients_or_hashtags(query, recipients, user, nil) do + restrict_recipients(query, recipients, user) + end + + defp restrict_recipients_or_hashtags(query, recipients, user, []) do + restrict_recipients(query, recipients, user) + end + + defp restrict_recipients_or_hashtags(query, recipients, _user, hashtag_ids) do + from( + [activity, object] in query, + join: hto in "hashtags_objects", + on: hto.object_id == object.id, + where: + (hto.hashtag_id in ^hashtag_ids and ^Constants.as_public() in activity.recipients) or + fragment("? && ?", ^recipients, activity.recipients) + ) + end + defp restrict_local(query, %{local_only: true}) do from(activity in query, where: activity.local == true) end @@ -1380,7 +1403,7 @@ def fetch_activities_query(recipients, opts \\ %{}) do |> maybe_preload_report_notes(opts) |> maybe_set_thread_muted_field(opts) |> maybe_order(opts) - |> restrict_recipients(recipients, opts[:user]) + |> restrict_recipients_or_hashtags(recipients, opts[:user], opts[:followed_hashtags]) |> restrict_replies(opts) |> restrict_since(opts) |> restrict_local(opts) diff --git a/lib/pleroma/web/api_spec/operations/tag_operation.ex b/lib/pleroma/web/api_spec/operations/tag_operation.ex new file mode 100644 index 000000000..e22457159 --- /dev/null +++ b/lib/pleroma/web/api_spec/operations/tag_operation.ex @@ -0,0 +1,65 @@ +defmodule Pleroma.Web.ApiSpec.TagOperation do + alias OpenApiSpex.Operation + alias OpenApiSpex.Schema + alias Pleroma.Web.ApiSpec.Schemas.ApiError + alias Pleroma.Web.ApiSpec.Schemas.Tag + + def open_api_operation(action) do + operation = String.to_existing_atom("#{action}_operation") + apply(__MODULE__, operation, []) + end + + def show_operation do + %Operation{ + tags: ["Tags"], + summary: "Hashtag", + description: "View a hashtag", + security: [%{"oAuth" => ["read"]}], + parameters: [id_param()], + operationId: "TagController.show", + responses: %{ + 200 => Operation.response("Hashtag", "application/json", Tag), + 404 => Operation.response("Not Found", "application/json", ApiError) + } + } + end + + def follow_operation do + %Operation{ + tags: ["Tags"], + summary: "Follow a hashtag", + description: "Follow a hashtag", + security: [%{"oAuth" => ["write:follows"]}], + parameters: [id_param()], + operationId: "TagController.follow", + responses: %{ + 200 => Operation.response("Hashtag", "application/json", Tag), + 404 => Operation.response("Not Found", "application/json", ApiError) + } + } + end + + def unfollow_operation do + %Operation{ + tags: ["Tags"], + summary: "Unfollow a hashtag", + description: "Unfollow a hashtag", + security: [%{"oAuth" => ["write:follow"]}], + parameters: [id_param()], + operationId: "TagController.unfollow", + responses: %{ + 200 => Operation.response("Hashtag", "application/json", Tag), + 404 => Operation.response("Not Found", "application/json", ApiError) + } + } + end + + defp id_param do + Operation.parameter( + :id, + :path, + %Schema{type: :string}, + "Name of the hashtag" + ) + end +end diff --git a/lib/pleroma/web/api_spec/schemas/tag.ex b/lib/pleroma/web/api_spec/schemas/tag.ex index 657b675e5..41b5e5c78 100644 --- a/lib/pleroma/web/api_spec/schemas/tag.ex +++ b/lib/pleroma/web/api_spec/schemas/tag.ex @@ -17,11 +17,16 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Tag do type: :string, format: :uri, description: "A link to the hashtag on the instance" + }, + following: %Schema{ + type: :boolean, + description: "Whether the authenticated user is following the hashtag" } }, example: %{ name: "cofe", - url: "https://lain.com/tag/cofe" + url: "https://lain.com/tag/cofe", + following: false } }) end diff --git a/lib/pleroma/web/mastodon_api/controllers/tag_controller.ex b/lib/pleroma/web/mastodon_api/controllers/tag_controller.ex new file mode 100644 index 000000000..b8995eb00 --- /dev/null +++ b/lib/pleroma/web/mastodon_api/controllers/tag_controller.ex @@ -0,0 +1,47 @@ +defmodule Pleroma.Web.MastodonAPI.TagController do + @moduledoc "Hashtag routes for mastodon API" + use Pleroma.Web, :controller + + alias Pleroma.User + alias Pleroma.Hashtag + + plug(Pleroma.Web.ApiSpec.CastAndValidate) + plug(Pleroma.Web.Plugs.OAuthScopesPlug, %{scopes: ["read"]} when action in [:show]) + + plug( + Pleroma.Web.Plugs.OAuthScopesPlug, + %{scopes: ["write:follows"]} when action in [:follow, :unfollow] + ) + + defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.TagOperation + + def show(conn, %{id: id}) do + with %Hashtag{} = hashtag <- Hashtag.get_by_name(id) do + render(conn, "show.json", tag: hashtag, for_user: conn.assigns.user) + else + _ -> conn |> render_error(:not_found, "Hashtag not found") + end + end + + def follow(conn, %{id: id}) do + with %Hashtag{} = hashtag <- Hashtag.get_by_name(id), + %User{} = user <- conn.assigns.user, + {:ok, _} <- + User.follow_hashtag(user, hashtag) do + render(conn, "show.json", tag: hashtag, for_user: user) + else + _ -> render_error(conn, :not_found, "Hashtag not found") + end + end + + def unfollow(conn, %{id: id}) do + with %Hashtag{} = hashtag <- Hashtag.get_by_name(id), + %User{} = user <- conn.assigns.user, + {:ok, _} <- + User.unfollow_hashtag(user, hashtag) do + render(conn, "show.json", tag: hashtag, for_user: user) + else + _ -> render_error(conn, :not_found, "Hashtag not found") + end + end +end diff --git a/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex b/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex index 5f8acb2df..2d0e36420 100644 --- a/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex @@ -41,6 +41,11 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do # GET /api/v1/timelines/home def home(%{assigns: %{user: user}} = conn, params) do + followed_hashtags = + user + |> User.followed_hashtags() + |> Enum.map(& &1.id) + params = params |> Map.put(:type, ["Create", "Announce"]) @@ -50,6 +55,7 @@ def home(%{assigns: %{user: user}} = conn, params) do |> Map.put(:announce_filtering_user, user) |> Map.put(:user, user) |> Map.put(:local_only, params[:local]) + |> Map.put(:followed_hashtags, followed_hashtags) |> Map.delete(:local) activities = diff --git a/lib/pleroma/web/mastodon_api/views/tag_view.ex b/lib/pleroma/web/mastodon_api/views/tag_view.ex new file mode 100644 index 000000000..6e491c261 --- /dev/null +++ b/lib/pleroma/web/mastodon_api/views/tag_view.ex @@ -0,0 +1,21 @@ +defmodule Pleroma.Web.MastodonAPI.TagView do + use Pleroma.Web, :view + alias Pleroma.User + alias Pleroma.Web.Router.Helpers + + def render("show.json", %{tag: tag, for_user: user}) do + following = + with %User{} <- user do + User.following_hashtag?(user, tag) + else + _ -> false + end + + %{ + name: tag.name, + url: Helpers.tag_feed_url(Pleroma.Web.Endpoint, :feed, tag.name), + history: [], + following: following + } + end +end diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 71a9e4d29..a34dd26ce 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -598,6 +598,10 @@ defmodule Pleroma.Web.Router do get("/announcements", AnnouncementController, :index) post("/announcements/:id/dismiss", AnnouncementController, :mark_read) + + get("/tags/:id", TagController, :show) + post("/tags/:id/follow", TagController, :follow) + post("/tags/:id/unfollow", TagController, :unfollow) end scope "/api/web", Pleroma.Web do diff --git a/lib/pleroma/web/streamer.ex b/lib/pleroma/web/streamer.ex index c03e7fc30..f009fbd9e 100644 --- a/lib/pleroma/web/streamer.ex +++ b/lib/pleroma/web/streamer.ex @@ -17,6 +17,7 @@ defmodule Pleroma.Web.Streamer do alias Pleroma.Web.OAuth.Token alias Pleroma.Web.Plugs.OAuthScopesPlug alias Pleroma.Web.StreamerView + require Pleroma.Constants @mix_env Mix.env() @registry Pleroma.Web.StreamerRegistry @@ -252,7 +253,17 @@ defp do_stream("user", item) do User.get_recipients_from_activity(item) |> Enum.map(fn %{id: id} -> "user:#{id}" end) - Enum.each(recipient_topics, fn topic -> + hashtag_recipients = + if Pleroma.Constants.as_public() in item.recipients do + Pleroma.Hashtag.get_recipients_for_activity(item) + |> Enum.map(fn id -> "user:#{id}" end) + else + [] + end + + all_recipients = Enum.uniq(recipient_topics ++ hashtag_recipients) + + Enum.each(all_recipients, fn topic -> push_to_socket(topic, item) end) end diff --git a/priv/repo/migrations/20221203232118_add_user_follows_hashtag.exs b/priv/repo/migrations/20221203232118_add_user_follows_hashtag.exs new file mode 100644 index 000000000..27fff2586 --- /dev/null +++ b/priv/repo/migrations/20221203232118_add_user_follows_hashtag.exs @@ -0,0 +1,12 @@ +defmodule Pleroma.Repo.Migrations.AddUserFollowsHashtag do + use Ecto.Migration + + def change do + create table(:user_follows_hashtag) do + add(:hashtag_id, references(:hashtags)) + add(:user_id, references(:users, type: :uuid, on_delete: :delete_all)) + end + + create(unique_index(:user_follows_hashtag, [:user_id, :hashtag_id])) + end +end diff --git a/test/pleroma/user_test.exs b/test/pleroma/user_test.exs index 44763daf7..cc6634aba 100644 --- a/test/pleroma/user_test.exs +++ b/test/pleroma/user_test.exs @@ -2679,4 +2679,74 @@ test "should report error on non-existing alias" do assert user.ap_id in user3_updated.also_known_as end end + + describe "follow_hashtag/2" do + test "should follow a hashtag" do + user = insert(:user) + hashtag = insert(:hashtag) + + assert {:ok, _} = user |> User.follow_hashtag(hashtag) + + user = User.get_cached_by_ap_id(user.ap_id) + + assert user.followed_hashtags |> Enum.count() == 1 + assert hashtag.name in Enum.map(user.followed_hashtags, fn %{name: name} -> name end) + end + + test "should not follow a hashtag twice" do + user = insert(:user) + hashtag = insert(:hashtag) + + assert {:ok, _} = user |> User.follow_hashtag(hashtag) + + assert {:ok, _} = user |> User.follow_hashtag(hashtag) + + user = User.get_cached_by_ap_id(user.ap_id) + + assert user.followed_hashtags |> Enum.count() == 1 + assert hashtag.name in Enum.map(user.followed_hashtags, fn %{name: name} -> name end) + end + + test "can follow multiple hashtags" do + user = insert(:user) + hashtag = insert(:hashtag) + other_hashtag = insert(:hashtag) + + assert {:ok, _} = user |> User.follow_hashtag(hashtag) + assert {:ok, _} = user |> User.follow_hashtag(other_hashtag) + + user = User.get_cached_by_ap_id(user.ap_id) + + assert user.followed_hashtags |> Enum.count() == 2 + assert hashtag.name in Enum.map(user.followed_hashtags, fn %{name: name} -> name end) + assert other_hashtag.name in Enum.map(user.followed_hashtags, fn %{name: name} -> name end) + end + end + + describe "unfollow_hashtag/2" do + test "should unfollow a hashtag" do + user = insert(:user) + hashtag = insert(:hashtag) + + assert {:ok, _} = user |> User.follow_hashtag(hashtag) + assert {:ok, _} = user |> User.unfollow_hashtag(hashtag) + + user = User.get_cached_by_ap_id(user.ap_id) + + assert user.followed_hashtags |> Enum.count() == 0 + end + + test "should not error when trying to unfollow a hashtag twice" do + user = insert(:user) + hashtag = insert(:hashtag) + + assert {:ok, _} = user |> User.follow_hashtag(hashtag) + assert {:ok, _} = user |> User.unfollow_hashtag(hashtag) + assert {:ok, _} = user |> User.unfollow_hashtag(hashtag) + + user = User.get_cached_by_ap_id(user.ap_id) + + assert user.followed_hashtags |> Enum.count() == 0 + end + end end diff --git a/test/pleroma/web/activity_pub/activity_pub_test.exs b/test/pleroma/web/activity_pub/activity_pub_test.exs index 8d39b1076..fc452ef1a 100644 --- a/test/pleroma/web/activity_pub/activity_pub_test.exs +++ b/test/pleroma/web/activity_pub/activity_pub_test.exs @@ -719,6 +719,24 @@ test "retrieve the activities for certain recipients" do end end + describe "fetch activities for followed hashtags" do + test "it should return public activities that reference a given hashtag" do + hashtag = insert(:hashtag, name: "tenshi") + user = insert(:user) + + {:ok, public} = CommonAPI.post(user, %{status: "maji #tenshi", visibility: "public"}) + {:ok, _unrelated} = CommonAPI.post(user, %{status: "dai #tensh", visibility: "public"}) + {:ok, unlisted} = CommonAPI.post(user, %{status: "maji #tenshi", visibility: "unlisted"}) + {:ok, _private} = CommonAPI.post(user, %{status: "maji #tenshi", visibility: "private"}) + + activities = ActivityPub.fetch_activities([], %{followed_hashtags: [hashtag.id]}) + assert length(activities) == 2 + public_id = public.id + unlisted_id = unlisted.id + assert [%{id: ^public_id}, %{id: ^unlisted_id}] = activities + end + end + describe "fetch activities in context" do test "retrieves activities that have a given context" do {:ok, activity} = ActivityBuilder.insert(%{"type" => "Create", "context" => "2hu"}) diff --git a/test/pleroma/web/mastodon_api/controllers/tag_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/tag_controller_test.exs new file mode 100644 index 000000000..a1b73ad78 --- /dev/null +++ b/test/pleroma/web/mastodon_api/controllers/tag_controller_test.exs @@ -0,0 +1,97 @@ +defmodule Pleroma.Web.MastodonAPI.TagControllerTest do + use Pleroma.Web.ConnCase + + import Pleroma.Factory + import Tesla.Mock + + alias Pleroma.User + + setup do + mock(fn env -> apply(HttpRequestMock, :request, [env]) end) + :ok + end + + describe "GET /api/v1/tags/:id" do + test "returns 200 with tag" do + %{user: user, conn: conn} = oauth_access(["read"]) + + tag = insert(:hashtag, name: "jubjub") + {:ok, _user} = User.follow_hashtag(user, tag) + + response = + conn + |> get("/api/v1/tags/jubjub") + |> json_response_and_validate_schema(200) + + assert %{ + "name" => "jubjub", + "url" => "http://localhost:4001/tags/jubjub", + "history" => [], + "following" => true + } = response + end + + test "returns 404 with unknown tag" do + %{conn: conn} = oauth_access(["read"]) + + conn + |> get("/api/v1/tags/jubjub") + |> json_response_and_validate_schema(404) + end + end + + describe "POST /api/v1/tags/:id/follow" do + test "should follow a hashtag" do + %{user: user, conn: conn} = oauth_access(["write:follows"]) + hashtag = insert(:hashtag, name: "jubjub") + + response = + conn + |> post("/api/v1/tags/jubjub/follow") + |> json_response_and_validate_schema(200) + + assert response["following"] == true + user = User.get_cached_by_ap_id(user.ap_id) + assert User.following_hashtag?(user, hashtag) + end + + test "should 404 if hashtag doesn't exist" do + %{conn: conn} = oauth_access(["write:follows"]) + + response = + conn + |> post("/api/v1/tags/rubrub/follow") + |> json_response_and_validate_schema(404) + + assert response["error"] == "Hashtag not found" + end + end + + describe "POST /api/v1/tags/:id/unfollow" do + test "should unfollow a hashtag" do + %{user: user, conn: conn} = oauth_access(["write:follows"]) + hashtag = insert(:hashtag, name: "jubjub") + {:ok, user} = User.follow_hashtag(user, hashtag) + + response = + conn + |> post("/api/v1/tags/jubjub/unfollow") + |> json_response_and_validate_schema(200) + + assert response["following"] == false + user = User.get_cached_by_ap_id(user.ap_id) + refute User.following_hashtag?(user, hashtag) + end + + test "should 404 if hashtag doesn't exist" do + %{conn: conn} = oauth_access(["write:follows"]) + + response = + conn + |> post("/api/v1/tags/rubrub/unfollow") + |> json_response_and_validate_schema(404) + + assert response["error"] == "Hashtag not found" + end + end +end diff --git a/test/pleroma/web/streamer_test.exs b/test/pleroma/web/streamer_test.exs index a9db5a015..b07c16faa 100644 --- a/test/pleroma/web/streamer_test.exs +++ b/test/pleroma/web/streamer_test.exs @@ -410,6 +410,36 @@ test "it streams own edits in the 'user' stream", %{user: user, token: oauth_tok assert_receive {:render_with_user, _, "status_update.json", ^create, ^stream} refute Streamer.filtered_by_user?(user, edited) end + + test "it streams posts containing followed hashtags on the 'user' stream", %{ + user: user, + token: oauth_token + } do + hashtag = insert(:hashtag, %{name: "tenshi"}) + other_user = insert(:user) + {:ok, user} = User.follow_hashtag(user, hashtag) + + Streamer.get_topic_and_add_socket("user", user, oauth_token) + {:ok, activity} = CommonAPI.post(other_user, %{status: "hey #tenshi"}) + + assert_receive {:render_with_user, _, "update.json", ^activity, _} + end + + test "should not stream private posts containing followed hashtags on the 'user' stream", %{ + user: user, + token: oauth_token + } do + hashtag = insert(:hashtag, %{name: "tenshi"}) + other_user = insert(:user) + {:ok, user} = User.follow_hashtag(user, hashtag) + + Streamer.get_topic_and_add_socket("user", user, oauth_token) + + {:ok, activity} = + CommonAPI.post(other_user, %{status: "hey #tenshi", visibility: "private"}) + + refute_receive {:render_with_user, _, "update.json", ^activity, _} + end end describe "public streams" do diff --git a/test/support/factory.ex b/test/support/factory.ex index 6ce4decbc..808f8f887 100644 --- a/test/support/factory.ex +++ b/test/support/factory.ex @@ -716,4 +716,11 @@ def delivery_factory(params \\ %{}) do user: user } end + + def hashtag_factory(params \\ %{}) do + %Pleroma.Hashtag{ + name: "test #{sequence(:hashtag_name, & &1)}" + } + |> Map.merge(params) + end end From 4c3971aebd9cb950e300aee17598a7be6e94691c Mon Sep 17 00:00:00 2001 From: floatingghost Date: Sun, 4 Dec 2022 18:35:04 +0000 Subject: [PATCH 085/631] Add changelog entry for hashtag following --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 136c7e65f..e0946b76d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Ability to set a default post expiry time, after which the post will be deleted. If used in concert with ActivityExpiration MRF, the expiry which comes _sooner_ will be applied. - Regular task to prune local transient activities - Task to manually run the transient prune job (pleroma.database prune\_task) +- Ability to follow hashtags ## Changed - MastoAPI: Accept BooleanLike input on `/api/v1/accounts/:id/follow` (fixes follows with mastodon.py) From ec6bf8c3f7a2d429b1eddcada1e39ec9dba4edec Mon Sep 17 00:00:00 2001 From: floatingghost Date: Sun, 4 Dec 2022 20:04:09 +0000 Subject: [PATCH 086/631] revert 4a94c9a31ef11f63ea71ad9c1f085c18cf8ef083 revert Add ability to follow hashtags (#336) Co-authored-by: FloatingGhost Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma/pulls/336 --- lib/mix/tasks/pleroma/user.ex | 7 -- lib/pleroma/hashtag.ex | 27 ------ lib/pleroma/user.ex | 58 ----------- lib/pleroma/user/hashtag_follow.ex | 49 ---------- lib/pleroma/web/activity_pub/activity_pub.ex | 25 +---- .../web/api_spec/operations/tag_operation.ex | 65 ------------- lib/pleroma/web/api_spec/schemas/tag.ex | 7 +- .../controllers/tag_controller.ex | 47 --------- .../controllers/timeline_controller.ex | 6 -- .../web/mastodon_api/views/tag_view.ex | 21 ---- lib/pleroma/web/router.ex | 4 - lib/pleroma/web/streamer.ex | 13 +-- ...0221203232118_add_user_follows_hashtag.exs | 12 --- test/pleroma/user_test.exs | 70 ------------- .../web/activity_pub/activity_pub_test.exs | 18 ---- .../controllers/tag_controller_test.exs | 97 ------------------- test/pleroma/web/streamer_test.exs | 30 ------ test/support/factory.ex | 7 -- 18 files changed, 3 insertions(+), 560 deletions(-) delete mode 100644 lib/pleroma/user/hashtag_follow.ex delete mode 100644 lib/pleroma/web/api_spec/operations/tag_operation.ex delete mode 100644 lib/pleroma/web/mastodon_api/controllers/tag_controller.ex delete mode 100644 lib/pleroma/web/mastodon_api/views/tag_view.ex delete mode 100644 priv/repo/migrations/20221203232118_add_user_follows_hashtag.exs delete mode 100644 test/pleroma/web/mastodon_api/controllers/tag_controller_test.exs diff --git a/lib/mix/tasks/pleroma/user.ex b/lib/mix/tasks/pleroma/user.ex index dd1cdca5b..278a01acc 100644 --- a/lib/mix/tasks/pleroma/user.ex +++ b/lib/mix/tasks/pleroma/user.ex @@ -471,15 +471,9 @@ def run(["blocking", nickname]) do def run(["timeline_query", nickname]) do start_pleroma() - params = %{local: true} with %User{local: true} = user <- User.get_cached_by_nickname(nickname) do - followed_hashtags = - user - |> User.followed_hashtags() - |> Enum.map(& &1.id) - params = params |> Map.put(:type, ["Create", "Announce"]) @@ -490,7 +484,6 @@ def run(["timeline_query", nickname]) do |> Map.put(:announce_filtering_user, user) |> Map.put(:user, user) |> Map.put(:local_only, params[:local]) - |> Map.put(:hashtags, followed_hashtags) |> Map.delete(:local) _activities = diff --git a/lib/pleroma/hashtag.ex b/lib/pleroma/hashtag.ex index 9030ee4e9..53e2e9c89 100644 --- a/lib/pleroma/hashtag.ex +++ b/lib/pleroma/hashtag.ex @@ -10,7 +10,6 @@ defmodule Pleroma.Hashtag do alias Ecto.Multi alias Pleroma.Hashtag - alias Pleroma.User.HashtagFollow alias Pleroma.Object alias Pleroma.Repo @@ -28,14 +27,6 @@ def normalize_name(name) do |> String.trim() end - def get_by_id(id) do - Repo.get(Hashtag, id) - end - - def get_by_name(name) do - Repo.get_by(Hashtag, name: normalize_name(name)) - end - def get_or_create_by_name(name) do changeset = changeset(%Hashtag{}, %{name: name}) @@ -112,22 +103,4 @@ def delete_unreferenced(ids) do {:ok, deleted_count} end end - - def get_followers(%Hashtag{id: hashtag_id}) do - from(hf in HashtagFollow) - |> where([hf], hf.hashtag_id == ^hashtag_id) - |> join(:inner, [hf], u in assoc(hf, :user)) - |> select([hf, u], u.id) - |> Repo.all() - end - - def get_recipients_for_activity(%Pleroma.Activity{object: %{hashtags: tags}}) - when is_list(tags) do - tags - |> Enum.map(&get_followers/1) - |> List.flatten() - |> Enum.uniq() - end - - def get_recipients_for_activity(_activity), do: [] end diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index c8262b37b..b0ab9d0cd 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -18,8 +18,6 @@ defmodule Pleroma.User do alias Pleroma.Emoji alias Pleroma.FollowingRelationship alias Pleroma.Formatter - alias Pleroma.Hashtag - alias Pleroma.User.HashtagFollow alias Pleroma.HTML alias Pleroma.Keys alias Pleroma.MFA @@ -170,12 +168,6 @@ defmodule Pleroma.User do has_many(:frontend_profiles, Pleroma.Akkoma.FrontendSettingsProfile) - many_to_many(:followed_hashtags, Hashtag, - on_replace: :delete, - on_delete: :delete_all, - join_through: HashtagFollow - ) - for {relationship_type, [ {outgoing_relation, outgoing_relation_target}, @@ -2558,54 +2550,4 @@ def update_last_status_at(user) do _ -> {:error, user} end end - - defp maybe_load_followed_hashtags(%User{followed_hashtags: follows} = user) - when is_list(follows), - do: user - - defp maybe_load_followed_hashtags(%User{} = user) do - followed_hashtags = HashtagFollow.get_by_user(user) - %{user | followed_hashtags: followed_hashtags} - end - - def followed_hashtags(%User{followed_hashtags: follows}) - when is_list(follows), - do: follows - - def followed_hashtags(%User{} = user) do - {:ok, user} = - user - |> maybe_load_followed_hashtags() - |> set_cache() - - user.followed_hashtags - end - - def follow_hashtag(%User{} = user, %Hashtag{} = hashtag) do - Logger.debug("Follow hashtag #{hashtag.name} for user #{user.nickname}") - user = maybe_load_followed_hashtags(user) - - with {:ok, _} <- HashtagFollow.new(user, hashtag), - follows <- HashtagFollow.get_by_user(user), - %User{} = user <- user |> Map.put(:followed_hashtags, follows) do - user - |> set_cache() - end - end - - def unfollow_hashtag(%User{} = user, %Hashtag{} = hashtag) do - Logger.debug("Unfollow hashtag #{hashtag.name} for user #{user.nickname}") - user = maybe_load_followed_hashtags(user) - - with {:ok, _} <- HashtagFollow.delete(user, hashtag), - follows <- HashtagFollow.get_by_user(user), - %User{} = user <- user |> Map.put(:followed_hashtags, follows) do - user - |> set_cache() - end - end - - def following_hashtag?(%User{} = user, %Hashtag{} = hashtag) do - not is_nil(HashtagFollow.get(user, hashtag)) - end end diff --git a/lib/pleroma/user/hashtag_follow.ex b/lib/pleroma/user/hashtag_follow.ex deleted file mode 100644 index 43ed93f4d..000000000 --- a/lib/pleroma/user/hashtag_follow.ex +++ /dev/null @@ -1,49 +0,0 @@ -defmodule Pleroma.User.HashtagFollow do - use Ecto.Schema - import Ecto.Query - import Ecto.Changeset - - alias Pleroma.User - alias Pleroma.Hashtag - alias Pleroma.Repo - - schema "user_follows_hashtag" do - belongs_to(:user, User, type: FlakeId.Ecto.CompatType) - belongs_to(:hashtag, Hashtag) - end - - def changeset(%__MODULE__{} = user_hashtag_follow, attrs) do - user_hashtag_follow - |> cast(attrs, [:user_id, :hashtag_id]) - |> unique_constraint(:hashtag_id, - name: :user_hashtag_follows_user_id_hashtag_id_index, - message: "already following" - ) - |> validate_required([:user_id, :hashtag_id]) - end - - def new(%User{} = user, %Hashtag{} = hashtag) do - %__MODULE__{} - |> changeset(%{user_id: user.id, hashtag_id: hashtag.id}) - |> Repo.insert(on_conflict: :nothing) - end - - def delete(%User{} = user, %Hashtag{} = hashtag) do - with %__MODULE__{} = user_hashtag_follow <- get(user, hashtag) do - Repo.delete(user_hashtag_follow) - else - _ -> {:ok, nil} - end - end - - def get(%User{} = user, %Hashtag{} = hashtag) do - from(hf in __MODULE__) - |> where([hf], hf.user_id == ^user.id and hf.hashtag_id == ^hashtag.id) - |> Repo.one() - end - - def get_by_user(%User{} = user) do - Ecto.assoc(user, :followed_hashtags) - |> Repo.all() - end -end diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 8233bcbf8..a4f1c7041 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -933,29 +933,6 @@ defp restrict_recipients(query, recipients, user) do ) end - # Essentially, either look for activities addressed to `recipients`, _OR_ ones - # that reference a hashtag that the user follows - # Firstly, two fallbacks in case there's no hashtag constraint, or the user doesn't - # follow any - defp restrict_recipients_or_hashtags(query, recipients, user, nil) do - restrict_recipients(query, recipients, user) - end - - defp restrict_recipients_or_hashtags(query, recipients, user, []) do - restrict_recipients(query, recipients, user) - end - - defp restrict_recipients_or_hashtags(query, recipients, _user, hashtag_ids) do - from( - [activity, object] in query, - join: hto in "hashtags_objects", - on: hto.object_id == object.id, - where: - (hto.hashtag_id in ^hashtag_ids and ^Constants.as_public() in activity.recipients) or - fragment("? && ?", ^recipients, activity.recipients) - ) - end - defp restrict_local(query, %{local_only: true}) do from(activity in query, where: activity.local == true) end @@ -1403,7 +1380,7 @@ def fetch_activities_query(recipients, opts \\ %{}) do |> maybe_preload_report_notes(opts) |> maybe_set_thread_muted_field(opts) |> maybe_order(opts) - |> restrict_recipients_or_hashtags(recipients, opts[:user], opts[:followed_hashtags]) + |> restrict_recipients(recipients, opts[:user]) |> restrict_replies(opts) |> restrict_since(opts) |> restrict_local(opts) diff --git a/lib/pleroma/web/api_spec/operations/tag_operation.ex b/lib/pleroma/web/api_spec/operations/tag_operation.ex deleted file mode 100644 index e22457159..000000000 --- a/lib/pleroma/web/api_spec/operations/tag_operation.ex +++ /dev/null @@ -1,65 +0,0 @@ -defmodule Pleroma.Web.ApiSpec.TagOperation do - alias OpenApiSpex.Operation - alias OpenApiSpex.Schema - alias Pleroma.Web.ApiSpec.Schemas.ApiError - alias Pleroma.Web.ApiSpec.Schemas.Tag - - def open_api_operation(action) do - operation = String.to_existing_atom("#{action}_operation") - apply(__MODULE__, operation, []) - end - - def show_operation do - %Operation{ - tags: ["Tags"], - summary: "Hashtag", - description: "View a hashtag", - security: [%{"oAuth" => ["read"]}], - parameters: [id_param()], - operationId: "TagController.show", - responses: %{ - 200 => Operation.response("Hashtag", "application/json", Tag), - 404 => Operation.response("Not Found", "application/json", ApiError) - } - } - end - - def follow_operation do - %Operation{ - tags: ["Tags"], - summary: "Follow a hashtag", - description: "Follow a hashtag", - security: [%{"oAuth" => ["write:follows"]}], - parameters: [id_param()], - operationId: "TagController.follow", - responses: %{ - 200 => Operation.response("Hashtag", "application/json", Tag), - 404 => Operation.response("Not Found", "application/json", ApiError) - } - } - end - - def unfollow_operation do - %Operation{ - tags: ["Tags"], - summary: "Unfollow a hashtag", - description: "Unfollow a hashtag", - security: [%{"oAuth" => ["write:follow"]}], - parameters: [id_param()], - operationId: "TagController.unfollow", - responses: %{ - 200 => Operation.response("Hashtag", "application/json", Tag), - 404 => Operation.response("Not Found", "application/json", ApiError) - } - } - end - - defp id_param do - Operation.parameter( - :id, - :path, - %Schema{type: :string}, - "Name of the hashtag" - ) - end -end diff --git a/lib/pleroma/web/api_spec/schemas/tag.ex b/lib/pleroma/web/api_spec/schemas/tag.ex index 41b5e5c78..657b675e5 100644 --- a/lib/pleroma/web/api_spec/schemas/tag.ex +++ b/lib/pleroma/web/api_spec/schemas/tag.ex @@ -17,16 +17,11 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Tag do type: :string, format: :uri, description: "A link to the hashtag on the instance" - }, - following: %Schema{ - type: :boolean, - description: "Whether the authenticated user is following the hashtag" } }, example: %{ name: "cofe", - url: "https://lain.com/tag/cofe", - following: false + url: "https://lain.com/tag/cofe" } }) end diff --git a/lib/pleroma/web/mastodon_api/controllers/tag_controller.ex b/lib/pleroma/web/mastodon_api/controllers/tag_controller.ex deleted file mode 100644 index b8995eb00..000000000 --- a/lib/pleroma/web/mastodon_api/controllers/tag_controller.ex +++ /dev/null @@ -1,47 +0,0 @@ -defmodule Pleroma.Web.MastodonAPI.TagController do - @moduledoc "Hashtag routes for mastodon API" - use Pleroma.Web, :controller - - alias Pleroma.User - alias Pleroma.Hashtag - - plug(Pleroma.Web.ApiSpec.CastAndValidate) - plug(Pleroma.Web.Plugs.OAuthScopesPlug, %{scopes: ["read"]} when action in [:show]) - - plug( - Pleroma.Web.Plugs.OAuthScopesPlug, - %{scopes: ["write:follows"]} when action in [:follow, :unfollow] - ) - - defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.TagOperation - - def show(conn, %{id: id}) do - with %Hashtag{} = hashtag <- Hashtag.get_by_name(id) do - render(conn, "show.json", tag: hashtag, for_user: conn.assigns.user) - else - _ -> conn |> render_error(:not_found, "Hashtag not found") - end - end - - def follow(conn, %{id: id}) do - with %Hashtag{} = hashtag <- Hashtag.get_by_name(id), - %User{} = user <- conn.assigns.user, - {:ok, _} <- - User.follow_hashtag(user, hashtag) do - render(conn, "show.json", tag: hashtag, for_user: user) - else - _ -> render_error(conn, :not_found, "Hashtag not found") - end - end - - def unfollow(conn, %{id: id}) do - with %Hashtag{} = hashtag <- Hashtag.get_by_name(id), - %User{} = user <- conn.assigns.user, - {:ok, _} <- - User.unfollow_hashtag(user, hashtag) do - render(conn, "show.json", tag: hashtag, for_user: user) - else - _ -> render_error(conn, :not_found, "Hashtag not found") - end - end -end diff --git a/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex b/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex index 2d0e36420..5f8acb2df 100644 --- a/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex @@ -41,11 +41,6 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do # GET /api/v1/timelines/home def home(%{assigns: %{user: user}} = conn, params) do - followed_hashtags = - user - |> User.followed_hashtags() - |> Enum.map(& &1.id) - params = params |> Map.put(:type, ["Create", "Announce"]) @@ -55,7 +50,6 @@ def home(%{assigns: %{user: user}} = conn, params) do |> Map.put(:announce_filtering_user, user) |> Map.put(:user, user) |> Map.put(:local_only, params[:local]) - |> Map.put(:followed_hashtags, followed_hashtags) |> Map.delete(:local) activities = diff --git a/lib/pleroma/web/mastodon_api/views/tag_view.ex b/lib/pleroma/web/mastodon_api/views/tag_view.ex deleted file mode 100644 index 6e491c261..000000000 --- a/lib/pleroma/web/mastodon_api/views/tag_view.ex +++ /dev/null @@ -1,21 +0,0 @@ -defmodule Pleroma.Web.MastodonAPI.TagView do - use Pleroma.Web, :view - alias Pleroma.User - alias Pleroma.Web.Router.Helpers - - def render("show.json", %{tag: tag, for_user: user}) do - following = - with %User{} <- user do - User.following_hashtag?(user, tag) - else - _ -> false - end - - %{ - name: tag.name, - url: Helpers.tag_feed_url(Pleroma.Web.Endpoint, :feed, tag.name), - history: [], - following: following - } - end -end diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index a34dd26ce..71a9e4d29 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -598,10 +598,6 @@ defmodule Pleroma.Web.Router do get("/announcements", AnnouncementController, :index) post("/announcements/:id/dismiss", AnnouncementController, :mark_read) - - get("/tags/:id", TagController, :show) - post("/tags/:id/follow", TagController, :follow) - post("/tags/:id/unfollow", TagController, :unfollow) end scope "/api/web", Pleroma.Web do diff --git a/lib/pleroma/web/streamer.ex b/lib/pleroma/web/streamer.ex index f009fbd9e..c03e7fc30 100644 --- a/lib/pleroma/web/streamer.ex +++ b/lib/pleroma/web/streamer.ex @@ -17,7 +17,6 @@ defmodule Pleroma.Web.Streamer do alias Pleroma.Web.OAuth.Token alias Pleroma.Web.Plugs.OAuthScopesPlug alias Pleroma.Web.StreamerView - require Pleroma.Constants @mix_env Mix.env() @registry Pleroma.Web.StreamerRegistry @@ -253,17 +252,7 @@ defp do_stream("user", item) do User.get_recipients_from_activity(item) |> Enum.map(fn %{id: id} -> "user:#{id}" end) - hashtag_recipients = - if Pleroma.Constants.as_public() in item.recipients do - Pleroma.Hashtag.get_recipients_for_activity(item) - |> Enum.map(fn id -> "user:#{id}" end) - else - [] - end - - all_recipients = Enum.uniq(recipient_topics ++ hashtag_recipients) - - Enum.each(all_recipients, fn topic -> + Enum.each(recipient_topics, fn topic -> push_to_socket(topic, item) end) end diff --git a/priv/repo/migrations/20221203232118_add_user_follows_hashtag.exs b/priv/repo/migrations/20221203232118_add_user_follows_hashtag.exs deleted file mode 100644 index 27fff2586..000000000 --- a/priv/repo/migrations/20221203232118_add_user_follows_hashtag.exs +++ /dev/null @@ -1,12 +0,0 @@ -defmodule Pleroma.Repo.Migrations.AddUserFollowsHashtag do - use Ecto.Migration - - def change do - create table(:user_follows_hashtag) do - add(:hashtag_id, references(:hashtags)) - add(:user_id, references(:users, type: :uuid, on_delete: :delete_all)) - end - - create(unique_index(:user_follows_hashtag, [:user_id, :hashtag_id])) - end -end diff --git a/test/pleroma/user_test.exs b/test/pleroma/user_test.exs index cc6634aba..44763daf7 100644 --- a/test/pleroma/user_test.exs +++ b/test/pleroma/user_test.exs @@ -2679,74 +2679,4 @@ test "should report error on non-existing alias" do assert user.ap_id in user3_updated.also_known_as end end - - describe "follow_hashtag/2" do - test "should follow a hashtag" do - user = insert(:user) - hashtag = insert(:hashtag) - - assert {:ok, _} = user |> User.follow_hashtag(hashtag) - - user = User.get_cached_by_ap_id(user.ap_id) - - assert user.followed_hashtags |> Enum.count() == 1 - assert hashtag.name in Enum.map(user.followed_hashtags, fn %{name: name} -> name end) - end - - test "should not follow a hashtag twice" do - user = insert(:user) - hashtag = insert(:hashtag) - - assert {:ok, _} = user |> User.follow_hashtag(hashtag) - - assert {:ok, _} = user |> User.follow_hashtag(hashtag) - - user = User.get_cached_by_ap_id(user.ap_id) - - assert user.followed_hashtags |> Enum.count() == 1 - assert hashtag.name in Enum.map(user.followed_hashtags, fn %{name: name} -> name end) - end - - test "can follow multiple hashtags" do - user = insert(:user) - hashtag = insert(:hashtag) - other_hashtag = insert(:hashtag) - - assert {:ok, _} = user |> User.follow_hashtag(hashtag) - assert {:ok, _} = user |> User.follow_hashtag(other_hashtag) - - user = User.get_cached_by_ap_id(user.ap_id) - - assert user.followed_hashtags |> Enum.count() == 2 - assert hashtag.name in Enum.map(user.followed_hashtags, fn %{name: name} -> name end) - assert other_hashtag.name in Enum.map(user.followed_hashtags, fn %{name: name} -> name end) - end - end - - describe "unfollow_hashtag/2" do - test "should unfollow a hashtag" do - user = insert(:user) - hashtag = insert(:hashtag) - - assert {:ok, _} = user |> User.follow_hashtag(hashtag) - assert {:ok, _} = user |> User.unfollow_hashtag(hashtag) - - user = User.get_cached_by_ap_id(user.ap_id) - - assert user.followed_hashtags |> Enum.count() == 0 - end - - test "should not error when trying to unfollow a hashtag twice" do - user = insert(:user) - hashtag = insert(:hashtag) - - assert {:ok, _} = user |> User.follow_hashtag(hashtag) - assert {:ok, _} = user |> User.unfollow_hashtag(hashtag) - assert {:ok, _} = user |> User.unfollow_hashtag(hashtag) - - user = User.get_cached_by_ap_id(user.ap_id) - - assert user.followed_hashtags |> Enum.count() == 0 - end - end end diff --git a/test/pleroma/web/activity_pub/activity_pub_test.exs b/test/pleroma/web/activity_pub/activity_pub_test.exs index fc452ef1a..8d39b1076 100644 --- a/test/pleroma/web/activity_pub/activity_pub_test.exs +++ b/test/pleroma/web/activity_pub/activity_pub_test.exs @@ -719,24 +719,6 @@ test "retrieve the activities for certain recipients" do end end - describe "fetch activities for followed hashtags" do - test "it should return public activities that reference a given hashtag" do - hashtag = insert(:hashtag, name: "tenshi") - user = insert(:user) - - {:ok, public} = CommonAPI.post(user, %{status: "maji #tenshi", visibility: "public"}) - {:ok, _unrelated} = CommonAPI.post(user, %{status: "dai #tensh", visibility: "public"}) - {:ok, unlisted} = CommonAPI.post(user, %{status: "maji #tenshi", visibility: "unlisted"}) - {:ok, _private} = CommonAPI.post(user, %{status: "maji #tenshi", visibility: "private"}) - - activities = ActivityPub.fetch_activities([], %{followed_hashtags: [hashtag.id]}) - assert length(activities) == 2 - public_id = public.id - unlisted_id = unlisted.id - assert [%{id: ^public_id}, %{id: ^unlisted_id}] = activities - end - end - describe "fetch activities in context" do test "retrieves activities that have a given context" do {:ok, activity} = ActivityBuilder.insert(%{"type" => "Create", "context" => "2hu"}) diff --git a/test/pleroma/web/mastodon_api/controllers/tag_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/tag_controller_test.exs deleted file mode 100644 index a1b73ad78..000000000 --- a/test/pleroma/web/mastodon_api/controllers/tag_controller_test.exs +++ /dev/null @@ -1,97 +0,0 @@ -defmodule Pleroma.Web.MastodonAPI.TagControllerTest do - use Pleroma.Web.ConnCase - - import Pleroma.Factory - import Tesla.Mock - - alias Pleroma.User - - setup do - mock(fn env -> apply(HttpRequestMock, :request, [env]) end) - :ok - end - - describe "GET /api/v1/tags/:id" do - test "returns 200 with tag" do - %{user: user, conn: conn} = oauth_access(["read"]) - - tag = insert(:hashtag, name: "jubjub") - {:ok, _user} = User.follow_hashtag(user, tag) - - response = - conn - |> get("/api/v1/tags/jubjub") - |> json_response_and_validate_schema(200) - - assert %{ - "name" => "jubjub", - "url" => "http://localhost:4001/tags/jubjub", - "history" => [], - "following" => true - } = response - end - - test "returns 404 with unknown tag" do - %{conn: conn} = oauth_access(["read"]) - - conn - |> get("/api/v1/tags/jubjub") - |> json_response_and_validate_schema(404) - end - end - - describe "POST /api/v1/tags/:id/follow" do - test "should follow a hashtag" do - %{user: user, conn: conn} = oauth_access(["write:follows"]) - hashtag = insert(:hashtag, name: "jubjub") - - response = - conn - |> post("/api/v1/tags/jubjub/follow") - |> json_response_and_validate_schema(200) - - assert response["following"] == true - user = User.get_cached_by_ap_id(user.ap_id) - assert User.following_hashtag?(user, hashtag) - end - - test "should 404 if hashtag doesn't exist" do - %{conn: conn} = oauth_access(["write:follows"]) - - response = - conn - |> post("/api/v1/tags/rubrub/follow") - |> json_response_and_validate_schema(404) - - assert response["error"] == "Hashtag not found" - end - end - - describe "POST /api/v1/tags/:id/unfollow" do - test "should unfollow a hashtag" do - %{user: user, conn: conn} = oauth_access(["write:follows"]) - hashtag = insert(:hashtag, name: "jubjub") - {:ok, user} = User.follow_hashtag(user, hashtag) - - response = - conn - |> post("/api/v1/tags/jubjub/unfollow") - |> json_response_and_validate_schema(200) - - assert response["following"] == false - user = User.get_cached_by_ap_id(user.ap_id) - refute User.following_hashtag?(user, hashtag) - end - - test "should 404 if hashtag doesn't exist" do - %{conn: conn} = oauth_access(["write:follows"]) - - response = - conn - |> post("/api/v1/tags/rubrub/unfollow") - |> json_response_and_validate_schema(404) - - assert response["error"] == "Hashtag not found" - end - end -end diff --git a/test/pleroma/web/streamer_test.exs b/test/pleroma/web/streamer_test.exs index b07c16faa..a9db5a015 100644 --- a/test/pleroma/web/streamer_test.exs +++ b/test/pleroma/web/streamer_test.exs @@ -410,36 +410,6 @@ test "it streams own edits in the 'user' stream", %{user: user, token: oauth_tok assert_receive {:render_with_user, _, "status_update.json", ^create, ^stream} refute Streamer.filtered_by_user?(user, edited) end - - test "it streams posts containing followed hashtags on the 'user' stream", %{ - user: user, - token: oauth_token - } do - hashtag = insert(:hashtag, %{name: "tenshi"}) - other_user = insert(:user) - {:ok, user} = User.follow_hashtag(user, hashtag) - - Streamer.get_topic_and_add_socket("user", user, oauth_token) - {:ok, activity} = CommonAPI.post(other_user, %{status: "hey #tenshi"}) - - assert_receive {:render_with_user, _, "update.json", ^activity, _} - end - - test "should not stream private posts containing followed hashtags on the 'user' stream", %{ - user: user, - token: oauth_token - } do - hashtag = insert(:hashtag, %{name: "tenshi"}) - other_user = insert(:user) - {:ok, user} = User.follow_hashtag(user, hashtag) - - Streamer.get_topic_and_add_socket("user", user, oauth_token) - - {:ok, activity} = - CommonAPI.post(other_user, %{status: "hey #tenshi", visibility: "private"}) - - refute_receive {:render_with_user, _, "update.json", ^activity, _} - end end describe "public streams" do diff --git a/test/support/factory.ex b/test/support/factory.ex index 808f8f887..6ce4decbc 100644 --- a/test/support/factory.ex +++ b/test/support/factory.ex @@ -716,11 +716,4 @@ def delivery_factory(params \\ %{}) do user: user } end - - def hashtag_factory(params \\ %{}) do - %Pleroma.Hashtag{ - name: "test #{sequence(:hashtag_name, & &1)}" - } - |> Map.merge(params) - end end From d55de5debf3645d97ec792e669f1249e62e07191 Mon Sep 17 00:00:00 2001 From: floatingghost Date: Mon, 5 Dec 2022 12:58:48 +0000 Subject: [PATCH 087/631] Remerge of hashtag following (#341) this time with less idiot Co-authored-by: FloatingGhost Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma/pulls/341 --- lib/mix/tasks/pleroma/user.ex | 7 ++ lib/pleroma/hashtag.ex | 27 ++++++ lib/pleroma/user.ex | 58 +++++++++++ lib/pleroma/user/hashtag_follow.ex | 49 ++++++++++ lib/pleroma/web/activity_pub/activity_pub.ex | 27 +++++- .../web/api_spec/operations/tag_operation.ex | 65 +++++++++++++ lib/pleroma/web/api_spec/schemas/tag.ex | 7 +- .../controllers/tag_controller.ex | 47 +++++++++ .../controllers/timeline_controller.ex | 6 ++ .../web/mastodon_api/views/tag_view.ex | 21 ++++ lib/pleroma/web/router.ex | 4 + lib/pleroma/web/streamer.ex | 13 ++- ...0221203232118_add_user_follows_hashtag.exs | 12 +++ test/pleroma/user_test.exs | 70 +++++++++++++ .../web/activity_pub/activity_pub_test.exs | 21 ++++ .../controllers/tag_controller_test.exs | 97 +++++++++++++++++++ test/pleroma/web/streamer_test.exs | 30 ++++++ test/support/factory.ex | 7 ++ 18 files changed, 565 insertions(+), 3 deletions(-) create mode 100644 lib/pleroma/user/hashtag_follow.ex create mode 100644 lib/pleroma/web/api_spec/operations/tag_operation.ex create mode 100644 lib/pleroma/web/mastodon_api/controllers/tag_controller.ex create mode 100644 lib/pleroma/web/mastodon_api/views/tag_view.ex create mode 100644 priv/repo/migrations/20221203232118_add_user_follows_hashtag.exs create mode 100644 test/pleroma/web/mastodon_api/controllers/tag_controller_test.exs diff --git a/lib/mix/tasks/pleroma/user.ex b/lib/mix/tasks/pleroma/user.ex index 278a01acc..dd1cdca5b 100644 --- a/lib/mix/tasks/pleroma/user.ex +++ b/lib/mix/tasks/pleroma/user.ex @@ -471,9 +471,15 @@ def run(["blocking", nickname]) do def run(["timeline_query", nickname]) do start_pleroma() + params = %{local: true} with %User{local: true} = user <- User.get_cached_by_nickname(nickname) do + followed_hashtags = + user + |> User.followed_hashtags() + |> Enum.map(& &1.id) + params = params |> Map.put(:type, ["Create", "Announce"]) @@ -484,6 +490,7 @@ def run(["timeline_query", nickname]) do |> Map.put(:announce_filtering_user, user) |> Map.put(:user, user) |> Map.put(:local_only, params[:local]) + |> Map.put(:hashtags, followed_hashtags) |> Map.delete(:local) _activities = diff --git a/lib/pleroma/hashtag.ex b/lib/pleroma/hashtag.ex index 53e2e9c89..9030ee4e9 100644 --- a/lib/pleroma/hashtag.ex +++ b/lib/pleroma/hashtag.ex @@ -10,6 +10,7 @@ defmodule Pleroma.Hashtag do alias Ecto.Multi alias Pleroma.Hashtag + alias Pleroma.User.HashtagFollow alias Pleroma.Object alias Pleroma.Repo @@ -27,6 +28,14 @@ def normalize_name(name) do |> String.trim() end + def get_by_id(id) do + Repo.get(Hashtag, id) + end + + def get_by_name(name) do + Repo.get_by(Hashtag, name: normalize_name(name)) + end + def get_or_create_by_name(name) do changeset = changeset(%Hashtag{}, %{name: name}) @@ -103,4 +112,22 @@ def delete_unreferenced(ids) do {:ok, deleted_count} end end + + def get_followers(%Hashtag{id: hashtag_id}) do + from(hf in HashtagFollow) + |> where([hf], hf.hashtag_id == ^hashtag_id) + |> join(:inner, [hf], u in assoc(hf, :user)) + |> select([hf, u], u.id) + |> Repo.all() + end + + def get_recipients_for_activity(%Pleroma.Activity{object: %{hashtags: tags}}) + when is_list(tags) do + tags + |> Enum.map(&get_followers/1) + |> List.flatten() + |> Enum.uniq() + end + + def get_recipients_for_activity(_activity), do: [] end diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index b0ab9d0cd..c8262b37b 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -18,6 +18,8 @@ defmodule Pleroma.User do alias Pleroma.Emoji alias Pleroma.FollowingRelationship alias Pleroma.Formatter + alias Pleroma.Hashtag + alias Pleroma.User.HashtagFollow alias Pleroma.HTML alias Pleroma.Keys alias Pleroma.MFA @@ -168,6 +170,12 @@ defmodule Pleroma.User do has_many(:frontend_profiles, Pleroma.Akkoma.FrontendSettingsProfile) + many_to_many(:followed_hashtags, Hashtag, + on_replace: :delete, + on_delete: :delete_all, + join_through: HashtagFollow + ) + for {relationship_type, [ {outgoing_relation, outgoing_relation_target}, @@ -2550,4 +2558,54 @@ def update_last_status_at(user) do _ -> {:error, user} end end + + defp maybe_load_followed_hashtags(%User{followed_hashtags: follows} = user) + when is_list(follows), + do: user + + defp maybe_load_followed_hashtags(%User{} = user) do + followed_hashtags = HashtagFollow.get_by_user(user) + %{user | followed_hashtags: followed_hashtags} + end + + def followed_hashtags(%User{followed_hashtags: follows}) + when is_list(follows), + do: follows + + def followed_hashtags(%User{} = user) do + {:ok, user} = + user + |> maybe_load_followed_hashtags() + |> set_cache() + + user.followed_hashtags + end + + def follow_hashtag(%User{} = user, %Hashtag{} = hashtag) do + Logger.debug("Follow hashtag #{hashtag.name} for user #{user.nickname}") + user = maybe_load_followed_hashtags(user) + + with {:ok, _} <- HashtagFollow.new(user, hashtag), + follows <- HashtagFollow.get_by_user(user), + %User{} = user <- user |> Map.put(:followed_hashtags, follows) do + user + |> set_cache() + end + end + + def unfollow_hashtag(%User{} = user, %Hashtag{} = hashtag) do + Logger.debug("Unfollow hashtag #{hashtag.name} for user #{user.nickname}") + user = maybe_load_followed_hashtags(user) + + with {:ok, _} <- HashtagFollow.delete(user, hashtag), + follows <- HashtagFollow.get_by_user(user), + %User{} = user <- user |> Map.put(:followed_hashtags, follows) do + user + |> set_cache() + end + end + + def following_hashtag?(%User{} = user, %Hashtag{} = hashtag) do + not is_nil(HashtagFollow.get(user, hashtag)) + end end diff --git a/lib/pleroma/user/hashtag_follow.ex b/lib/pleroma/user/hashtag_follow.ex new file mode 100644 index 000000000..43ed93f4d --- /dev/null +++ b/lib/pleroma/user/hashtag_follow.ex @@ -0,0 +1,49 @@ +defmodule Pleroma.User.HashtagFollow do + use Ecto.Schema + import Ecto.Query + import Ecto.Changeset + + alias Pleroma.User + alias Pleroma.Hashtag + alias Pleroma.Repo + + schema "user_follows_hashtag" do + belongs_to(:user, User, type: FlakeId.Ecto.CompatType) + belongs_to(:hashtag, Hashtag) + end + + def changeset(%__MODULE__{} = user_hashtag_follow, attrs) do + user_hashtag_follow + |> cast(attrs, [:user_id, :hashtag_id]) + |> unique_constraint(:hashtag_id, + name: :user_hashtag_follows_user_id_hashtag_id_index, + message: "already following" + ) + |> validate_required([:user_id, :hashtag_id]) + end + + def new(%User{} = user, %Hashtag{} = hashtag) do + %__MODULE__{} + |> changeset(%{user_id: user.id, hashtag_id: hashtag.id}) + |> Repo.insert(on_conflict: :nothing) + end + + def delete(%User{} = user, %Hashtag{} = hashtag) do + with %__MODULE__{} = user_hashtag_follow <- get(user, hashtag) do + Repo.delete(user_hashtag_follow) + else + _ -> {:ok, nil} + end + end + + def get(%User{} = user, %Hashtag{} = hashtag) do + from(hf in __MODULE__) + |> where([hf], hf.user_id == ^user.id and hf.hashtag_id == ^hashtag.id) + |> Repo.one() + end + + def get_by_user(%User{} = user) do + Ecto.assoc(user, :followed_hashtags) + |> Repo.all() + end +end diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index a4f1c7041..3f46a8ecb 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -933,6 +933,31 @@ defp restrict_recipients(query, recipients, user) do ) end + # Essentially, either look for activities addressed to `recipients`, _OR_ ones + # that reference a hashtag that the user follows + # Firstly, two fallbacks in case there's no hashtag constraint, or the user doesn't + # follow any + defp restrict_recipients_or_hashtags(query, recipients, user, nil) do + restrict_recipients(query, recipients, user) + end + + defp restrict_recipients_or_hashtags(query, recipients, user, []) do + restrict_recipients(query, recipients, user) + end + + defp restrict_recipients_or_hashtags(query, recipients, _user, hashtag_ids) do + from([activity, object] in query) + |> join(:left, [activity, object], hto in "hashtags_objects", + on: hto.object_id == object.id, + as: :hto + ) + |> where( + [activity, object, hto: hto], + (hto.hashtag_id in ^hashtag_ids and ^Constants.as_public() in activity.recipients) or + fragment("? && ?", ^recipients, activity.recipients) + ) + end + defp restrict_local(query, %{local_only: true}) do from(activity in query, where: activity.local == true) end @@ -1380,7 +1405,7 @@ def fetch_activities_query(recipients, opts \\ %{}) do |> maybe_preload_report_notes(opts) |> maybe_set_thread_muted_field(opts) |> maybe_order(opts) - |> restrict_recipients(recipients, opts[:user]) + |> restrict_recipients_or_hashtags(recipients, opts[:user], opts[:followed_hashtags]) |> restrict_replies(opts) |> restrict_since(opts) |> restrict_local(opts) diff --git a/lib/pleroma/web/api_spec/operations/tag_operation.ex b/lib/pleroma/web/api_spec/operations/tag_operation.ex new file mode 100644 index 000000000..e22457159 --- /dev/null +++ b/lib/pleroma/web/api_spec/operations/tag_operation.ex @@ -0,0 +1,65 @@ +defmodule Pleroma.Web.ApiSpec.TagOperation do + alias OpenApiSpex.Operation + alias OpenApiSpex.Schema + alias Pleroma.Web.ApiSpec.Schemas.ApiError + alias Pleroma.Web.ApiSpec.Schemas.Tag + + def open_api_operation(action) do + operation = String.to_existing_atom("#{action}_operation") + apply(__MODULE__, operation, []) + end + + def show_operation do + %Operation{ + tags: ["Tags"], + summary: "Hashtag", + description: "View a hashtag", + security: [%{"oAuth" => ["read"]}], + parameters: [id_param()], + operationId: "TagController.show", + responses: %{ + 200 => Operation.response("Hashtag", "application/json", Tag), + 404 => Operation.response("Not Found", "application/json", ApiError) + } + } + end + + def follow_operation do + %Operation{ + tags: ["Tags"], + summary: "Follow a hashtag", + description: "Follow a hashtag", + security: [%{"oAuth" => ["write:follows"]}], + parameters: [id_param()], + operationId: "TagController.follow", + responses: %{ + 200 => Operation.response("Hashtag", "application/json", Tag), + 404 => Operation.response("Not Found", "application/json", ApiError) + } + } + end + + def unfollow_operation do + %Operation{ + tags: ["Tags"], + summary: "Unfollow a hashtag", + description: "Unfollow a hashtag", + security: [%{"oAuth" => ["write:follow"]}], + parameters: [id_param()], + operationId: "TagController.unfollow", + responses: %{ + 200 => Operation.response("Hashtag", "application/json", Tag), + 404 => Operation.response("Not Found", "application/json", ApiError) + } + } + end + + defp id_param do + Operation.parameter( + :id, + :path, + %Schema{type: :string}, + "Name of the hashtag" + ) + end +end diff --git a/lib/pleroma/web/api_spec/schemas/tag.ex b/lib/pleroma/web/api_spec/schemas/tag.ex index 657b675e5..41b5e5c78 100644 --- a/lib/pleroma/web/api_spec/schemas/tag.ex +++ b/lib/pleroma/web/api_spec/schemas/tag.ex @@ -17,11 +17,16 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Tag do type: :string, format: :uri, description: "A link to the hashtag on the instance" + }, + following: %Schema{ + type: :boolean, + description: "Whether the authenticated user is following the hashtag" } }, example: %{ name: "cofe", - url: "https://lain.com/tag/cofe" + url: "https://lain.com/tag/cofe", + following: false } }) end diff --git a/lib/pleroma/web/mastodon_api/controllers/tag_controller.ex b/lib/pleroma/web/mastodon_api/controllers/tag_controller.ex new file mode 100644 index 000000000..b8995eb00 --- /dev/null +++ b/lib/pleroma/web/mastodon_api/controllers/tag_controller.ex @@ -0,0 +1,47 @@ +defmodule Pleroma.Web.MastodonAPI.TagController do + @moduledoc "Hashtag routes for mastodon API" + use Pleroma.Web, :controller + + alias Pleroma.User + alias Pleroma.Hashtag + + plug(Pleroma.Web.ApiSpec.CastAndValidate) + plug(Pleroma.Web.Plugs.OAuthScopesPlug, %{scopes: ["read"]} when action in [:show]) + + plug( + Pleroma.Web.Plugs.OAuthScopesPlug, + %{scopes: ["write:follows"]} when action in [:follow, :unfollow] + ) + + defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.TagOperation + + def show(conn, %{id: id}) do + with %Hashtag{} = hashtag <- Hashtag.get_by_name(id) do + render(conn, "show.json", tag: hashtag, for_user: conn.assigns.user) + else + _ -> conn |> render_error(:not_found, "Hashtag not found") + end + end + + def follow(conn, %{id: id}) do + with %Hashtag{} = hashtag <- Hashtag.get_by_name(id), + %User{} = user <- conn.assigns.user, + {:ok, _} <- + User.follow_hashtag(user, hashtag) do + render(conn, "show.json", tag: hashtag, for_user: user) + else + _ -> render_error(conn, :not_found, "Hashtag not found") + end + end + + def unfollow(conn, %{id: id}) do + with %Hashtag{} = hashtag <- Hashtag.get_by_name(id), + %User{} = user <- conn.assigns.user, + {:ok, _} <- + User.unfollow_hashtag(user, hashtag) do + render(conn, "show.json", tag: hashtag, for_user: user) + else + _ -> render_error(conn, :not_found, "Hashtag not found") + end + end +end diff --git a/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex b/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex index 5f8acb2df..2d0e36420 100644 --- a/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex @@ -41,6 +41,11 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do # GET /api/v1/timelines/home def home(%{assigns: %{user: user}} = conn, params) do + followed_hashtags = + user + |> User.followed_hashtags() + |> Enum.map(& &1.id) + params = params |> Map.put(:type, ["Create", "Announce"]) @@ -50,6 +55,7 @@ def home(%{assigns: %{user: user}} = conn, params) do |> Map.put(:announce_filtering_user, user) |> Map.put(:user, user) |> Map.put(:local_only, params[:local]) + |> Map.put(:followed_hashtags, followed_hashtags) |> Map.delete(:local) activities = diff --git a/lib/pleroma/web/mastodon_api/views/tag_view.ex b/lib/pleroma/web/mastodon_api/views/tag_view.ex new file mode 100644 index 000000000..6e491c261 --- /dev/null +++ b/lib/pleroma/web/mastodon_api/views/tag_view.ex @@ -0,0 +1,21 @@ +defmodule Pleroma.Web.MastodonAPI.TagView do + use Pleroma.Web, :view + alias Pleroma.User + alias Pleroma.Web.Router.Helpers + + def render("show.json", %{tag: tag, for_user: user}) do + following = + with %User{} <- user do + User.following_hashtag?(user, tag) + else + _ -> false + end + + %{ + name: tag.name, + url: Helpers.tag_feed_url(Pleroma.Web.Endpoint, :feed, tag.name), + history: [], + following: following + } + end +end diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 71a9e4d29..a34dd26ce 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -598,6 +598,10 @@ defmodule Pleroma.Web.Router do get("/announcements", AnnouncementController, :index) post("/announcements/:id/dismiss", AnnouncementController, :mark_read) + + get("/tags/:id", TagController, :show) + post("/tags/:id/follow", TagController, :follow) + post("/tags/:id/unfollow", TagController, :unfollow) end scope "/api/web", Pleroma.Web do diff --git a/lib/pleroma/web/streamer.ex b/lib/pleroma/web/streamer.ex index c03e7fc30..f009fbd9e 100644 --- a/lib/pleroma/web/streamer.ex +++ b/lib/pleroma/web/streamer.ex @@ -17,6 +17,7 @@ defmodule Pleroma.Web.Streamer do alias Pleroma.Web.OAuth.Token alias Pleroma.Web.Plugs.OAuthScopesPlug alias Pleroma.Web.StreamerView + require Pleroma.Constants @mix_env Mix.env() @registry Pleroma.Web.StreamerRegistry @@ -252,7 +253,17 @@ defp do_stream("user", item) do User.get_recipients_from_activity(item) |> Enum.map(fn %{id: id} -> "user:#{id}" end) - Enum.each(recipient_topics, fn topic -> + hashtag_recipients = + if Pleroma.Constants.as_public() in item.recipients do + Pleroma.Hashtag.get_recipients_for_activity(item) + |> Enum.map(fn id -> "user:#{id}" end) + else + [] + end + + all_recipients = Enum.uniq(recipient_topics ++ hashtag_recipients) + + Enum.each(all_recipients, fn topic -> push_to_socket(topic, item) end) end diff --git a/priv/repo/migrations/20221203232118_add_user_follows_hashtag.exs b/priv/repo/migrations/20221203232118_add_user_follows_hashtag.exs new file mode 100644 index 000000000..27fff2586 --- /dev/null +++ b/priv/repo/migrations/20221203232118_add_user_follows_hashtag.exs @@ -0,0 +1,12 @@ +defmodule Pleroma.Repo.Migrations.AddUserFollowsHashtag do + use Ecto.Migration + + def change do + create table(:user_follows_hashtag) do + add(:hashtag_id, references(:hashtags)) + add(:user_id, references(:users, type: :uuid, on_delete: :delete_all)) + end + + create(unique_index(:user_follows_hashtag, [:user_id, :hashtag_id])) + end +end diff --git a/test/pleroma/user_test.exs b/test/pleroma/user_test.exs index 44763daf7..cc6634aba 100644 --- a/test/pleroma/user_test.exs +++ b/test/pleroma/user_test.exs @@ -2679,4 +2679,74 @@ test "should report error on non-existing alias" do assert user.ap_id in user3_updated.also_known_as end end + + describe "follow_hashtag/2" do + test "should follow a hashtag" do + user = insert(:user) + hashtag = insert(:hashtag) + + assert {:ok, _} = user |> User.follow_hashtag(hashtag) + + user = User.get_cached_by_ap_id(user.ap_id) + + assert user.followed_hashtags |> Enum.count() == 1 + assert hashtag.name in Enum.map(user.followed_hashtags, fn %{name: name} -> name end) + end + + test "should not follow a hashtag twice" do + user = insert(:user) + hashtag = insert(:hashtag) + + assert {:ok, _} = user |> User.follow_hashtag(hashtag) + + assert {:ok, _} = user |> User.follow_hashtag(hashtag) + + user = User.get_cached_by_ap_id(user.ap_id) + + assert user.followed_hashtags |> Enum.count() == 1 + assert hashtag.name in Enum.map(user.followed_hashtags, fn %{name: name} -> name end) + end + + test "can follow multiple hashtags" do + user = insert(:user) + hashtag = insert(:hashtag) + other_hashtag = insert(:hashtag) + + assert {:ok, _} = user |> User.follow_hashtag(hashtag) + assert {:ok, _} = user |> User.follow_hashtag(other_hashtag) + + user = User.get_cached_by_ap_id(user.ap_id) + + assert user.followed_hashtags |> Enum.count() == 2 + assert hashtag.name in Enum.map(user.followed_hashtags, fn %{name: name} -> name end) + assert other_hashtag.name in Enum.map(user.followed_hashtags, fn %{name: name} -> name end) + end + end + + describe "unfollow_hashtag/2" do + test "should unfollow a hashtag" do + user = insert(:user) + hashtag = insert(:hashtag) + + assert {:ok, _} = user |> User.follow_hashtag(hashtag) + assert {:ok, _} = user |> User.unfollow_hashtag(hashtag) + + user = User.get_cached_by_ap_id(user.ap_id) + + assert user.followed_hashtags |> Enum.count() == 0 + end + + test "should not error when trying to unfollow a hashtag twice" do + user = insert(:user) + hashtag = insert(:hashtag) + + assert {:ok, _} = user |> User.follow_hashtag(hashtag) + assert {:ok, _} = user |> User.unfollow_hashtag(hashtag) + assert {:ok, _} = user |> User.unfollow_hashtag(hashtag) + + user = User.get_cached_by_ap_id(user.ap_id) + + assert user.followed_hashtags |> Enum.count() == 0 + end + end end diff --git a/test/pleroma/web/activity_pub/activity_pub_test.exs b/test/pleroma/web/activity_pub/activity_pub_test.exs index 8d39b1076..1ba1ad96a 100644 --- a/test/pleroma/web/activity_pub/activity_pub_test.exs +++ b/test/pleroma/web/activity_pub/activity_pub_test.exs @@ -719,6 +719,27 @@ test "retrieve the activities for certain recipients" do end end + describe "fetch activities for followed hashtags" do + test "it should return public activities that reference a given hashtag" do + hashtag = insert(:hashtag, name: "tenshi") + user = insert(:user) + other_user = insert(:user) + + {:ok, normally_visible} = CommonAPI.post(other_user, %{status: "hello :)", visibility: "public"}) + {:ok, public} = CommonAPI.post(user, %{status: "maji #tenshi", visibility: "public"}) + {:ok, _unrelated} = CommonAPI.post(user, %{status: "dai #tensh", visibility: "public"}) + {:ok, unlisted} = CommonAPI.post(user, %{status: "maji #tenshi", visibility: "unlisted"}) + {:ok, _private} = CommonAPI.post(user, %{status: "maji #tenshi", visibility: "private"}) + + activities = ActivityPub.fetch_activities([other_user.follower_address], %{followed_hashtags: [hashtag.id]}) + assert length(activities) == 3 + normal_id = normally_visible.id + public_id = public.id + unlisted_id = unlisted.id + assert [%{id: ^normal_id}, %{id: ^public_id}, %{id: ^unlisted_id}] = activities + end + end + describe "fetch activities in context" do test "retrieves activities that have a given context" do {:ok, activity} = ActivityBuilder.insert(%{"type" => "Create", "context" => "2hu"}) diff --git a/test/pleroma/web/mastodon_api/controllers/tag_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/tag_controller_test.exs new file mode 100644 index 000000000..a1b73ad78 --- /dev/null +++ b/test/pleroma/web/mastodon_api/controllers/tag_controller_test.exs @@ -0,0 +1,97 @@ +defmodule Pleroma.Web.MastodonAPI.TagControllerTest do + use Pleroma.Web.ConnCase + + import Pleroma.Factory + import Tesla.Mock + + alias Pleroma.User + + setup do + mock(fn env -> apply(HttpRequestMock, :request, [env]) end) + :ok + end + + describe "GET /api/v1/tags/:id" do + test "returns 200 with tag" do + %{user: user, conn: conn} = oauth_access(["read"]) + + tag = insert(:hashtag, name: "jubjub") + {:ok, _user} = User.follow_hashtag(user, tag) + + response = + conn + |> get("/api/v1/tags/jubjub") + |> json_response_and_validate_schema(200) + + assert %{ + "name" => "jubjub", + "url" => "http://localhost:4001/tags/jubjub", + "history" => [], + "following" => true + } = response + end + + test "returns 404 with unknown tag" do + %{conn: conn} = oauth_access(["read"]) + + conn + |> get("/api/v1/tags/jubjub") + |> json_response_and_validate_schema(404) + end + end + + describe "POST /api/v1/tags/:id/follow" do + test "should follow a hashtag" do + %{user: user, conn: conn} = oauth_access(["write:follows"]) + hashtag = insert(:hashtag, name: "jubjub") + + response = + conn + |> post("/api/v1/tags/jubjub/follow") + |> json_response_and_validate_schema(200) + + assert response["following"] == true + user = User.get_cached_by_ap_id(user.ap_id) + assert User.following_hashtag?(user, hashtag) + end + + test "should 404 if hashtag doesn't exist" do + %{conn: conn} = oauth_access(["write:follows"]) + + response = + conn + |> post("/api/v1/tags/rubrub/follow") + |> json_response_and_validate_schema(404) + + assert response["error"] == "Hashtag not found" + end + end + + describe "POST /api/v1/tags/:id/unfollow" do + test "should unfollow a hashtag" do + %{user: user, conn: conn} = oauth_access(["write:follows"]) + hashtag = insert(:hashtag, name: "jubjub") + {:ok, user} = User.follow_hashtag(user, hashtag) + + response = + conn + |> post("/api/v1/tags/jubjub/unfollow") + |> json_response_and_validate_schema(200) + + assert response["following"] == false + user = User.get_cached_by_ap_id(user.ap_id) + refute User.following_hashtag?(user, hashtag) + end + + test "should 404 if hashtag doesn't exist" do + %{conn: conn} = oauth_access(["write:follows"]) + + response = + conn + |> post("/api/v1/tags/rubrub/unfollow") + |> json_response_and_validate_schema(404) + + assert response["error"] == "Hashtag not found" + end + end +end diff --git a/test/pleroma/web/streamer_test.exs b/test/pleroma/web/streamer_test.exs index a9db5a015..b07c16faa 100644 --- a/test/pleroma/web/streamer_test.exs +++ b/test/pleroma/web/streamer_test.exs @@ -410,6 +410,36 @@ test "it streams own edits in the 'user' stream", %{user: user, token: oauth_tok assert_receive {:render_with_user, _, "status_update.json", ^create, ^stream} refute Streamer.filtered_by_user?(user, edited) end + + test "it streams posts containing followed hashtags on the 'user' stream", %{ + user: user, + token: oauth_token + } do + hashtag = insert(:hashtag, %{name: "tenshi"}) + other_user = insert(:user) + {:ok, user} = User.follow_hashtag(user, hashtag) + + Streamer.get_topic_and_add_socket("user", user, oauth_token) + {:ok, activity} = CommonAPI.post(other_user, %{status: "hey #tenshi"}) + + assert_receive {:render_with_user, _, "update.json", ^activity, _} + end + + test "should not stream private posts containing followed hashtags on the 'user' stream", %{ + user: user, + token: oauth_token + } do + hashtag = insert(:hashtag, %{name: "tenshi"}) + other_user = insert(:user) + {:ok, user} = User.follow_hashtag(user, hashtag) + + Streamer.get_topic_and_add_socket("user", user, oauth_token) + + {:ok, activity} = + CommonAPI.post(other_user, %{status: "hey #tenshi", visibility: "private"}) + + refute_receive {:render_with_user, _, "update.json", ^activity, _} + end end describe "public streams" do diff --git a/test/support/factory.ex b/test/support/factory.ex index 6ce4decbc..808f8f887 100644 --- a/test/support/factory.ex +++ b/test/support/factory.ex @@ -716,4 +716,11 @@ def delivery_factory(params \\ %{}) do user: user } end + + def hashtag_factory(params \\ %{}) do + %Pleroma.Hashtag{ + name: "test #{sequence(:hashtag_name, & &1)}" + } + |> Map.merge(params) + end end From c62e1e3ad51522e283ce11f0ff5e033e70dfa719 Mon Sep 17 00:00:00 2001 From: floatingghost Date: Mon, 5 Dec 2022 13:39:27 +0000 Subject: [PATCH 088/631] varnish config/docs (#342) Co-authored-by: Mark Felder Co-authored-by: FloatingGhost Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma/pulls/342 --- docs/Pipfile.lock | 104 +++++++++--------- .../{ => integrations}/howto_ejabberd.md | 0 .../{ => integrations}/howto_mongooseim.md | 0 .../{ => optimisation}/optimizing_beam.md | 0 .../optimisation/varnish_cache.md | 54 +++++++++ docs/mkdocs.yml | 8 +- installation/akkoma.vcl | 41 +------ 7 files changed, 119 insertions(+), 88 deletions(-) rename docs/docs/configuration/{ => integrations}/howto_ejabberd.md (100%) rename docs/docs/configuration/{ => integrations}/howto_mongooseim.md (100%) rename docs/docs/configuration/{ => optimisation}/optimizing_beam.md (100%) create mode 100644 docs/docs/configuration/optimisation/varnish_cache.md diff --git a/docs/Pipfile.lock b/docs/Pipfile.lock index c7b8f50db..4cd8c59b9 100644 --- a/docs/Pipfile.lock +++ b/docs/Pipfile.lock @@ -19,7 +19,7 @@ "sha256:0d9c601124e5a6ba9712dbc60d9c53c21e34f5f641fe83002317394311bdce14", "sha256:90c1a32f1d68f940488354e36370f6cca89f0f106db09518524c88d6ed83f382" ], - "markers": "python_version >= '3.6'", + "markers": "python_full_version >= '3.6.0'", "version": "==2022.9.24" }, "charset-normalizer": { @@ -27,7 +27,7 @@ "sha256:5a3d016c7c547f69d6f81fb0db9449ce888b418b5b9952cc5e6e66843e9dd845", "sha256:83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f" ], - "markers": "python_version >= '3.6'", + "markers": "python_full_version >= '3.6.0'", "version": "==2.1.1" }, "click": { @@ -66,15 +66,16 @@ "sha256:cbb516f16218e643d8e0a95b309f77eb118cb138d39a4f27851e6a63581db874", "sha256:f5da449a6e1c989a4cea2631aa8ee67caa5a2ef855d551c88f9e309f4634c621" ], - "markers": "python_version >= '3.6'", + "markers": "python_full_version >= '3.6.0'", "version": "==3.3.7" }, "markdown-include": { "hashes": [ - "sha256:a06183b7c7225e73112737acdc6fe0ac0686c39457234eeb5ede23881fed001d" + "sha256:b8f6b6f4e8b506cbe773d7e26c74a97d1354c35f3a3452d3449140a8f578d665", + "sha256:d12fb51500c46334a53608635035c78b7d8ad7f772566f70b8a6a9b2ef2ddbf5" ], "index": "pypi", - "version": "==0.7.0" + "version": "==0.8.0" }, "markupsafe": { "hashes": [ @@ -127,7 +128,7 @@ "sha256:0096d52e9dad9939c3d975a774666af186eda617e6ca84df4c94dec30004f2a8", "sha256:70775750742b25c0d8f36c55aed03d24c3384d17c951b3175d898bd778ef0307" ], - "markers": "python_version >= '3.6'", + "markers": "python_full_version >= '3.6.0'", "version": "==1.3.4" }, "mkdocs": { @@ -140,26 +141,26 @@ }, "mkdocs-material": { "hashes": [ - "sha256:143ea55843b3747b640e1110824d91e8a4c670352380e166e64959f9abe98862", - "sha256:45eeabb23d2caba8fa3b85c91d9ec8e8b22add716e9bba8faf16d56af8aa5622" + "sha256:b0ea0513fd8cab323e8a825d6692ea07fa83e917bb5db042e523afecc7064ab7", + "sha256:c907b4b052240a5778074a30a78f31a1f8ff82d7012356dc26898b97559f082e" ], "index": "pypi", - "version": "==8.5.9" + "version": "==8.5.11" }, "mkdocs-material-extensions": { "hashes": [ - "sha256:96ca979dae66d65c2099eefe189b49d5ac62f76afb59c38e069ffc7cf3c131ec", - "sha256:bcc2e5fc70c0ec50e59703ee6e639d87c7e664c0c441c014ea84461a90f1e902" + "sha256:9c003da71e2cc2493d910237448c672e00cefc800d3d6ae93d2fc69979e3bd93", + "sha256:e41d9f38e4798b6617ad98ca8f7f1157b1e4385ac1459ca1e4ea219b556df945" ], "markers": "python_version >= '3.7'", - "version": "==1.1" + "version": "==1.1.1" }, "packaging": { "hashes": [ "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb", "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522" ], - "markers": "python_version >= '3.6'", + "markers": "python_full_version >= '3.6.0'", "version": "==21.3" }, "pygments": { @@ -167,16 +168,16 @@ "sha256:56a8508ae95f98e2b9bdf93a6be5ae3f7d8af858b43e02c5a2ff083726be40c1", "sha256:f643f331ab57ba3c9d89212ee4a2dabc6e94f117cf4eefde99a0574720d14c42" ], - "markers": "python_version >= '3.6'", + "markers": "python_full_version >= '3.6.0'", "version": "==2.13.0" }, "pymdown-extensions": { "hashes": [ - "sha256:1bd4a173095ef8c433b831af1f3cb13c10883be0c100ae613560668e594651f7", - "sha256:8e62688a8b1128acd42fa823f3d429d22f4284b5e6dd4d3cd56721559a5a211b" + "sha256:0f8fb7b74a37a61cc34e90b2c91865458b713ec774894ffad64353a5fce85cfc", + "sha256:ac698c15265680db5eb13cd4342abfcde2079ac01e5486028f47a1b41547b859" ], "markers": "python_version >= '3.7'", - "version": "==9.8" + "version": "==9.9" }, "pyparsing": { "hashes": [ @@ -237,7 +238,7 @@ "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174", "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5" ], - "markers": "python_version >= '3.6'", + "markers": "python_full_version >= '3.6.0'", "version": "==6.0" }, "pyyaml-env-tag": { @@ -245,7 +246,7 @@ "sha256:70092675bda14fdec33b31ba77e7543de9ddc88f2e5b99160396572d11525bdb", "sha256:af31106dec8a4d68c60207c1886031cbf839b68aa7abccdb19868200532c2069" ], - "markers": "python_version >= '3.6'", + "markers": "python_full_version >= '3.6.0'", "version": "==0.1" }, "requests": { @@ -266,42 +267,45 @@ }, "urllib3": { "hashes": [ - "sha256:3fa96cf423e6987997fc326ae8df396db2a8b7c667747d47ddd8ecba91f4a74e", - "sha256:b930dd878d5a8afb066a637fbb35144fe7901e3b209d1cd4f524bd0e9deee997" + "sha256:47cc05d99aaa09c9e72ed5809b60e7ba354e64b59c9c173ac3018642d8bb41fc", + "sha256:c083dd0dce68dbfbe1129d5271cb90f9447dea7d52097c6e0126120c521ddea8" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5' and python_version < '4'", - "version": "==1.26.12" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", + "version": "==1.26.13" }, "watchdog": { "hashes": [ - "sha256:083171652584e1b8829581f965b9b7723ca5f9a2cd7e20271edf264cfd7c1412", - "sha256:117ffc6ec261639a0209a3252546b12800670d4bf5f84fbd355957a0595fe654", - "sha256:186f6c55abc5e03872ae14c2f294a153ec7292f807af99f57611acc8caa75306", - "sha256:195fc70c6e41237362ba720e9aaf394f8178bfc7fa68207f112d108edef1af33", - "sha256:226b3c6c468ce72051a4c15a4cc2ef317c32590d82ba0b330403cafd98a62cfd", - "sha256:247dcf1df956daa24828bfea5a138d0e7a7c98b1a47cf1fa5b0c3c16241fcbb7", - "sha256:255bb5758f7e89b1a13c05a5bceccec2219f8995a3a4c4d6968fe1de6a3b2892", - "sha256:43ce20ebb36a51f21fa376f76d1d4692452b2527ccd601950d69ed36b9e21609", - "sha256:4f4e1c4aa54fb86316a62a87b3378c025e228178d55481d30d857c6c438897d6", - "sha256:5952135968519e2447a01875a6f5fc8c03190b24d14ee52b0f4b1682259520b1", - "sha256:64a27aed691408a6abd83394b38503e8176f69031ca25d64131d8d640a307591", - "sha256:6b17d302850c8d412784d9246cfe8d7e3af6bcd45f958abb2d08a6f8bedf695d", - "sha256:70af927aa1613ded6a68089a9262a009fbdf819f46d09c1a908d4b36e1ba2b2d", - "sha256:7a833211f49143c3d336729b0020ffd1274078e94b0ae42e22f596999f50279c", - "sha256:8250546a98388cbc00c3ee3cc5cf96799b5a595270dfcfa855491a64b86ef8c3", - "sha256:97f9752208f5154e9e7b76acc8c4f5a58801b338de2af14e7e181ee3b28a5d39", - "sha256:9f05a5f7c12452f6a27203f76779ae3f46fa30f1dd833037ea8cbc2887c60213", - "sha256:a735a990a1095f75ca4f36ea2ef2752c99e6ee997c46b0de507ba40a09bf7330", - "sha256:ad576a565260d8f99d97f2e64b0f97a48228317095908568a9d5c786c829d428", - "sha256:b530ae007a5f5d50b7fbba96634c7ee21abec70dc3e7f0233339c81943848dc1", - "sha256:bfc4d351e6348d6ec51df007432e6fe80adb53fd41183716017026af03427846", - "sha256:d3dda00aca282b26194bdd0adec21e4c21e916956d972369359ba63ade616153", - "sha256:d9820fe47c20c13e3c9dd544d3706a2a26c02b2b43c993b62fcd8011bcc0adb3", - "sha256:ed80a1628cee19f5cfc6bb74e173f1b4189eb532e705e2a13e3250312a62e0c9", - "sha256:ee3e38a6cc050a8830089f79cbec8a3878ec2fe5160cdb2dc8ccb6def8552658" + "sha256:1893d425ef4fb4f129ee8ef72226836619c2950dd0559bba022b0818c63a7b60", + "sha256:1a410dd4d0adcc86b4c71d1317ba2ea2c92babaf5b83321e4bde2514525544d5", + "sha256:1f2b0665c57358ce9786f06f5475bc083fea9d81ecc0efa4733fd0c320940a37", + "sha256:1f8eca9d294a4f194ce9df0d97d19b5598f310950d3ac3dd6e8d25ae456d4c8a", + "sha256:27e49268735b3c27310883012ab3bd86ea0a96dcab90fe3feb682472e30c90f3", + "sha256:28704c71afdb79c3f215c90231e41c52b056ea880b6be6cee035c6149d658ed1", + "sha256:2ac0bd7c206bb6df78ef9e8ad27cc1346f2b41b1fef610395607319cdab89bc1", + "sha256:2af1a29fd14fc0a87fb6ed762d3e1ae5694dcde22372eebba50e9e5be47af03c", + "sha256:3a048865c828389cb06c0bebf8a883cec3ae58ad3e366bcc38c61d8455a3138f", + "sha256:441024df19253bb108d3a8a5de7a186003d68564084576fecf7333a441271ef7", + "sha256:56fb3f40fc3deecf6e518303c7533f5e2a722e377b12507f6de891583f1b48aa", + "sha256:619d63fa5be69f89ff3a93e165e602c08ed8da402ca42b99cd59a8ec115673e1", + "sha256:74535e955359d79d126885e642d3683616e6d9ab3aae0e7dcccd043bd5a3ff4f", + "sha256:76a2743402b794629a955d96ea2e240bd0e903aa26e02e93cd2d57b33900962b", + "sha256:83cf8bc60d9c613b66a4c018051873d6273d9e45d040eed06d6a96241bd8ec01", + "sha256:920a4bda7daa47545c3201a3292e99300ba81ca26b7569575bd086c865889090", + "sha256:9e99c1713e4436d2563f5828c8910e5ff25abd6ce999e75f15c15d81d41980b6", + "sha256:a5bd9e8656d07cae89ac464ee4bcb6f1b9cecbedc3bf1334683bed3d5afd39ba", + "sha256:ad0150536469fa4b693531e497ffe220d5b6cd76ad2eda474a5e641ee204bbb6", + "sha256:af4b5c7ba60206759a1d99811b5938ca666ea9562a1052b410637bb96ff97512", + "sha256:c7bd98813d34bfa9b464cf8122e7d4bec0a5a427399094d2c17dd5f70d59bc61", + "sha256:ceaa9268d81205876bedb1069f9feab3eccddd4b90d9a45d06a0df592a04cae9", + "sha256:cf05e6ff677b9655c6e9511d02e9cc55e730c4e430b7a54af9c28912294605a4", + "sha256:d0fb5f2b513556c2abb578c1066f5f467d729f2eb689bc2db0739daf81c6bb7e", + "sha256:d6ae890798a3560688b441ef086bb66e87af6b400a92749a18b856a134fc0318", + "sha256:e5aed2a700a18c194c39c266900d41f3db0c1ebe6b8a0834b9995c835d2ca66e", + "sha256:e722755d995035dd32177a9c633d158f2ec604f2a358b545bba5bed53ab25bca", + "sha256:ed91c3ccfc23398e7aa9715abf679d5c163394b8cad994f34f156d57a7c163dc" ], - "markers": "python_version >= '3.6'", - "version": "==2.1.9" + "markers": "python_full_version >= '3.6.0'", + "version": "==2.2.0" } }, "develop": {} diff --git a/docs/docs/configuration/howto_ejabberd.md b/docs/docs/configuration/integrations/howto_ejabberd.md similarity index 100% rename from docs/docs/configuration/howto_ejabberd.md rename to docs/docs/configuration/integrations/howto_ejabberd.md diff --git a/docs/docs/configuration/howto_mongooseim.md b/docs/docs/configuration/integrations/howto_mongooseim.md similarity index 100% rename from docs/docs/configuration/howto_mongooseim.md rename to docs/docs/configuration/integrations/howto_mongooseim.md diff --git a/docs/docs/configuration/optimizing_beam.md b/docs/docs/configuration/optimisation/optimizing_beam.md similarity index 100% rename from docs/docs/configuration/optimizing_beam.md rename to docs/docs/configuration/optimisation/optimizing_beam.md diff --git a/docs/docs/configuration/optimisation/varnish_cache.md b/docs/docs/configuration/optimisation/varnish_cache.md new file mode 100644 index 000000000..1598354f5 --- /dev/null +++ b/docs/docs/configuration/optimisation/varnish_cache.md @@ -0,0 +1,54 @@ +# Using a Varnish Cache + +Varnish is a layer that sits between your web server and your backend application - +it does something similar to nginx caching, but tends to be optimised for speed over +all else. + +To set up a varnish cache, first you'll need to install varnish. + +This will vary by distribution, and since this is a rather advanced guide, +no copy-paste instructions are provided. It's probably in your distribution's +package manager, though. `apt-get install varnish` and so on. + +Once you have varnish installed, you'll need to configure it to work with akkoma. + +Copy the configuration file to the varnish configuration directory: + + cp installation/akkoma.vcl /etc/varnish/akkoma.vcl + +You may want to check if varnish added a `default.vcl` file to the same directory, +if so you can just remove it without issue. + +Then boot up varnish, probably `systemctl start varnish` or `service varnish start`. + +Now you should be able to `curl -D- localhost:6081` and see a bunch of +akkoma javascript. + +Once that's out of the way, we can point our webserver at varnish. This + +=== "Nginx" + + upstream phoenix { + server 127.0.0.1:6081 max_fails=5 fail_timeout=60s; + } + + +=== "Caddy" + + reverse_proxy 127.0.0.1:6081 + +Now hopefully it all works + +If you get a HTTPS redirect loop, you may need to remove this part of the VCL + +```vcl +if (std.port(server.ip) != 443) { + set req.http.X-Forwarded-Proto = "http"; + set req.http.x-redir = "https://" + req.http.host + req.url; + return (synth(750, "")); +} else { + set req.http.X-Forwarded-Proto = "https"; +} +``` + +This will allow your webserver alone to handle redirects. \ No newline at end of file diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index c19439942..a70dac1fc 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -7,7 +7,10 @@ theme: font: false logo: 'images/akko_badday.png' features: - - tabs + - navigation.tabs + - toc.follow + - navigation.instant + - navigation.sections palette: primary: 'deep purple' accent: 'blue grey' @@ -31,7 +34,8 @@ markdown_extensions: - pymdownx.tasklist: custom_checkbox: true - pymdownx.superfences - - pymdownx.tabbed + - pymdownx.tabbed: + alternate_style: true - pymdownx.details - markdown_include.include: base_path: docs diff --git a/installation/akkoma.vcl b/installation/akkoma.vcl index 4752510ea..4eb2f3cfa 100644 --- a/installation/akkoma.vcl +++ b/installation/akkoma.vcl @@ -1,4 +1,5 @@ # Recommended varnishncsa logging format: '%h %l %u %t "%m %{X-Forwarded-Proto}i://%{Host}i%U%q %H" %s %b "%{Referer}i" "%{User-agent}i"' +# Please use Varnish 7.0+ for proper Range Requests / Chunked encoding support vcl 4.1; import std; @@ -22,11 +23,6 @@ sub vcl_recv { set req.http.X-Forwarded-Proto = "https"; } - # CHUNKED SUPPORT - if (req.http.Range ~ "bytes=") { - set req.http.x-range = req.http.Range; - } - # Pipe if WebSockets request is coming through if (req.http.upgrade ~ "(?i)websocket") { return (pipe); @@ -35,9 +31,9 @@ sub vcl_recv { # Allow purging of the cache if (req.method == "PURGE") { if (!client.ip ~ purge) { - return(synth(405,"Not allowed.")); + return (synth(405,"Not allowed.")); } - return(purge); + return (purge); } } @@ -53,17 +49,11 @@ sub vcl_backend_response { return (retry); } - # CHUNKED SUPPORT - if (bereq.http.x-range ~ "bytes=" && beresp.status == 206) { - set beresp.ttl = 10m; - set beresp.http.CR = beresp.http.content-range; - } - # Bypass cache for large files # 50000000 ~ 50MB if (std.integer(beresp.http.content-length, 0) > 50000000) { set beresp.uncacheable = true; - return(deliver); + return (deliver); } # Don't cache objects that require authentication @@ -94,7 +84,7 @@ sub vcl_synth { if (resp.status == 750) { set resp.status = 301; set resp.http.Location = req.http.x-redir; - return(deliver); + return (deliver); } } @@ -106,25 +96,12 @@ sub vcl_pipe { } } -sub vcl_hash { - # CHUNKED SUPPORT - if (req.http.x-range ~ "bytes=") { - hash_data(req.http.x-range); - unset req.http.Range; - } -} - sub vcl_backend_fetch { # Be more lenient for slow servers on the fediverse if (bereq.url ~ "^/proxy/") { set bereq.first_byte_timeout = 300s; } - # CHUNKED SUPPORT - if (bereq.http.x-range) { - set bereq.http.Range = bereq.http.x-range; - } - if (bereq.retries == 0) { # Clean up the X-Varnish-Backend-503 flag that is used internally # to mark broken backend responses that should be retried. @@ -143,14 +120,6 @@ sub vcl_backend_fetch { } } -sub vcl_deliver { - # CHUNKED SUPPORT - if (resp.http.CR) { - set resp.http.Content-Range = resp.http.CR; - unset resp.http.CR; - } -} - sub vcl_backend_error { # Retry broken backend responses. set bereq.http.X-Varnish-Backend-503 = "1"; From b70a60c6c5f7737c7ae044a4ec7cbfe17ae00286 Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Mon, 5 Dec 2022 13:45:36 +0000 Subject: [PATCH 089/631] Doc branding --- docs/docs/images/akko_badday.png | Bin 15791 -> 0 bytes docs/docs/images/favicon.ico | Bin 0 -> 67646 bytes docs/docs/images/favicon.png | Bin 0 -> 5028 bytes docs/docs/images/logo.png | Bin 0 -> 12555 bytes docs/mkdocs.yml | 4 ++-- 5 files changed, 2 insertions(+), 2 deletions(-) delete mode 100644 docs/docs/images/akko_badday.png create mode 100644 docs/docs/images/favicon.ico create mode 100755 docs/docs/images/favicon.png create mode 100755 docs/docs/images/logo.png diff --git a/docs/docs/images/akko_badday.png b/docs/docs/images/akko_badday.png deleted file mode 100644 index b79c67dae438a291dcd6bcdbdd7295f27bd413d9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15791 zcmZ{Lbx<757wrOzyL)h02(tJBA-FBR5WI9R{#K;_&`5y-Q+xXl8Rb@r) zB0pR6e=ch1El#mUlYr!TQ|Oa;6+e`h4NWgTxY9~IeDG2F)TdGXZPG4knwd7;4? z$fYEq1OzZ?#UNRXB56r>_h$8{R^yl@KjhN`b4;WXoLJavv2@UGo~E>j)6qT2$E0|#jsHA3lHNlAL&PrZylqNM9D71gOX}oI zx3N>!j@VFJj#a4Ktc5LK6v~ z(nIa7CeJg@^bF=e8Y>bYFw{Ij;>#oEh1J@Fo|KhulMyE^_kUx&{b2meEFG&@QcMj% zWT&8-yCFGzlAd&m9OhlB_@I8Ci%=oQr&>t zfs@CDH~a=C1Z;v&3xNp(%Sfhn1!x?8T5$P$&s$MZ?3{c5#2J0 z-4RU;hGj*;lJ~oHizz})J=cB8{ML*y3eW6wn0aEfbFh=GkK@A1>;S&GuBne))2R)p zlJe|d90R{-4gjn@RYyfohigc|cFxZfELRW)bG_Y`0$w9j4dze^wE0N8tdTj~0$1Fe z>TF|*L2gxcR498!v6L{56eQJ%WN_4|qh64A5I_tCu#7%=^26ME&O8liWRfNzSek~Hy${yeN%Bi%Bj;zZCI_AP2fcI z({ZtUXE{r&T)cf95cF-FJe<&^nS`#<)X})vu-Q~$C;JMC*>kit2i*Hh01@>2qm8h~ zDmg&JVm($$iUCUGS3K9)a6m@qinCQ!o=q&etD0+P7GA7MWw2FT+&SZB{W$0FbEFHN z2Mn<#MEKD}9W8B>2y_MNJdToVdup3+Y&C>C) z8i|IAuG^}Vq)1ysgPwi@GMq4ZpA@xE9GciHvXzjLo*!DBRc=ylDe2m;DXtcoddyJ}Lg@CHM| zgM-a7z=E`~Q^g3mcbH4y}#h&m3@pAW-}J13$& zKjw5z+U7TwnCOPvW$8b!>}6wq-tke7Btjmd0P%K!!sz7ozMxp=6k0EU1;xc2GuC67 z7_hRR-oQXJF)VvMlF7{UQC+&f^#tQrpEiOW^mk^5ce?HmjL}@&k_Za?^(1}!-I}}$(5}gh-;rHAjv5y02!_7^SP}6-hfj&az zAnn(F9R>Rhoad69cO!8?2Lj8D$c-o@=OOk>Nbq0+b~n}jFXcu|a2>gde_43ce;$Yjt)V&ud6{fRpaUoja^mv49|E)LD-GUbJ z`jkJAaAL>8K#Bk?D2L*A!gltosImN8b2#$fh)X60VCa-*Z!L5Bn~JSGoze~u8lcka z^q?X>9|H>}#=;2GDT&i*$1WhjSqV&rB5aVyC~e?nq}>zLN<`U46gk8&4<}EW>teux zflLnTV%zy(0=dHt{%a#u&R}mx&DMn$a9~uBDcA2Og zsGpJ;p)jCQC|HS}U8;Zt#*zez0uluS@^GTf1Nnv=hjL?ioyVj=UJB=O?5Ohsx@o8l zx}nE^s<^Q0ZGvFYQUoUJ4-@Qi>vv~pC?Ez&z?Zg!QAcz}C8;7tC6W~Fq6vshr^k;b z)0rZ;RB}&xFyz9i1muSu$cZ8^1`)h$mRq{({-OVvnY?wx>%Q_gG_DZ-rDMUMQi1`J>PX`L>Sp;#LSFc4LRYL- zqY!c|0dg-02pATSx?H1vGwnv3X3^|%>tyMPmDqz<;d>*!%@YJvJ1H@h>jnSti_ezLl=*?7up~WcsG@X-NQ6b^dKQ}DbdqEN`7M|W z8+AUc*apn``kHR;MlcR>j;jW=R#7FHKAsWyHK7APFB!pNNt--x2`hX ztbUYm89(0)dh$_5|93oD+?PG!o?8rMBqIvt)wM(;vZ6Vb!Vdul+US3W4}oz|vc6KP z+GH`RYB9UScHpl+yzw2EAqgk2!D6@AAtMY1M@a$pa(1OqQ_)!yX_-Sx8iG;PHzKaVJbR@Y*_VA#yfD$4N{^nqKSGB#pr^__a8EmBJ*FfVio%lpVc?UA8o!*IJq=5D?N86g2<}l-OvS@tgK7wA}BKXAbw3vRJ z9I16C#ZLk;7TUR8@v;a1I{tx7#Wve=by#+BQ2Q^aQ)^nS9Me9qWtn89Q7efIP_F(* zm@=kWIj>RqVZ-OW2i_uzmAJ+%JC1O4q3gBsHCFI1^WY05QcTzcf&RGLJ~6sw1T{5F|{08 z#mNLFk*+y7-aDtJDU-_F5YG8^!l!@fSZu6 zgL}05uL-bDxz3vE#YM?}I?3J4PB<%OVC>Q(M0%K-9%|MDW7H-JfdrDvVQf*v@_yh> zFLKC+@P-V&uI72A9N(r{_CuL zMF=qLxDjOe`y$j#k1iC}lfY!1(>*mx%Q%VcD{B*7V3BXVunxDl6DGi5NQxvGB#`}U zDFK+sJy-7r!!7pwf3HJ4Y2VA{=#hrj(wbOU@`Mff$>(dc>QII_Ed6Qr#FLxvoIQ+r z9Ri^7F*T<7w0C>xZ=%z1GcD6hIZ#EP0odiZvanZ(!i;HOQE0#LV+Z1l$%Hq#_spbV zT@CA`zv2}WkNTa-&RJP$X5&Q~rD!G*)n2`Lob#?0y!N}MzNNl__dR8AwRn5m#qKK< zsD@t8mpN{rgjbwKrBDEY#rZNzJ7VmBa)10-&6yaBJrxv$IkTRK8CVb(ZTJcSC(=x2 zBvU%cnbx%VR_tQ2=L_bYtJ?i{irNr6(y+|%9*}T9a`>3Pgf|Wr@r{FW8Fi+RP>zR<`1nRxAAlrptCGNrl$ z{+{2RC|^TRs(PCn{1om6OAqdcv8;k3(zOC!?(Tx-zLb5tbS=%gl+R5ba>p)D-g zxDZAWYJv>L4B6?W;H=!}Xk~ML48iX(A*nc|k7YDy{2Ye&&WRrG>+j;~_W>Fe1uduT zJ4e(R^*1{JPN=`#n~mN6N`&o(b_rZ@J*6HB^I!l_;r8TdrhhwkcUVbPmoq$rs{6i}HVd-*h`9htb;zNus5cW8N z9qntxY#gqAz25hETkH5)7Y7&2RvmJ=eyP%RX^oE0v^{*iwkM5FHJ(N%ly=E$#H9E0|~uwNq|FKX978`~&U9iadP30U4N8r+|z= z+b!IqwFdO?iiA()(j32h#0^@!N$1I&@=m?>uF?N2+nYK#(B{)w%BjQhS5CS(o4)+b zM|Zv+dZ+gOhEGRWh*wN3Y*QB3=ijm1f;$p`$}A)EYe(F^%}*m;sW=LHsp#VhMwFlo zJcBgv<|_bMcY8nTej>wukNtAVMwS@BW=*U-ebQ1<1q93nd8A{V^e%iJ=x8Z%QO z87r!*7MxGI-9!i_$AM+6%~=!{mYE=G9#c#P#Hz z&b;sj{<}zRNsJ(fT4E$guQbwYL%k#V-uz+YNIY<{N5FqS{afO3Tw0UcGoQHk86cB3 zyJLCTO{bxokN31mDE{3AU~^XJk^iG9e;a>?0w9DBXN+e(?(`Wj8D*B?pu;OH5|kOm z3zm0hnCc2aPq?TRCWA>}$oo;83iAReDrcUp)P4&<(gzBz&8_{yU66TjOsHA0>T~6G zUFR8~DVmVzsr<{frJ(WWg|R{<4ieKDPs62h5^QY>DxpP(mW#e@$lc=Mm-E?qmz`x) zP6Okvoj%qAusjW$vkD4sNg!`oAl5dRDeTK{)BtyseDY7@t!x^!P6XXkAGved8>L9u z-$2{~<5g7yt4Fqx81iEC{(LWhh(w(%vKCz9{h64bf&8k${s1Nzz}Qu5jd!hVjVDeJ z$1;TCyraWbR_^S$Y$s>028)TO8tEIr(ri}A2q*z6b5!k0m|nTC`y5y_fpk_Tmo$Mq zLol=S0(-|~ToUSlO`m%=Oq>h9ZUrkal%UH!Evs0H(qi$(*aw$QJ-0LSlHBEB6c+}I;-5w-Y$4jqPBBDlBj(H#Q{cE2Jhwk%QYudc{> zcQ+I!qkx~9onppn0VjaU=ZiuEH+4xZ3xgVGQ8cmseIW&9>h3$5xR_BArhrvYLRJBu zew!|TY>@i}G~cEUKHbo$pNRW6h|F1Q<8&*I8@ADi)aMqTy52FM1nT9xncA3bjjI{9 zUj3D=TSciNm(9fbvDKeMUQ+r4!ae<4UO|&k+7yh(!2BsGIBCT13mf3_JB|yM$B`Zx zC64dYrNr&~9da^;O<)e6Hiw07MTm4Aj<`y`_j}RZ$`DT!ilk6E5x1cZ_K;q8fn4OB zA7*=XOW=bKDstR!(Z&(F;aTU9MR;}~Dd)TMT!am7ZWg(d; z^mR_Sfk3w|!02+FD$@>c3VG^O82vbMhG?w=e~zsXSA$+ST^Pmfo2+Y5|9>g%v0HS$ z7<6B*OmpsIcq9+ysvzj&PfGg26CgPF!%vf;@;pcKbug|@B4fQ^##H{$wIq;VNgZH*D=!!X}!r5p<8>6H#AbC<4o%8NiAmRKfMhzBm&x zmsp1hA7=49Jvv%Gx|%`fNWI9v))BjZCja{GDdAz@&`>K z2}2j`%6fD^zXH9NFSA^}8HB|#@3y=4JPPGHH>oJ{Bd35-B+hQGaQ!8;r8zdZG)cc6 z2^)0&_x%F;Dck5dYuo+tX~7}Bi3r)7yR*VX*yf%YzS;iWd`GCPl(6Po5>2jD6Ad&{ zghuHAOdA?ZjQoPA&7dojX>e#dJ)3N9eyiM6d`^_#j8mTP&Iv1O#rv)zSsL#55MQ9_ z#0Vv}$7{0oL1Bh=a6>eppR7L<^>tvfzm%yj&}R+yX$CP;k^G$DYc^>g9pKif{B$#J8s3TR=oEG_~i0l#kD+ zPbi$_6{h~~q||TUW~|hb<2HmM^hnPa0h}M4l$2YygH=!znT6E9_VKH1bSC&^%)ONx zfQDo^yToraz>?!ggw0XN;q+R8R1BAmM3VE z08Hjmg6tI|K1u}~J`^k4PdL*l#Ou98-{FnB?O%}V(Bn75)C2HV-|nsxVbvNSGXT#! zP)H;pVT^%)frKb6Alcn6)GKnHLT#?Xv&o2jVk~>t-wif3-Hom60Cu+}h~rr9>H6L?r>W&iHLnDdqhoAh1S^ufB|Q@NCyyRw{ql3-^zM5) z?e~^8i=}Og>;&Y*zycBtBg}Z3 z;OdDE`6Z4+Lp*i4AxZ|aka?86(3@e1%p)<8)JYz>Y?Y z?5mH5@25v1|7ZXZpj5vvlIw!Our4PhR2F8b@Zp5xyKl-5O%*YeQ5xiiIFwL=aB`sc z+T|9r((RtEQ9ok}#q$9lMn3ouH+Id>`f7n0qx#nu+(UorzAvbrqqH5%Bk#32W+#0f zL9%=J6Yq(o)qS-&@a%0q{fZdClgfG;-=jwv6)s^0#ttUo(ac@rbfO@JupgD3j2h3n zN}kv8mrO}ojc;3-0!y{0h@m~*pKE^7C3a%Vgeu`UW@O%ugfw;2it8mEd!R3zhiYR? zzLIo? zT3KktyZEXov%f|}nXk(Chq9eFJm~o~v+4+NaMP3iE2wvqUb~#0AJ6eR7+$;Gxy&w~ zLkqkSr#+7c)Zaf{|Ijy3l+D_sLjT}qUbIIQ!lfGO5*q*QgYBUK$_FftwNW7D7g>uc z3n(nEku;D?1YPAakO_Ta7Y!}H~Mz|&m{Pdg^PS9@nO3*ZT4kP0=t>Y^8DM2oWuQ(9;u z)D6dj0(fvHFZ~+RP?d+>Hz%w$fxyoLu9;#8KEEtxBKk8yrbBudbf+N3K9zE3Q~j7A zXh76DoJI&M&niKadcS@uabq`pEt#3U3luY#S-Q%s+;NDl&63z()kb-CmYXZ z^VGH-HfRUHesC66UP=`%C@RlFEt8c4Cq}L{e%Gq748K>XNfQL@L}eZDJWo zg(nLA4!n@FG>ZZQ4vW@sufkz66Me~G^Pu~2-+xMvvnj@VMorH9gM)fob+c-R^^s$q zs3rsorkyo@(gS8xTPfXl+)Gy?fWRHIDoG5YOnN9$k#uZw3l>%>2`Fw}ld5dv){l(? z9q;5@PDWN$qoX~sr_7=d1w-Y`8)O9!KuOT&ui_NrGWt01NtIta9j9Z_&SR$fIzmS# zB-RvfRz6c=1dhhx`aTcxY`!(Vqe@FpOD#PV7U)ywZV-C%aH!1R{}6Ynl8~gbubgVpX!Bm1UgTy4sWR#h7aFneW4i`<-oLDZWkjIg)tj)Q+RU4!B^Z)qhdL#6E5H%s5O({BtoM%IS z?Gdl-uKYBA+A)NG2l-YE@V=YE@Z+cS6nx|{_l$7txI=(az70@{q~r4O=9kA#8eqgS zr#FZ$>}4`0*3WxgLZ^l{Zj!SMJmV4#0;O_MnBl}*FsN$DDg}e06l%x&So<_NNe6Xn zlSnbOvV?o=_j$4uq-MYt-G2rU6iAJ^Zz)kI#XX|OllGR~KQtQ+ic8{{+1OBoZ%nI8 zSUt@e`vn;{eZe$^e7?j8Gy}YMS!`L8luv|4DQElTIMorB8?pfe%%`}2 z9E&rfuljuKd2(d^H$)%rzaFviks?2(zJg9C$Lhgg`-wPO5>LM?alG0R$T|o`3rmjN z0)}cj$8`(ffX4{gFn!0-=OHx1$l7GgB?D$Z;FkGR3Glqu%tHqt6wC+u)qFrmV+mKc-;TG%((sH^m$X_Y3KF&xt#ir3}y=( z3?S)qIUc?4v_dl_*zNGZU8yhWPoR0(3+j#txITS4|MEN8dW)EKi|TH(^08|?;AJh~ zpX=#=Jv)YR29Egm?1e`>AjH<&T#wrSIOZW+^ctCUn6Zs)r@;e-e3>#8@L&xrDT0m~ z6bG^chU@?9n!x z$mJFkO@E#=2{5mz4*0HF;3l71=Gr5@Sr_khY*R^+_O@1zLCk^0X4@=b#piS?Zu@29 ze?PR==kr&%?JXb-ZjJ9vO=a~h4JHJ*mhI&din!)sCU?lhq3T0inV22a!O5gxJ4q{3FBLXk(E~>(dpbv4wRFBY-&iVeWKPn3$+Z8CRaeuS2pzU05GhUUlBg{z ztz1f>y#|CTWDLYh!GcyY@w)pC3WY&1=6q-IxwD$YDB0{kKOac9)K?Eafx%~Q?qeIw z!|>)~cH~-VovLgO?z89=zG*-|;8bjPza?R2E?WMVgP*R97opJdntx^Tedu!mdHij5cvUUt>e0;jg&;3o4 z+0I6@yic~EOe&h(?sXhdYCJD`kX`b=O_?7{g#$*1s@xQQ3gV^e_rm=mHk^tNoUiiqaV&S9L|JD)MR z)9WzmLGrfq5Up>|i-#*c3l9^^L0emK-nsH2WSD3UM0b8B+sITg<69`5lo#}^P!1dP ztg&C2@=+>!REvgmt&lKB^EO*f61T6o{(nfn4+iLIreGaD#B}zK`ai%c>;k;+yIfxm zB%T-AjqbKywptJS{Pp#-EL5}1TVRFprZuDf4I`B8OEcFBZWZEtSv!RNHN|0x|LD&c zQl;xOLdUM(>Bg03SdB%&urM-LnuDBw*v849?o~6r2D7;7n)|JWm$z;5tC(T_(9Fi- z!!Nz^qJhTXU46b-b|$#)@8*z_af5$GM#@cJ z1$Wg{PT57{W0?OD;53~HrJ0OLBy8z+%9v%@LTIw&l_bc{J|Tr@LE!XfOq@Q1ZZaWu z`+IVj2lYW&>W!G&&n*UY1$r3gR zk7QuOD}i9LCl(_Yo0UBLJ2iaowkH|j=#iy4bY+K)J=UxI(Kd*#X5X?J3LZ$r3UN1>Yna#j-&8brm#yM;;+>-Y1V(-FTRq@SqsYz2rG+-WuXCTu+O zFyv)|i(n>jbKGy+dE3r`jNw>UT|>zB$ARj<$n3 z%8DC$ut~eBizFIEqmGwiArZ;tDQom&|@87Ls_+AU4&OKSEWZl(mCu4M-csI99l}PF_F)L84MZXBVIxtamw6*^Gy9CnK@ZZ z&5lwb$oo!6QU7v~b_ITGQR`WpQkP(9pf=BCyG7 zE4i^=M9PE1Buh2eNkbA_1pad*eMrm>4TwN*_~G3!zCEf}{l%j{Z6r0Z&uaH2w$YQ4qq__(J^52- z{(DtPLNTH|p)xC2#}h$R^S^>E*2-LtWkjv0P(3~az?&J5l@3}Q9{FOvYZV-k+00M! z-&UsF^}kWO6FDdk;k|5ynsjY^`7+fxKB7HyZka@a6W<^#=K)JAGzE%>GqQ&>U42lk%oQ#_D$~j0V3gRKf!7uOs)WkiPTXT;&hEr52a2lWvGN|Pt|jg3`7tMok^gHRo`3!x$#n%-oTZXwNIZX~#E zAzDl2@4vP!wmnCymw&E)XT+7>U>oE?$O5F=m0JSi{TJ?~-dXccO)xvI+A_s+$)R0? z+iL-mO41O$r4NXm7T|R=!_*Lz-_IGVBN`rl2)8)bU*;dlaYC{6p~d!y>SjPc*{shc z_HV#vpf6Mju}L%0cZXB=cf=^HE6WJE8H^N<`ToXEN32mwF3R`%Qnr_Z~R2i%6fcNPB)} z^>xZOjQK6?=oc7bM1f)_7mmzaTVvwtxaV~AHin>9Rn?Q!zr>8*VG#FXZU{+A^Mt~Q ziY)@q^@l6i5fgU!XBP{I+x>yY1M0ChZ-nj2k%t$QomuHsxcGEr4Xd`Yrmg74b@G*g66#O%m2|I%MQ-QY5Q9lma>Ia_)ThkVb8PA z)GQ!m?++!2Y{gJwG|3Vbc*=EMHsa~%jTyeJALsE9u(JHA!;=wyUVo~d%$)82^H4EN zV>aqMEa7E{_*y~YVsGYZrf45hzuz<_TdpJC;&l48nW}D4w|V-U$ME;!3cnaJCd0W$ zq4KK7uo8lR<-B;T&MUb(cZ@x|Lx`K2L%8Yq^jK$WRFdZNZd!G69812N@;o8HVBY2N z>(+s=|K-OJb>Bx9_v^*`1IxF2{Ke^?J3eq030Jrm@}W7}Aynr+F6tUNnoTE=`F^k5 zXSu<)>3rU-VKjdFNUqa<-FsL*Z*&B#e3SdL<-gA(F{X?a*99}!S~d^)VoXahslpG3uW_0 z{{Q56^`eN!cQ}PGql}DBeg>GDUaEfD=i!&H3|DIU3f;zSsap5RFVn>8p6Kw{mqU=G zkRnpR9Sy%IlBXflSr%3iIneUgeAABVsB7Tit9(1A#l5!n^L zD-K_UE2-6%mx^_InIbMn+@6-UP@jWLt8Qi`?Lwo3E-+0PMF1p_qOUZSJm$)`^YhoZ z>8n(TYFYvFe=*bMT!c0fq>PEsJD4dwoC*XoW~Y3M8gwM@;5!hvWc34=YrOowLSVS* zW<_(tW<$V3gY&$h!XIbNQ20r&@;r~Dqc`hr6S?fubjb4srQdbzm?*VYVod|y#Wi;H z26&ez1M$=qzENZ z>gy0bLZYm(n*5XB=aUZj&hGxWPF*=pu68XtrGK*Or?K83Lvk|cdd~M}Jq``VZ+Phb z2rvD*=8YcF>O7r!D zj-IC0u}G2}vYz}`?Z1}yAKi0Uzlr((?Lc@mP&@ssoGmnJh#f!=LY`NxGDOob(pR=0 zuE~zOKRP$_T&eRMU)EHe9n*?Hv;skU5WYfz}HZeT-rVCnjmaUr`d&a~)^1+kdSeRd5fJ*i%* z-u7^lh41C&_S?#ryMX)Q?U?k+(1D?g&6nMzkO*WGC;cCF5?;?!nZbRG5`Lch)bbb* zBzvfafZ$UDtFnap)>S*Z%e^bE4AXWps_K@mV+5o>mwy)_@?OVjW_8SY5WVi3*I9SM z)rsF3l7o%=_TTpBt8W1(c58Ph*)PL%Px*4mx4dJ2wzh+PZgdO%O+I}d%FW7^DV+@c zz}b52g=Pw>FlhBS{!MP|z14RxME?Bu<+1(c-VmwL&(j{=`Fp=(+F8^z90`o1i#p6L z0Noau|8+74k>~+s=fPi(OQ=F^QZ)61-DHGuXv6!Er1RnLi2Kf8Zp+iZzIecyrG7&g zkfP|1WFmo0DjRR*kTkMuXVe3(YTV^9qGQ+FqWGFC?E_|X4z%J4=;{#fbWKR+GvaEi zc9^=qmVLA{Z@8riLT~w(|LrdFCd&A+=c&$i*4DGRtVHeG-5mZ`zmvBC7q1&k`~bc7 zmm7Zv@1HR5naR4RI+#nnE~g49G<5-5-c~YYJ+bqb84Gct-zE`H{PSnU{k+pMq_w5y zK1`qct?zJ@bR5S-4``VC0{ZLddfDqk?364AX`juM1O7es?5BOW*&>f_xC>ON4wM=l z3eSQ~1;S7ZB#Q`T(d#|kC0mm(l6ay|eaa@PnOC~MH#ex{7q%IAdL{@hB*V+HZFyL|bO@Q^! zgp65$EpAN z?!B$dRu0`4KTRB0gQIbhiYKm)=Bi_PNw6w}=ImpMrQbXzLCzEq<)(WA!j&vAb__nV zXa;4cOu#3=vo?bD5hTBK+J4#~<}T7rPx@D@zc?3P04re<;?-4mg!t%tagcrdmzc_| zU9;+^%e>2Xi~sHnr?g+zqneFx5o@=9(XEPEv3=8xl#{i8mRDB#UuUm9ZyG;e8wYGZ zjK8~iia2d=xLJN%$qP85dtO}=W|)$0Udf~?`#{H?9-Z(z-gW-ZZO`onlfuu^1(6-| zo3w&Z4Fi3HmhJT?A8cko%@!Hzf&&(0_(Z*DZ_c0&996w=7>_pG_N|9qN^{FvZqV5^ zYETc?HO^9t>B=e+_EL^GOdzqRPP6ITwtQ-SS#N*lDM@%E<~=fTo$X%&CpvcYe7ef4 zt(3Uiu6!JAe{6U;wL;=d!$$4>PblH){($Nw*Z2w1)ixNlm})nV_p9mY!C-08$NY4; zC*+1kVvdGxt&D;^os6vgnki<2E}ewWRg4tbC5t|m=~gq+f4y+mXU`kOtre*S{6(Gr z&uMrOGGnQRkf5Lib-{PL8e-sQ#LCG{;Tf#f;5R6APtHaAraO`D{jc%%!;aL5SB@Ct8;ko?TrVG%IC1{` zITE4dz3Q@}6*@VcUHt;@h?eC+-dhyiasM`9r z4Hl&)DtS#DbN33RH=<^-rFVAN98ra5eFu8&v->!Y^aP%OM_xrmOqpp7cf(sv5>M~e z&Pu`l{BFQi)R>k3%nz|~TxSMscQCW>EIk%yc zr>Jmi`JqS5I$q!@FN+eE>NH$2W$!Lsts>xVN!`#T27w(0v-v%J%x%!_!nEh$_=h9j z9xKpAjbbY^V7JM#Trcw#=V|%ej1aPKcWsw_^pQBaIRV_hNs;bL)yx5e7HB(9ryKeB zT^_27`|UV=^}b)Gj~2!m^Cb+^1n*|S90&)c56N0$cdV;i-ANBDA_GES|Il0=aM9z4)D;<8#r#k^d=FpOCM%c|3 zJMg!!5s0_t9=l>nS??~dTzP)^|8ZI-Q+SrJ;&Y>&g%QRAV(h5t0j$HQBV#INpKP&$ zoeeU-^$*>niLP)bd+xEcbO)XCE3t1x5QZY#rt%eM;i{;`7V0>4aFNw!up!Pu08h{B z^()$k|Ibsv>TFLh5m~?^e-K0X>mgJgx-R|qF^w^WBLC7<>26CZe!{7|97y-C;jm108o-sldX_83I0D#o7@Wk diff --git a/docs/docs/images/favicon.ico b/docs/docs/images/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..a0dd726ade8b60d84b30fcabf0b11d7688321bd2 GIT binary patch literal 67646 zcmeHQS$Gvi7LIT8HgEGhkG{;f%#5FovnVREC>lTkL70I76dAS|RFnjg09imnLRcj% zvI!B$#v1s*ASAK{1e5?_hmZtFNN$#Ud%078#=`zC>At;GueUm1r~CF=b^gE3Idy93 zq@*Xv-|X2*mB7QmjUMh z=K$vb=K$vb=K$vb=K$vb=K$vb=K$vb=K$vb=Ku>1%=+US;>IayLQUCzq3PPqaNGUn zXz1s)rM@wIe*bq;v;Xv_WHl{z+z%XqCvc6I7v=eT*Kf=7 zUw>b=BTZg;X3=Lknq@&Lk9hmw!S>XJk(s}L-7_*rznlK=v!| z37xGW)3Q;M+1b67g4;3!2lwU{idOU*&EM(r1HSfk)O5{-L)8(QN7h@En+1JGxnd81 zJ@H|gvV5fo@qkY@*|GBff~Bl`b>qsy3AfYURj}$B`d1axi+2 z(;R@kw}aQnhhOSB@%V^*ko<^7u{3)`B~3ob`wPw$u%m4Ee|w zy|2s*;znlV?X`Q(RUCH2_A6ya_fPEDV~Y&!tjo}}cZJ%cLGS?(%cpsAdJEr-#M+s1 zz=^U?<@80rQNH#8P&e*qX{Fh5Ws5lM(xDTX$+4!i!ZCY>HY2a;b0g`=d3CsJWnW1) z(!MCNh!Nr$M&tU*bQs+y@oi?jHG&(fYZt!pPv-GnqcWt|BTj6!tzc))a>vR((!Dc# znJxY+D}3WUC-3dCRQ#UU?wFNpsXW0acQPXPuyds+EJ3#t!I9m3RQ;xrNynA}W;kDlw_N$%N{T%uvU8t+HUl=5o}9Y;JEG&0{-)RkMKnOUyTEoj-J$2CnVQ#{7uXa zkonTPmil_C;l}bf`VeZ_fjKV@5}b_rDD(FH)^cCh{~%ZN>G$%2{sQQmsKx=ebU$Q< zaRO@T^2>2I+kf=(PR$M=URYmy#j(CCvFY7D%ir-|aJ26G8rS3(D^IQ8W%CLivjc@= zK6b_K({z&l^1j#qr%Eb3?E_L-cefKN`j4hPH$XzW5k2q5wqWoFzK;K+{O?)#rK>VD zf*X8+O;gh&%STL(Tsd~e^|mY2pZsFy)zVqHW~-|@)Cm4wx;EV25s3aj+h)2GJMj{h zX3_$`S*=X@>3HsdF}(bnAOOa{`w3^Yw4x3bdeGv!Ej0mwtG5Ip_Cq=0R{Yde04=_J zd+HaeF)1onzicZOuXU{txJ4LTyFD*?tgYi$oaD~h4?g2QfB_~6;Yif)bKWTVg}ex1 zUxa}Spk&{rm=8%QzaZ@2I_qrTN&C>T|H;R{+4Wc~+V322y6?38DB1UhAo+fjw{G>J zvJWNuo{X3Ym0OUux6WVW^?*3EA^p;H^-1z0FDh4W;q`zx_@CYTZ6M1&__}=fB#wU^ z{LxlJ-D~DHK!XEYKAsm?{J{|?$4@K8j6VOQO)b)Vry(4>!saTkb!#7e zQ0BZiFfei7o^%4nv^ybR#L()FosM7*-j$=KMY3NRrW#X$Ucy*)T!-s%pBsICF~@OF zG7Hi%%xPlhyjj4Vw4DiL?hH%ubBy)hvv8HA`CN_i9DOB%gtb~;4zDS)Mc-l$<=i($ zGi^6VKfr@4HwoaCol7FQ0kDsq) z-LD?L-It@LS;XRfPeKb`?&Oi(8Da4;y> zu$)WD$$1h`KWAP3QRfH>u14~~Di+`*{yDF)9n%cI58sM0BDbJi%W5t~NAYJor`=Bn zs}joY$8wj&yefXiA7hPTWs*q0;rCj#r+0q3?3fH$)?H2deR5{6p~B+9AIe)k%@Qz1 z{P5bMuIi$4fwUb)v7RcckPfda3KxBrEs<}}dD^dJQ5S>_b*jH)S>_VUe5HIx9Z0LJ zr#=6cNZL%r(s>2)@ol?>>!*JdjLxTvxK(jRo~Qi_7Inc5lV&-RN5tqUepa@Kfh*^s zLpjJFI1b;3luniG6C1AFU>0*E@AC9K5|D${Hi664r)bFG}*vB$Q2X1tIrwYNMpJdTlKO}ETI)%hTl3sT3hO)grP z8a-#VE?{R~N#8}?WuIaliC9u;IuX{stfu?`)AmrKm>RhrKG4mx7c8|6-@SAd-%exd z?<^bkZ%M2Dm*P#g+K4!J_Q9?CDDhc*gFm>!A|`ld*Fk3bj?|x}dpB-B*62sErd#Jw z)%PawmBcET$-ziDwt8*#<`PSa6Lz4YV4Y>37kWfF4-m!L3wm9P1;{^{JI+>L*eb?a z_oJR=wLS%ql?KZqV&xiQ*s^@eXSr@RFA)nAwD&MOO??0g2RZ*1bbAE>*}`}?~+$|n2O_oC(5 z%c9q7&PO3bKQ2gjdCsyP^JgbUc0L<+faM&F@QKj3dw;>Y2ekmX_|{D4ShfU3!ve_?r7S?#N5to#1<4FBb3E--rv57`9;! z0CS4FVd3_0LnI<}V+lM%p-?x*z!&>!3(kWhxCZyJ(mABPOZWFnV&&<_-)JAu%K=vU zonqJ47K(OsbPyZ`%lLJ6c3OG{(sW?yS0a&z<@ko*c%a1rR%IRX1=e(hUT3|)UYOAX zi07^vJw4F2J{~7yIY9Nh8F?yk17^@|+#}S~es0ec!(>#!{uw119M8; zwPf$axyHsO)z=`et49Afq04;gv;Ab!*H(OR`!17)7nJqR&MwcycYCroq2?BO*Mb#N z$}{~E&bO!KA9{YvCz(=X-F3_59R&=29qMmZ{X^BlYVt%=)4fM`BK}O~tU&ujLhJgk zK1vZ-=y@tw_=k4I-sn5bZjmdjOxn zjy8O&d00CswaY8z(#dqBKmV4z`-_!g{lzP!m^z{ky4(3+6P$XV9&QxR$xpcQAIr0x z-XkQ;QG+oHm;<4?zEQ$=uURj6Cg#AnP<2wcalV#moY8DrkB~8LvGU-*dq+u3P|SK| zm;nEXw1Gx8Oi2rGoslhKo}+l{=IL{V4O3=!tr{~ug8Osd94)86m>kA4scch8+gfSX zQZdx>&>7{ULXcX*cbX=??d`ZPoc-!>@nrdasi$^W708$#ZfUw7MZac_z4O>BWxjs$ zEb;!G2FG;);?xWK|0AK>{ggPkxsN_p$4mB#PWKVmG<`0&0iQh5W%aUI|> z9YA@oVOqM>Nn-VOF1r^Mav#v6_=5-egT{+@>#o^Gfm=Ub;`nQVkK&@Y{>5#8$2pMlbRW5bjJvg?Z`mO-PZhN}eCs`bP>IRvv7d+!>eT1X+y?jrfA9eH_U&o8Qb%hWli2ZvBgc99 z_YwY77hvqprRo~Xxiqv;pUGQ|Vd4zixwc|gXzcWU?WPx#1ZP1_K>z@;j|==^1poj532;bRa{vGjod5t2odI%Y(7FHs6FEslK~#8N?VSg3 z6xSKYx7-~%wNo!h6bT^^LiBEm4T3-@Cbj`%6C69kP+SLh0UkSmF&GjI2xAk+CYVr+ zDFOqgm;kn9z!Fsm6;wbC^{&(1mb~v~&!YfBS9ag7(Eet2*gZ~nd;9(0_kHhsZ{Ly= zVwUiPO1p&;{#B6)7roBxVbGg|L+q#?KnC30UHI5(ec8t+#!z9AL8uY(MACn6@@tpw zCs>9fg|}fr6#z!S@Kc{1%uky=jP&(4{GXvYjw2S&-O8k0y`vFc!h#wCFrd-U{G?|F za$66+%D?#9AEKlpM*(KOjpb9`D z4Bl?st4pVFtN;0urh8N<)mjTr`Sli4U)MwnhuBaBAOWK$^x`&uw~(ANa~Or(zwm0y z@H|hPICxnWTc`pM5&s|q`{9P!?E9b0qWl89Y|F|ZD{q)IlSir&oHbifVN0rh!^+qmbv_E%buh>4Q_TDv7y0896xYb7UKh| z033v(DSpb#!Cd_Ah2(%?-6@3dKlX7l;SyU@)gYT4Q~@|ZP^dSz3bp!|^Yh2jTCG-iRU8;I zgR=k2iWr4e1@HjEA_Lh^zkZ1x6&pi}rPV^csVYo7uzDg?G{G zXq1h&+E=cru4l|%`qLW||fZnYGKY7MrE_P}^s%u0bvV-)7fOyNYEaBqfBHNt% zd)c`1Ab)uGMMZ@G$#a0N5dqwmy|0k-7Eh$Zx(7*ae7M7=p`n3*_ z_W-tp3t9NyEMR6bN9ac6`Qdlc)oD%`b1;ChDVNW`Y zMx$lZgW*LUxf6?q`g-g)e%gZM0@%MJi8q@V;YfVIPw@@|#SSiRWr+)bE0+F9v#&-@6fZ4cCT@=U%04NH< zMORWKu&T0>aCLJd(C?(C%osxY1$wgS*YgQuqgl3-lwAM-@{VL~=3VmW_rDR6ThiV%Pm zxB%(b@~MPf=Pe$gQ5E^o`O89_a1MeH)=}@u=e*+03{M%$ST7&@mj(nE0K)phT zyugD1p^u-|pX%7fmqkf3I#)blq0OulIB-Nn)5_0Z(4Yj*sXKMR2#_Q~cz~f|oL-^2 zx|%Q;48l>%R8`dTn^q=p=T4+besYTGjyw#CBDrx>`oV+_i}AsTU_eJIfY$uL4Y^_{ zA;Zuy%pCwxNR6#M6YvI0);>$et(nPr81#~sITaZKnghmvYsJ$n62R}x9^5yyTrePP zU_3`!GKc{LWyuo+5x@qYZ%x+30zMy-KwCo(ybmVNjQ&FmnUhh>N|hTZS^y6+eska= zS;YVz0ro)!3H2r#kuaboL+F6_ zJP7OeTSqG4ea?6kIH$gY!>H)~U0_WC4kd`9c>~1?VA||q%&fnTwmaK{i)A&UHQ}?q z<_J($2Co1c7!ndk_)IV;7`MEv%u;KBtq~c#wx-6?)r0rI90f6pQNf`;Q0z3HOt`|GNVvpaxsVOZwo~Zyks#Wp5VSfCIc8!ERastV&b(3R zln4~(0p49T!#s9!U&lN80>(xYzx%7R+>yN(pvrob=DXc&t>o%Rwi&Ig;h3PnD8D!#Hb0qksx{z zA)Wo&REPi(9Nu$*-L&$MLn2U22msgr@s__(de;sPTOTgQp0Cew8&)KcwRWt&iCifG zq2ZTPXUwe>XYIE`PXabbB9#h=V8J_+H4~p2X!l7fLIB-+bu>?%HN>g7 zf9BXVcE=b0b-KBlni%5acXtzocgiiH5kvr+wId&Y#?HS<_@0iYA- zUtKy4{o}apVAZX4AMA4~8*WZzSsnGsyWib+KZ8{aumMUF1L_?R@2{Cf+cSP3y8uRv zjbeKA4t03`7P$WPA02>27ll{EA^mzjwSPxai>;}-7+|vsLGDlix8W^%Z?bUIIe|{A3SaEk%L>C{<6g`m)K)jr*HUst3G6VknUz*V?A&^Wid(Rao;hX}KmX~C+@_U> zEM@9DIVFr(H`3agRm)NcLg&W6zU)a@gWq8RK&y;jb(ljJOp^HD9CuF_Zt%!Rr@u$< zsv}XWhsVQOKZ~rYs3$X03&_Nu(qJ+yN<0%;c#d#(dJ$PsTFau}$GPZr6!MtDpR^8$ z=&R3uWHM6=TfM%rl!6}{*US9DKb~{Sb>F&KWL`8gUQ+jO1@)~>pY2#6%Hj?%yJz8y zcnak&_VjysAAfh&+sB>m5)r_1OFcnM`I5iHXThFV>_aWs#^W zYt!e;B7luM7n&oZL!2_+@q;O*b<6f)S#iTZ&|v!Z#M`2M*BgKS!i;(@Sj5{J*mD4= z`k_q`KVB}L{p%QEPkyiqVEXeTEZvm0gxIG$V0eVa*WW`Cw=-iE0F3yJp3qxyw@9}} zul`*`l>p3iik;RUe}(7)U=_f4^rOX^<`ogu5!<;>dTNm9-}S_#KCm=B_WbK!uw6v> zu@jygAlmnZbr00^9?(_tHFt)M>B;pS5+-_A6DpuE4k8@N1~vio=pABqrtEt!kVm}v zw?9#yUapdfVBqiw{{1yGC0k;4%FH3co_t^vz^L)PMgOjjoqfsAzMW5ncJUK6p1SCD z++SXeWj@+CheZ3rtKx$^n8w{xFRK^8QVB$HpM7)rQ?MYk=uOGP;7b1SnL)7F0&_d3 zl&`C4bXaJRq)vZsIQ#yZSrkkwy8He0fRD1Di19Bz^&&=D-jy67IMeI3j|K>eE>x=Di5Ekerld ziktrpmV(xUz#@RRS3YBoood@HUSa~n#btMEV3ErEexp{WfqMgF?~=lp#_VycS>(B7 zITy)u0BC80Q0o#7u>#4Pe~>{N5bUM9cT_J zYh+-%p7>!8F@w53S^_|dCUiPA{M$-ku$K-Rjc|w!$pjD?9ij$*JAnK8`~p2C4apBe zvM)qk8`-K`ZIzxe`11fs1OR>7Zasr#8{ulJ^ynReeVUjg0)RfP!P^bHJ8SEB`QR^^ zOJby`KAnX<6?=f?@q}G$NFspF-TZ|;6?<^^)azjKjBtnrNd!<`Y5M|Aa#LSxNK)Val(5J^ldy{g(FFhlKuVqi z0IvVX11S$}WwkYpn(HaKvP{r`F#(*2E&$Y(QLOu~EU)8My}O5ekn6vf(?_ogdyh6) z6An3nTLadAcmP)BvZ;si+b@}xzj@SYHv-uA?_bQnp1EmrAG@NoR-1XFP~K%fG0-jq zkds-=Zi_!N0C;l9s(1GAjy!4W%&}{ad>DA-1+ZoH5jO8ui9@M% zaY5xH9|lAh0K>4dmQtH@?)Y`)*#2av%F?HgToLy0key!Kw#NcYMn?8!PXHLy`E2ipW`4wJr82F5{$dd?%l2cw< zi#6#GT>#MHP~wHPoY@>m+P++Sl*vdf5Ur$kU`HahWDt2StYuV5l0bOchOmpB;|EjB zhjyPAHIAZ0P;>A8u}EmvT!MZi97#Bxyn51x_EiDybL9N-Grh@F9r+ZlxDd^|eN9*({9j zuY7A4Z)=_3Q8s^a7@pTFSvNQFr!=hYACN=<;KoiJzKkUdfbn5oUvAc2$z3P(2w*@- zickQ*kNcC+b&^&CR^vCH*C#bFptN<}G10q)sKIc!<3Avo0J3ftNt!uB z%zt@SJb}~rR`zXA1P>?LZ-a&c4MsS`iev%+HY`6#LMs&xMFUE_i(mMXFUqf!^!!@_ z8I1gN$@iLntv@bGIDq658jNs=6-k$hMg3Z;ytIZHF*XX8Mi*Xn97w>ntp0)ddgDor zBcppFL#AHJqq5S9%>9Ojla4Nf3!ZGnTRUM6qAb5h^0k7qGm2?sIMa~PJscJR7=HWa zQ_PyUy;S=3eCX$6PnKFDKd+4b@jx=y!9~Z0M+Q-_{;%*~tx|ZqoR3@Z4OvlEC!3hD zJv6HC;Be;k52jHeUHokNu~5&4=k@)t=K^){=L~2e*b^jsfycnWlR!qsMw9Sdq?QB^ zzwPMvzcJfCKShZ#Uf~Q_pBe@?J`Nrk$;0B2Jz_#RcMlhxwK1Dbj0x)Zs8z72J4D>L zatE?}S>mD?c>B4VB6@Zt{ewJd>$2m}ExKD+$tdZ!$@17Z73CmzBBdfTssP$KssP$K ussP$KssP$KssP$KssP$KssP$G1o1z{X9}TpCzd(@00000vP8nWELpNuL@8N@ zlzmGHS%zfa_ifC4kN4;M!~MALzu@+G;PpDMbFOop>pZXZoQGy6`mD_S%m4sZLjzq4 z0Fdwz3D6Ai-}>F3yYL^v&q7}tyzM+X17A=cS{Jkcco%<&;!F?UnS2c{`2oP5aqx>E zlUMoxkjpaE)v~qTGK)JodRo95ZlvEHwAV+|f==bhkrJ+IhuOdcbvWDt=n z`xtABjg4s5N?<-2a5F#byO;8?E0)xWcC)rdXW7Xp%aZV?0M`W-$EG~N>P zA2$+vRACTz;(KEAOIM3r*N*ueoS)G3=s&*RT@&`T!lU(m=IOr=dvq>Qx+YqzC6ieI zST-`rL;#{b8ghO20sKRZ`Tsn+5y5DFwJKY|xTgR7ztYJg7bQD3TZLH`_$3Q}tj%s0 zs>Zb`e2RgCsr`9zds9=BwbgG+dH=JZgdU)q@)zbuu!hf=LRvKNh~jk1rT z4*DCO-(&1up|1>@>rhq@P`=sv*J`QuN>2Vr^E_Xrk<5}cV=~ak08l5r)%EN=p+Y2+ z_F(97hH4)F(vwm4&+-Zi7cW%>EXan0ge>*OJE>U16RN;#$r{e)z7MwaDDViqx>-DAbE3K3peQ(;l1}iSm%%xHfjiMz1aLV7i z6HlA@nE$GxjV`TH*l%360Gy44QVFQ^adsX%=O6C9m>w8lP)P7d8lcpjhjMm`xw7Wx z*HyIUXYL$(%@E?z$`9;AUEeXrSY8wD{K z^K{Sc;jrH$o08h5T&D1RlZe+VJ#Mk`8Q7 zcw0I|bG>y{{lu1lTql8Rz{Lr2Mf>&97pNhSc-1ch`|K^6dzbQ(cs9he8fhD(L2rLK z)PHhGsP+w@=^QtG!P2__N{M>4%(lI~tE1+v%r%OjHdL0x@*7Y(52`Iau7(a(2vUU1 zo3@Hld=Wbdkx^@}fTPqEuyr?^%A`ST~cdMCb->}&}@mPXn8CG#I!OYwCsvk5fov;RQe z-cRBeqBUPFk;x~6j=a-bBHudbsp1&CA7PXtvp>AMF-J2ae=$F3l^K=Tt}zHaY(O{rd##l>B1T(L=CZSZZUJobm7N z$>f@0$>j6(J*1J55z^22Q4aXA@B5sOlY8*xk=;POE7bS9C`}One2>&nB?8#lJ)q{U zIj&2q>i{r%EO`Gya}_H$H}~5DqhMObG1!l(hRWSi#TpzEGLeUq+Fyg)Ogt4iOqt$L zwkcnak0q$hGxLq6-YM4^;U!8;v$f=rFecEb zR=`iohdlJ1KWTS{x+{NKB#E~9_;GXI<7Bx#vLD>zek@_8Cy!(`mEU#v_%8-_Ps-pc z0m8^`41n}!*qT>sH|F{XZ-3vbF~aGon7c*Dy6K&7Q08KNHr<&$Dh_Tu z8E$;)iIU^H8Yj8-ZAbbvYL;+Dw9+U;A~5zNf4I>X9x(Uj<7T>ApiKGAL8X1(^sB4F z)=+JUhOReheoNJBCYeLs+xj~Ev;!!nf6iTL;)FZF6(vq{x``8~O}}v@QH9sVF-~ZJ z|9xVo$#eauK-$6}0DyuM(whhE~`v+ca-RUCgdq$0!Ed+V`ycuUgxwl8149Pu|CkB^4t z=ns~)>xa~eQPW6Rh(b+G%{(Q>3KG{nN&56@+s>bgTv{|0Orn)aLKYvi_S_{DTDJaO z3)<&3OkAanc8?}Q0Q>K9lpceU$Tm|RF&)p$coXRT#*C_e3X=c)gmh=7hg_sEz8`Hy zU@U7wP7oB&0nlA|;5tZ`N#Xlbyi3YD9h11OIfZTv3_I@psr~ltn@8X4OATkswO+|O zJRP9n9Q*pVuI-~ep|K+dgk2Qu>gekFu`S^KW3pp)mMlDD=VS%V=No3nvAt<15=hdx zqnN-)(>H=lT)u@rLnR$@9IJwsW1sg`LC}V52rWk(j_6Q-9p?i5$!1%}=xEjpr_|ww z1`Ddkj__ruE!_sTtAs@HaQCFx6vbAWCm#aTou55Vm0D34oEFIcJAqr9UA?=()D7WT zcl#+tx;*6WM=6@iChoU3G`+3G4u2ob8n=*7mr+ce*M#5Shqh=4%Jr_^#xY#L;*iRD zD)$qTY%CyFK+KR@>_Teu<1(u?&K&WYKftR>J?E6faRvBuymw+|mMiOw7d^}N9Msv} zTbh|<(UOGWDxZ>YmP28Vf~N!NJo%1*I@7ZBr33Y4jU{cIpyk{|fjZf;>ZLROY!z!( zHH094DXDMUxX)SuP*#?|B%h)MuFUpsH8;w8P2C{nKg2+1fs7ZdB7dE%Mt9eFKGh?7-Z@0$JJ)74AxYA+oJch=| z! zXvp>)F0x7JVvN)d3Q7TA%&#^YL>!CiF0n& zhgd8Y3D;qS6TZ2mPZwBx&l$kAj>do1qyC(pz5*i&A!`C{FK}_F@_D01P@cuL#Wz3l zn>H5Ox+tTJq_aD_H=1Zv;qY}2i^a^ev_jV-t@{Pyr@(qeXLT#z6%p|1TH!nPwzVQg z+DZPP@_iCvzi;%>ekYa6G7+wLn=<{qeYv^$Df7eXA;dv%=fZki0A+jWNB`iI@w?Ok z^AoPFha3Y|8m>EpOdMeXw4uSlkdkoJohTTE<}o-n&RWH<{h+_R@j&(OK06*lXYvq#SlauKZfldcj;Xb< z-lozg)dl$$G9F6azjK3W#|LV8(su)AM>W7SGosF3s{yB^6yWRWIn4zr@{LobpP>wD zB%{QM)BJXb=Y?ic+?keBqKeebBnA?9EKYS}a=M^4dqsZ>4cwnN(59?fX;)sFZF_BS zc!?YBeEs#t?%u6%iJg~r6LWnHDFAUr6r|?Jsj2N9@z?xvmNfh&+VR&)n=6iQ$sUF$xBn{l=D zpS6KpL(?_Nf<#hzZVG`)*%{3k*niNlIOeP(zbE_z3vx^3%%!N6wb5>_?xfU^{NE>C zB87n+2J~#Lq~HG%9>!`ErLecRTlC{h>Szoq{g+49DHOJI!K)=GpH9oH8BK&MW=z?qymg~Y9N$>!L0G`5m55Fdp$Ii(zh#g^2thgD;0#|ft>y=h?~7#{*wvH zTL_6c@~^H(L<}F2c*()6$)-5P;P?9dLuups@v~}m>d*}?%^GFhK!Nh+=WgL&Ll5jW z1Q*jJ9R``W746>LK|S71>E z3S4wtrvrA^dyEL6&J6|D=(*^6SL$@%Z3i!--d*}J*ro|UH6E1Siy{gyN*&fzQBvA` zG%Na5D*(Jm%Xq~M>Vi<9>TpbSw2-RIt`;Hpu@`Y#OHQ5c zR+3v`*=aYGwC&<4YV)#i_h}@Nko$3Y<=wk?_jGi0G7B`dkLMz>Mkq4BV8{GOL$_3q zXjSAhm_=I?2sE0-M-<|H6c{bRqKywfBGi_f^*e?|nY2{Ym-%56BqG6YEr55vetlM< zG9$wW3frwbJX)!xiq3U!bY*3w9Yz%4%(?flL~9JdNH*tYFARPpTq5UO7z-tSzv$z- z`FJQV6Z!qRB9D_e*S9}&YKQLo6u0sG)WYBetr1vD%UIg@ECv70mU3%@t(=9CN+tO}ot& zjz;+A5$8og?tR0^fUA61;|2%h&7xu52kG>~DeIhd0q^okH3~qT;x{UlO0tNh>Gz&F z#dsN`L@j&Sec&JGm>kYVJ)O3R5mtd<>g!FrPOL`*IV(B!y4HwaE#8q3P4j|gGAZ{w zPMZ?P5V=|oD(WgKJ4XI3LqLZEIDP)jbdPq++k4S5GXIQ8ZGFh*jg}FFPE`PX-&B`l zfq)Q5%#B$oVBq}+06T+}P4fE2#{S^!0&B?9=Tm37P~O~&GPY{!SSv(jO#1BsugMQK z4&MUFF*Y(hRTKdm?~M;=qRUN`nhz4r*EXD z;%9TSt%8r3Vw2!U^5W0Z*lK%&rDM$rcxEVO-6u-aShFLx>0Sz)h>AsbrvD+zZjCm}a1e}pM z`~>sCZG~H<^4F#tU{&f+XHibY3az8W(Vf$oC-f%ezA;9M`;lppkp#LiiW&5{+mDmc zRuP-cYUqQ4>cIOTKVMV-EDejzuHwwhC0@=4>_m^d&{T#wd6EWAop8QBcW1`1%tXQn$*WO2x~p^@hj& za~jd8>?Rm4Ir+nRbx`ScnrUXu3H9sWX4*5V^j`R||F$*ylwtUBft!^-uB1wv2LxiRbF?ygmUghDDGC;dtYOx?^E7< zI5<%5K?~m7T!=3=(#A7F3(@oO=gP)xo+BE$f<8qL)0khZ!clR;8vHNBkFw17Kbdwv zH%1zK)$#lpf2fF&Xc+G=gVz53e%WXkQ&^@%5tShChiCRlxp9K^=}l<5m88axwo>li z<~0k0-c>ih`C<~C?-$#Y%vKps4&PQuy5YdI; zJRm=jfq67*4u&3)Hcs+ULDsh^%9|gGk64SwR!QAt$uoDuYfRF=j{(F_-?u*!u|W48 zrdxFrfgfTkyw^y2_`A{Z3#>wxI^yRF0M_L3Uf{!4(9KulSa-ZvJekM<8)cklG8;*U zoX1VAfM@)5%9g2#3Dx3CxPzc2oi&~w+;SSi=~>bfE5fV0~ZEu!q8bFN08z6Ck_ieX`AK3aRAH_pRJvEvzs~O z(s~~;7Ub>y$?0j1AbB=o@;l=MK=hPbBv-!W-`7La;r(i301|vYH$zfzZVB*sY#T_4zvblYBn1cRPF+Lz=)iK>aMn6GLt*wVHa40d z9)%ct8pBky1X$jgRLRhF28|Afb{HjvVGA6 z)#Rr&J(_Mgl}CgKh$d#cJ|_G$)4`tQk|;UQr6P<(15chj+T?3!5QvJ!#x_JSxpO#ieu;s zfYX`!uQ-01sv@1{A`VA5T zy3t&;Swj~I4ZHXF7%-ssVZktB;VP#{&oKe|*w|Q&H!^Qn5Ge3EYJ{M1?W=2uqp0J= z4aqCgGoEgE!!>aAMGFktd63fIZKEk%+LejiTk_o-=(3-bj9nMqm^ljVGX zc^k~SD>@h+-U*H8`K5KS3onW8aCYX?!ga6q5&cXUkpol1h6H)E{(`0FIkR^H zH#*rk(a&sHh!U>!?d-)Vli5fjriLbPV!x@W;3d)8Ob}ny*wiF!aeTZOpa8m&>XWrD zEczn``LFXLxGWEIlb0~x=$f{3;Q-j_eR7>QLH-Ah{L_YBH)0m>w`{D3>ZCt@3x$aF z+1qmoTTlzwGm7)qL3BXUZ{FBdcqxV5!y*CON(G6is5ifvf=MX?v1WqA837arpy(~p z7$m6TU6qn}QAG$H>> zuQlcAjsV=d`6Y&6+Dr~}H|hwoswD*Zv*nXBfO$;+dj3e)I^W5aAQ^mq0Ym>(|H?S2 zL^f6nEVDzw*>3r;6@fRWE*KkAx)hR<#&?CdPaI~>OuV?!${Ga{U{A!M*4C2R-C2F;XYbOW(wbDpyn7sM2-7iHvPI0iF}(zhPd|)jWpChf zQ?H0!$FIZ@Hw@bK*UrCZZcrOKwVg>r4ZP6JMnVJz)1uAE=O}R%GOv-ZEBxH9U_U9U zg={S^FO&MXdJ^FNTWBrK!qr7vko8&U-h1as;uVZu;wAE0KE0p6B)eq*1N(>B#n$ zox^T<)Cg$|4Q@XA%-sFY=a=_R9Xce;J5WBQV=U)od_TYGXV>)e-Ct-F*fOV<=mWVI zyC$Da(=)7^K93^)HH4IzCFxmVx>&LVQ~5%f*kB%jsJppN_1XNy3=FrPbxRb1n?`Uy z|9L)nxPUac-%u5}w3T<+>H4@V8hGbyIm%9-ECdMwrc4(w;CFzrppsR^Y!UrI*)HH# znKR4=-|a31>&g_Hwrc}lp7KH;y&W?|PqNUBO8l=Oi!T~c zdJIXdVQ8ILeNfBr!o1LO@nU{hubOUDC(>IRl=i)}mkEri)$`lC(|}wHvk{ytN_h~u zC?&^2R7C+b`JIxmo-Bg~N<@ve|EzBV}%lt>cUg?@+U;&c% z!3g1M0n&--2&ih_9yXeFqL9=q5iHpPG>_i;e!}SjBo@ty zQf^0g3MBiXK!_PN zK7*nzEQ%6))QAhKoYlP=jZoJIrHtZLcS8*Yqli)6+XDBO4tH^YdF%~Zo@>lq1N2=( zWs?UHC@KF?qbohz0+G%Dmb&VG)3#fD0T-Q17U5M{=*Aqxi!!PKU_pO`#g)^!w~nE7 zb;ILk6NdM5`?@Gc6jp}+$Rmk640o3Z*l|CO&mDm@qTtDs&WSF2{2HH~>GwQUx*88nob^gL*u zbKkl0p-bMs^h`xe0Z5JgKyy#Xc)jlFmIsa?E`+nKu9>Ac$7hnQ)Z|%UL4-Jvn&rZM zZM0g5-;CCwmFB2S8RNyVl7{~-#XAFbd6bh(D{V6AWdv7mTf0s9!2H_o?~|(2p&x^J z*131m@31!jp<^J`NaCX5r6U0ataP}GF(20Ge+FuweI;z2^;cuxc-l{(1icAOxV^>I zoW|QYA4}OWI#|s-L95EI&^9~u#Hm!fq?TJF6b<)8 z2gq?v5D1FQ4CXmD@$OJIEQmVer!+)vgfoaQW$9M8C`umT2V${#O+qk#jp-o3`oM(< zby%uqXF7_%oV!;43ZH?6hwazDGp(Qyby9Q_wXOx?QQB zZPHG+3{9rg(-Dv>nbJ1=(qzkeX%v?3R2c58G7#U_IA)H?!8f*;sZ&82~l_1r*Gvj7}`ikh>9(je?xxV&&qc<7hDB zvV{W@*{5gDBJsQZ`|Kd$;K5)3JZ?}2TO6S0+bRy|T@@nk!M;~_gh7(|%R9UX?3K_@ z02Cf9$@;50_y{{T9CUOMIw%3pIKz$ta+WhE;O&y!+|6&Z;sCV3qKVG=>uN+~^P?2?g1`EG!!?4{# zA5QuD{L-Z_x_FqQCc?u!FgLAX)Q@SFM-g4+sqA&uERL$tAVEqK4}d5-5t0Q9gxY<$FiBla?I zl9oVzz7G;uMsn%vf`gA?OBe!Rai7ol1!9z0RWS|=hyK=zY2-i=w_6zSdmCr|8~)W) z3C#BP0jCe={m*f6Aq4T@f$+p>(AjKlqbSeO4I@>6uS!Kv10=q>AE1ek3cOT_0Nx;j zp(pP{_|WPKSHJ=OoJ(UNK3cS7JcW=tSpNGPF{-vqPAW)zC>#cyr2h9nY)c(?J!s^m zF^-*-q1>Q&P)`b4kAK_Br@aoj4p&o!v!@%^f4y3kq8|X$;tJ z((O8A(D}k}1^FRCcY9Q(OmU(ndl7ZF4`z{PP)cm1nfphv(r!Crw%@Cw z5l*t84X&^LD{ud+OXH4nLH-zIodb9VZ>@Odudo}U?`8)x)#<^5OrLZ`>dS`N1cDIp zJ{o)%=pMgHoN=`#zIy_E|U1npcI|lg>HjmpY(WQR8!~tw00oWFK+e47vA-kU=dbCcohV(vMAWB1F zKMO@KzIH(BJuF{$d?ZQqxLrBV?|)Uz>0n-Q;Yh(=qdMMODbyS0^gv1ro*_Teogq{< zOx)fnt7ULH0S}KWa?jH~NcdF_oeX2GGlLUfF?>c%aWTX?LH&H+Pmg(JkhAVMC#Oai ze1A#vfb2IJqTD(DJlf@XmT8{aJt1;FYdCLOVHPC2(EA~(%)x8$1~fQ;eqELu6r?l0+DnalP;gNLHs~+4zp%YZ~Tf=G9K^+zj6jGAfv5Q6V z@YMn*s2)y?0!{lVNrbJB#VMc%;&pzs^%D-RR0OVc$4h9-F%Hg%fdjo{p8jt^aJN!B zzKIhKRt+bfyj=+8=bLAr_NxzAz;pa|*S$niud%z|fP5G$7G931Q-2%#ALm$jYE`GM z>9x@&2NF)h$+>Od(z&+KbiEef|Z-ocW@?XPUZNV-Z*_wJd z@)!~%XgW6T+kAm9@S07647qVXWqcUm;blVn=TO_#kNi76Q^R00C(%U&eizDwBKB0D z-}*5S z0e*2ia*}_7{`M`Fp0p6dRK=?8r9flO-oJbbMO{T!zY4= zr`f#r#19J;(X+;2hw}{Y))LDBISeGX!zt3Zuh!&>H+tHZe9r$WJ1~MXPQ$cYqX=*} zPn4Aua*?K>_JZ%Q48?DWAf`etnotsij^c5IKfIy@qgsq862G3xF;{Z@=St`XCr1{u zlcuUVwEM4?FibQV!y~kKi}7 zfb5OmD0R6cS2KEW724${=Nc`Bp~hU&Uo(0+c0s{5XqDs(m79rGsp~0HMPSkynKc1- zX%D`_yfV7`RC+4#JTSH=;wv9E;xu50_|isog|GA|0;}0h=gS^T*v)0e64=3KXb#xd zz|fc5IECgeN2(AnvjNW$6GjXmPTDSdaPNdToxo~v)~13v03Crri?>r{W)SSuH8_i9 zQ9E!5?$U#%{CvS`lg_Z`9j~KW;6X~Lq2cA|^wf0^rD!DQt1a4bj9MhX;Cjl^Jt+%y zX86c{8d(}TBzYDmVSYkLGnqpN(ehGf9D~GDPF(zbzmcpN+Q^CDA!|UldGwdCP-<)= z*@1=r>*G~Y2pY7c{)A1B8p+(8ps0uXz1PcbK^@4+R*nzq1Oqg~YD*m|iVgcv+PA*PPxUW*s&0=y4-ib~VVw4L_AinUa$PGg&r?QWASw zntm}qSB}rx9%t`9TtjF&h+NF@l)s0JgXK>pgw1`-iv{2u{QNq}b8b0lTy)QB9l>yoX?< z>9neqqs+;=qf%BY{05B+i6TCiU+LmP5!YK7V_y;%TXV^*sw+3QP8 z5{Q2ztPtr*vfdKAFYQ7Z_*B=}5OqgG5g%frh0PD8Fo&B9*1qX{(#2&&JqS$?iDaqp zhkxz(*ya35L+QC|5KP&GwCh?ux1WeP79kX=Lh#=SZt=O!{Z4R7>Iw76_nkSEqQwC$AR;^(mJPqZQJ=6Pb4Vc=YW}n)}|~jo6V-_ z*vvwM67=76{zHXq0-Dc5JI!K%Q~c;5{f$JL?M9-qmGGqtwU0-v8EeA&y-%_fbWJ5h zWSa7azkUFmgm=o``Fn#{O?wXuH)6DK@iEZfvM!{b1wF##?SZ~^=~&IsivkR~uOo96JQpauaq}^PxS|ZV^#bd+4zuHmI`9wlXNqY2lX|}|6^-FlgEAZ!r5@!+1GCk^! zEDOUzu(@F9NH Date: Mon, 5 Dec 2022 13:47:52 +0000 Subject: [PATCH 090/631] update default favicon --- priv/static/favicon.png | Bin 7132 -> 5028 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/priv/static/favicon.png b/priv/static/favicon.png index 287c75bfafa195f66b769066d3b13a9dba88e40e..1a12b4ad8acebcd289c638c37e532c6e84584382 100644 GIT binary patch literal 5028 zcmV;V6I<+wP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGjod5t2odI%Y(7FHs6FEslK~#8N?VSg3 z6xSKYx7-~%wNo!h6bT^^LiBEm4T3-@Cbj`%6C69kP+SLh0UkSmF&GjI2xAk+CYVr+ zDFOqgm;kn9z!Fsm6;wbC^{&(1mb~v~&!YfBS9ag7(Eet2*gZ~nd;9(0_kHhsZ{Ly= zVwUiPO1p&;{#B6)7roBxVbGg|L+q#?KnC30UHI5(ec8t+#!z9AL8uY(MACn6@@tpw zCs>9fg|}fr6#z!S@Kc{1%uky=jP&(4{GXvYjw2S&-O8k0y`vFc!h#wCFrd-U{G?|F za$66+%D?#9AEKlpM*(KOjpb9`D z4Bl?st4pVFtN;0urh8N<)mjTr`Sli4U)MwnhuBaBAOWK$^x`&uw~(ANa~Or(zwm0y z@H|hPICxnWTc`pM5&s|q`{9P!?E9b0qWl89Y|F|ZD{q)IlSir&oHbifVN0rh!^+qmbv_E%buh>4Q_TDv7y0896xYb7UKh| z033v(DSpb#!Cd_Ah2(%?-6@3dKlX7l;SyU@)gYT4Q~@|ZP^dSz3bp!|^Yh2jTCG-iRU8;I zgR=k2iWr4e1@HjEA_Lh^zkZ1x6&pi}rPV^csVYo7uzDg?G{G zXq1h&+E=cru4l|%`qLW||fZnYGKY7MrE_P}^s%u0bvV-)7fOyNYEaBqfBHNt% zd)c`1Ab)uGMMZ@G$#a0N5dqwmy|0k-7Eh$Zx(7*ae7M7=p`n3*_ z_W-tp3t9NyEMR6bN9ac6`Qdlc)oD%`b1;ChDVNW`Y zMx$lZgW*LUxf6?q`g-g)e%gZM0@%MJi8q@V;YfVIPw@@|#SSiRWr+)bE0+F9v#&-@6fZ4cCT@=U%04NH< zMORWKu&T0>aCLJd(C?(C%osxY1$wgS*YgQuqgl3-lwAM-@{VL~=3VmW_rDR6ThiV%Pm zxB%(b@~MPf=Pe$gQ5E^o`O89_a1MeH)=}@u=e*+03{M%$ST7&@mj(nE0K)phT zyugD1p^u-|pX%7fmqkf3I#)blq0OulIB-Nn)5_0Z(4Yj*sXKMR2#_Q~cz~f|oL-^2 zx|%Q;48l>%R8`dTn^q=p=T4+besYTGjyw#CBDrx>`oV+_i}AsTU_eJIfY$uL4Y^_{ zA;Zuy%pCwxNR6#M6YvI0);>$et(nPr81#~sITaZKnghmvYsJ$n62R}x9^5yyTrePP zU_3`!GKc{LWyuo+5x@qYZ%x+30zMy-KwCo(ybmVNjQ&FmnUhh>N|hTZS^y6+eska= zS;YVz0ro)!3H2r#kuaboL+F6_ zJP7OeTSqG4ea?6kIH$gY!>H)~U0_WC4kd`9c>~1?VA||q%&fnTwmaK{i)A&UHQ}?q z<_J($2Co1c7!ndk_)IV;7`MEv%u;KBtq~c#wx-6?)r0rI90f6pQNf`;Q0z3HOt`|GNVvpaxsVOZwo~Zyks#Wp5VSfCIc8!ERastV&b(3R zln4~(0p49T!#s9!U&lN80>(xYzx%7R+>yN(pvrob=DXc&t>o%Rwi&Ig;h3PnD8D!#Hb0qksx{z zA)Wo&REPi(9Nu$*-L&$MLn2U22msgr@s__(de;sPTOTgQp0Cew8&)KcwRWt&iCifG zq2ZTPXUwe>XYIE`PXabbB9#h=V8J_+H4~p2X!l7fLIB-+bu>?%HN>g7 zf9BXVcE=b0b-KBlni%5acXtzocgiiH5kvr+wId&Y#?HS<_@0iYA- zUtKy4{o}apVAZX4AMA4~8*WZzSsnGsyWib+KZ8{aumMUF1L_?R@2{Cf+cSP3y8uRv zjbeKA4t03`7P$WPA02>27ll{EA^mzjwSPxai>;}-7+|vsLGDlix8W^%Z?bUIIe|{A3SaEk%L>C{<6g`m)K)jr*HUst3G6VknUz*V?A&^Wid(Rao;hX}KmX~C+@_U> zEM@9DIVFr(H`3agRm)NcLg&W6zU)a@gWq8RK&y;jb(ljJOp^HD9CuF_Zt%!Rr@u$< zsv}XWhsVQOKZ~rYs3$X03&_Nu(qJ+yN<0%;c#d#(dJ$PsTFau}$GPZr6!MtDpR^8$ z=&R3uWHM6=TfM%rl!6}{*US9DKb~{Sb>F&KWL`8gUQ+jO1@)~>pY2#6%Hj?%yJz8y zcnak&_VjysAAfh&+sB>m5)r_1OFcnM`I5iHXThFV>_aWs#^W zYt!e;B7luM7n&oZL!2_+@q;O*b<6f)S#iTZ&|v!Z#M`2M*BgKS!i;(@Sj5{J*mD4= z`k_q`KVB}L{p%QEPkyiqVEXeTEZvm0gxIG$V0eVa*WW`Cw=-iE0F3yJp3qxyw@9}} zul`*`l>p3iik;RUe}(7)U=_f4^rOX^<`ogu5!<;>dTNm9-}S_#KCm=B_WbK!uw6v> zu@jygAlmnZbr00^9?(_tHFt)M>B;pS5+-_A6DpuE4k8@N1~vio=pABqrtEt!kVm}v zw?9#yUapdfVBqiw{{1yGC0k;4%FH3co_t^vz^L)PMgOjjoqfsAzMW5ncJUK6p1SCD z++SXeWj@+CheZ3rtKx$^n8w{xFRK^8QVB$HpM7)rQ?MYk=uOGP;7b1SnL)7F0&_d3 zl&`C4bXaJRq)vZsIQ#yZSrkkwy8He0fRD1Di19Bz^&&=D-jy67IMeI3j|K>eE>x=Di5Ekerld ziktrpmV(xUz#@RRS3YBoood@HUSa~n#btMEV3ErEexp{WfqMgF?~=lp#_VycS>(B7 zITy)u0BC80Q0o#7u>#4Pe~>{N5bUM9cT_J zYh+-%p7>!8F@w53S^_|dCUiPA{M$-ku$K-Rjc|w!$pjD?9ij$*JAnK8`~p2C4apBe zvM)qk8`-K`ZIzxe`11fs1OR>7Zasr#8{ulJ^ynReeVUjg0)RfP!P^bHJ8SEB`QR^^ zOJby`KAnX<6?=f?@q}G$NFspF-TZ|;6?<^^)azjKjBtnrNd!<`Y5M|Aa#LSxNK)Val(5J^ldy{g(FFhlKuVqi z0IvVX11S$}WwkYpn(HaKvP{r`F#(*2E&$Y(QLOu~EU)8My}O5ekn6vf(?_ogdyh6) z6An3nTLadAcmP)BvZ;si+b@}xzj@SYHv-uA?_bQnp1EmrAG@NoR-1XFP~K%fG0-jq zkds-=Zi_!N0C;l9s(1GAjy!4W%&}{ad>DA-1+ZoH5jO8ui9@M% zaY5xH9|lAh0K>4dmQtH@?)Y`)*#2av%F?HgToLy0key!Kw#NcYMn?8!PXHLy`E2ipW`4wJr82F5{$dd?%l2cw< zi#6#GT>#MHP~wHPoY@>m+P++Sl*vdf5Ur$kU`HahWDt2StYuV5l0bOchOmpB;|EjB zhjyPAHIAZ0P;>A8u}EmvT!MZi97#Bxyn51x_EiDybL9N-Grh@F9r+ZlxDd^|eN9*({9j zuY7A4Z)=_3Q8s^a7@pTFSvNQFr!=hYACN=<;KoiJzKkUdfbn5oUvAc2$z3P(2w*@- zickQ*kNcC+b&^&CR^vCH*C#bFptN<}G10q)sKIc!<3Avo0J3ftNt!uB z%zt@SJb}~rR`zXA1P>?LZ-a&c4MsS`iev%+HY`6#LMs&xMFUE_i(mMXFUqf!^!!@_ z8I1gN$@iLntv@bGIDq658jNs=6-k$hMg3Z;ytIZHF*XX8Mi*Xn97w>ntp0)ddgDor zBcppFL#AHJqq5S9%>9Ojla4Nf3!ZGnTRUM6qAb5h^0k7qGm2?sIMa~PJscJR7=HWa zQ_PyUy;S=3eCX$6PnKFDKd+4b@jx=y!9~Z0M+Q-_{;%*~tx|ZqoR3@Z4OvlEC!3hD zJv6HC;Be;k52jHeUHokNu~5&4=k@)t=K^){=L~2e*b^jsfycnWlR!qsMw9Sdq?QB^ zzwPMvzcJfCKShZ#Uf~Q_pBe@?J`Nrk$;0B2Jz_#RcMlhxwK1Dbj0x)Zs8z72J4D>L zatE?}S>mD?c>B4VB6@Zt{ewJd>$2m}ExKD+$tdZ!$@17Z73CmzBBdfTssP$KssP$K ussP$KssP$KssP$KssP$KssP$G1o1z{X9}TpCzd(@0000Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D02p*dSaefwW^{L9 za%BK;VQFr3E^cLXAT%y8E;VI^GGzb&8%;?>K~#8N?c5ElWmRBsRe8UX^l}EQ>~g%O;c!1X=_t!f%G(sH_g>z;MqzUQ6$HS-<_c#}2vzH|54XYc>|um4(mpL1tvjb1M) zc4o0p7rXBTFL+_YcG+dOX3tk1+#GuFDb1#h7dKnacyF`q><={;ocrPCP1}C6dCP@2 zjoDk@{M(&rxA}y($GLm$c|`NFm;6HWiaic$_I~w-=D__=Z`L1iQFH8ucZ3~(>{ZPh zj(b;U{$`stUOBf7^`URq*>|6l;`%@PGdne9e(b(tA1=18*wglUaj^vX`^92F1_q=P zkAGWp)|u~b-hBQ?n~N^Eu`_?a>AV}73(xyV7~mau?2J?1-5kCC+yHp@m+u#5vWFjf zK}@~|BtaPg`_5IhKKQRc`qFUnZoBRkL@INAqS%*;omgy5UoR}Sq1dg(I*>6BP-mWY zZGeca0b&8O2DcBg&!_(4RRz#9q7Tjj_Q4086_czdJ^~gShe28ktFM3b`b#3ZcHU{1 zWcfFXA>5k0URmtwV)qv7KtASm=Z~@2dmr31z}HL`1sDuu6X~;fEttDKmZ1BLB^NQk8!=Wr5`Ne{U&@MjaqwI$#Zcw4E6_+KlwQ?Z3#WaIW? zPwH&l-bV#sDFs8o)|T4LF*H3TgWjbkKN~@=%^b`{LT{@SW#K{<3Vq&IjPOU8s1(lL z@_~ie3}^{3*=#_vxdF1F!9N?#Tu34PZUI*cD~o5oguuncLZ5X&V=YAH(PozIjz8{~ zLz|y#Z0_5DoG6E9Rwsadd$FjUfn;HVrECb;+EO;o-TE6*X*eI)y#8DSxi<3?wIUdH z#pJn(FSJ*2JX9?7_2iST7_oE?*+`(3bO#>rhOW}ED0!{}&63^b+)4>$7<^%L2Q)TH zgmVL3+Gy(>Ni=1{AOPJT*mKp)RfW}-f~vO_uau65cm&Xr+PsNS8xmvF$hjiI1)mRW z?wdKwOE4&Svay${Loy7F9s_!gM3`DG5xRid`T3yFlWnvxlPFs$8GFf?QFQ>Tla4un z#%N~ilx&PPp+;rh^Al(`0^6#x-Kgqb*74T!k<7@zBGOR;Py@pKsss;VSj z*6-HwQAd-3d6Oa8_$knn4Gwf$qyt)scT=$^QQa~ccyra!Z9C3c3H0#ApKq2D3L9Xn zJRY{vIrz1kW8Y$4pt0W~CzIh%fnI4Nu&<1I8`$^Cl;~o}(0%7tm(alKEbpEkjUL^MWv)5RvK@Qo^2c&T5@2Jt zRgUCHd+o}R2b)cOzyWQyFL&;8!LpW<=>zLpk`CDtQJifYY5sQH_xcA z__ZWRZLY=n1=rZvPTN+@^AGl|qdIXH2FPjtHc1lz#_9t-3OfcIASJl_yynnm!}=qe z3(kIH^VSQuHS1ozceC4zUes(pI^k zTzkc@G`D@`6V2cM?O!zi@h^YZ{P6yNiocIK^pF7c>MdtC*PVNQyaOEgK3{R#8O>#z zPmaHjf9*ldfv?)L+2f^q#5`OB2zlMLV)`_&^JS0Zaas;!a-w1}NGFa4H{AK6wmjL< zBLP4@V88vFw_SWu^SMvl(tPKeUu*vNzrNQr|NVoe`O(A6_QQwbdu=iKy=R}-Ty@5l z0CcaHzO1?Agp5{nl4 zUF-DfuweNPx&$I(Fd4{y{-r-`9{IO>$AE1fePG-Q_)k3eug&}4U7S<^#$cdgx~M#I z-97=nV^|JspMSM=%00H@}hTFB9aXm%Hczw#p;J4lt|X{bX}WhJ;KK zK6T5D%OGQNAKtzWJO8BFbkq?YyD|6YcHTLRq$H~Wp5~agJ_DV$8v{*Wj@;D& zd~UF_EL_c{xITcby5K~s*G(Ia2{s3V0X+mP>odGKgno+#Oa>nL0G-McQ8MXYya4T zAteAN55N{B9KeY{oCJ0nY0(DDRWATv4RWOtm@iN#y(GwoF?+S-!@x~IsEQVSpLE>D z=AOU)$_VHJS`F@)6$XF%uCGQ_@;7(<(Xvy#7rXv_*96!Y3hcuUJfQjb%{N4QjCXt% z;G`yHh>injM+uhEL5fGPu6)^Yy&V{`^^SXZ6iWIbM=#%X*U(cna{xCBXja;g8Bq{& zlTy=yo=Gy94eUF<@R=}R0}y+MK(38L^uckfQR3#g`Wity{&H)~&E6*@#~t_XIM6gv zm;ytcoXi{pwr_2l-}>Nn%{g1PG~fN!UCUq(Xtt!tk)(<2h@O;^exe*Q?JSJOwgBG@7^}DU0^Wt7WC&=hJB*XaLI$SD2ao{-H1DJ% z7!Bx5q&~N-rvIXbGcDaM;p6)Pb}o2mFaU?Z9WqiPQj8yA%x7`pjq;Ve*FN*tz5HCm z4EH$rmx zo@yjbTje78BLUmDA2b3R7Am_yxqW$N8XAc6NJ*{RH6}yzo@9xi2rt-n zVB1!`3Hsab#gTkiY3hT9VulF~KBtTsuIpus#_?_!N5UWG_9Cf#TQ);ZKs0&s zQm!8p;wT^_7=Vd-JQ-UXkQtEsQd70T@Oz5Ba~!}`L&hVbLRG>MtdhGzy=yXfKHc9G}&T70^pDfa=-^%xNont!PuD(wxsaedyDj49Y;Q{MCWUeKG^W4P1a=LDDgXL^qDba>XwA;u} z7Q1?>{UbztdDCUKCZ$t22xtaWmsOZeQnI!ND7LV?E8dlA?XtWEYF+~jsqjAZeK@Tx zAyZN~9lMig0FU#@TxsXCAcnduwg+v@>cR2e(AV?TCdv?$CazBwTc4L2WA zJS(qpgzu~R`p#nOmfSV>&<(J&5}73<+GLprIFg`-O|Y?AW;Z}Oh_!&lAfbrSs|s{& zLv8vdiVEA2!1&BTlBCS_w$E%?0R@NM|f?5}!)1N52&FIGG13_uc39b0vV0 zBSu-)g(VN~^>Wxdt)qFC%O*yvF$trEbFgd(h)D*>WF}eg-bxRhO^bHfM*C^<)B=tK zKmoXfiP;jW(hu0)fh~H?Y1Uo|{Ho0-KU{LxYu!>lk?NsJOl8yLBs)@l@U#KcU}xE9 zfCj9>FnIt=Vxf)m0u87t^d&?3pVf+xCrvaMBfWF3@3i6IxSsPTU9%-ZRxIR&q|kJ8 z0=78<+uzteT}npPT(uwK>9TFbZe8*WUjpu7O61CIXS+>a?Lo(s~SdF&*uDD(qo9n1pFq;$Uv*-l2 zxh1oGo_2rIG1$SV0IUj8Uw^*X;{kR)H0c3%zdXR&m1W?v$8wdJUI(`Kx*EykxR7MD zOcvVMCA?KLoCe5`+;DUA2cNsGx#Lg&viZi{-)g@7&-XXq`~H764?psFn9q*+PMhET z_^0DM;Bx}dV?1r7jF~aEq!2CSBDWlJBTcksE<#AS^rZyYy^`j}05iPe{%d}<698zYS8WV56RWWWGeV$%1fO(z6!zZ z(2y8R-o>#v6QN@{5XU&cV1;E&pq|i>l{WNT$lEZwut>lcKJ@F&H$M4$@&1l;wuUT- z6zs;@n$GBu;yljNul~u4B)9@_pNrA`T1Jou*g!_8Nm2srN%26<`k~OdVjk3*;S-)MjA?*krrGXd~Iggj5AJuzf2Nrjq~x#Pyf{Qu7a={r%?O zZ~t=hz#rch=5L_8<{LL17r@i))NFvJrEF-UEr9j;XE%Se`OX(V8}E)gUou=lhVnPL zsS{)kHZsXoR>u9kl8pYg3JKFD{~MFLm>0(Le=mf}M3Wpbf^Ld?z_#&%{ln zwDKKB1C4_KngHK-+vhv0k0sjy$gsXPU^sr```#76a@74_{$ke$Cw}#oj|JeayJCz* zx3ly!rasu_XWk-Nv^dQ(wvSc29=P89hPp2+tB?4GlnBS+@ zNy1dUF2`v!UB_qu0s=5K(6!Z|v1|)ahPnMVb-V1tbzIMNm5WiI=Qs=42p}?Y1zCfg zBqOEdbCf7YE9#UGVCPTKkrvP}od`Co6DB~j$j5F2k#sOv(y<^gm|V;#pJuTdgD?ye z`=HD+ZKv7LIceF(b!mCXNmeK=3CzhnkS8mU1Un-e2AL@RaxV9-hk#~N!Dax@A1v`C z_PQudlStIB7>vmV=R1taU9=S-r}r>rDFB^!48UhRho+R8a5s3K5BNNz%V2$W zve?&bK&wy^X#e#GpxF>+wJpulC{0_XAh4B2N~C(AHhF*-Az2T8niUqAm<^}3l#`m# z33N!I@%QDffQ>jLf+lA*0&GBA#92-I{|&KuUJT>r!MyC&PRD+xC&YpkDJ9IH4IblJ zJ%LHqwi79`zuI@T0oNBJRiwk(V63*Tt;_*gEOwNBSPg8S)zu8pc1K~d2w9ihrCF5S z3U)tjmRLG~bFeLVV+m)Lm2*@twl-HA@a)6#U2Y&*DyIN?Xnf_k=;RPmVF8n1t2(w9 zXl<8h&O+=iVWTZ}=Tl3O3|k{57CY+j(C#7j3|Vm)Spqn%lXcv+#4Ys62H}<8{}|U1ZbGSc*#P=3eg`!4TsEya#d*$fxZb#gES$( z(p7i*9Cy|i035?@&E}S<&$pSjkz7V1=04 zD=e0H%VyI;>~1@-s*GiPkrXVC=Rpd{`V(qEw~Sv1@K%OIjF6YeB(*FH$;&LO>u7So zc{3MTtc=lh%>&p#uB#7o9r{05rWu^_hWe5fpPec<3>NiRGF+W0GxL1*r6y0n$HI3W z9S3*;#yO(JofWKn^zN@U5B}9x0?0H{k)M6XwA0@C@uXDt*}qP0Wo$@+)i5C&v>Mn} zixQ)o0OmU{*eM@yXz$#No?dle5q77!u=D&E8T236{!c)EyI44(06vzOW=%W|6RY-; zE`|bf$VhE;Sha^eA&4V1wL&{n{oTuLaJ2$!)Wp{1PQ>Exf z5=pOehNZ0I^c_d6Kw2OZv#yfo7XH-Y9k8Bhra9( zhKxWxOB&z+YN&&0=Db|+&^Dj5FBj%v8|{|*DvoaBXI_@Cg|$HEY7rL3?!TZ`>gByw zVCQz~JPHu=F5j!z;A#~r(Jt9IvNEzN!ahk)XG5J#Go1t01^WGDNb$7)z8^y*E-a74 z^-O?HUdlC%L2?(}fHp?bCrJW0Wh85DH&S9wQwV9Uq%`(Tiq_M7eJrImrRRW=zzuaY z&GI62+kpLDGa&vh{pPJU6H=|XW7B~SgduQN%Q&@MhrX*)ETS-4L;_l_>4TkHs+lCo zE%w%Puji;A?Z}7nQ6J7a0!zHBj@Ia|}dPf&oKilE0Y1k@~xh$tpHrb&`xS$oPCYFHtPW%=ZilC4Xm^MbA&18iD*z8t}saf7)y7Z@be zIJ^6W1uX9pIFWhywv^ZpyDL1W4r&5sZm`lNaaLU}xmlc`eWJcSLg;vukNv z6;>?kcY+yI3i4XQ(C9>W$1 z7JCdjpLH8*8;&TTORAn$^+2SjPdzvZbbz}n6jh33*9V&e3gD!MWMH%i$>;r2rvZm` zB6ixgvazT3CQB2e8W(djb~#FJ(l2=$VszS4e&7wPFsQ6hYB@=H=nrm^nM^Wv)~=%O zLMMx3JQ$ge20!}P|Hb3JoPfDqS=a}>I6)%CEaT;*`bk!Q1D{j@aZ(;(=9xqh1#(yd zn4rTbbz6QCDcUAc6Vuw98(?QAJSl92VJ1!;t4;tn4Y0nMOomq`+ldowJACd*1F<4(JnXIYF%Ov?= z9oT@y=5}W)K=-BN!bTWQ)455etr9X4$H0oRw%R!-Y~B*AOrUDO$wk!PtyX)tiR5Mj zpfNhnVLp>2ea^FfFh=u4FnDB?Cupevq{LoNfL?L~ypps-7GV1a^<`PhR$v2H1IKlq zNrAVgg<#*bOZ_7e)0Vl+L}hi3?K9M8>;$;lIrO_EP4WTgl%E>tH0Oz!O!h<9W+{~_ zDccFaHuoBAm}H`L<7HA!-M0WcPX;ic8DLYZ(ivHshJF`z&I5SLLu&V|T}8*4YuFw1 z3xfpDJ1{vx;0S1IX)ht|mw zaNZdJbDWqyiPg1MN8dA8oofTj@ys7e$$piQ1SKK$!pFO|zVluKe$Cc%n*Rs+Hy#kR SmkNXc0000 Date: Tue, 6 Dec 2022 10:57:10 +0000 Subject: [PATCH 091/631] Allow dashes in domain name search --- lib/pleroma/user/search.ex | 7 +++++- test/pleroma/user/user_search_test.exs | 22 +++++++++++++++++++ .../web/activity_pub/activity_pub_test.exs | 10 +++++++-- 3 files changed, 36 insertions(+), 3 deletions(-) create mode 100644 test/pleroma/user/user_search_test.exs diff --git a/lib/pleroma/user/search.ex b/lib/pleroma/user/search.ex index 6b3f58999..ddce51775 100644 --- a/lib/pleroma/user/search.ex +++ b/lib/pleroma/user/search.ex @@ -62,6 +62,11 @@ defp maybe_add_uri_match(list, query) do end end + def sanitise_domain(domain) do + domain + |> String.replace(~r/[!-\,|@|?|<|>|[-`|{-~|\/|:|\s]+/, "") + end + defp format_query(query_string) do # Strip the beginning @ off if there is a query query_string = String.trim_leading(query_string, "@") @@ -69,7 +74,7 @@ defp format_query(query_string) do with [name, domain] <- String.split(query_string, "@") do encoded_domain = domain - |> String.replace(~r/[!-\-|@|[-`|{-~|\/|:|\s]+/, "") + |> sanitise_domain() |> String.to_charlist() |> :idna.encode() |> to_string() diff --git a/test/pleroma/user/user_search_test.exs b/test/pleroma/user/user_search_test.exs new file mode 100644 index 000000000..5ea5bf774 --- /dev/null +++ b/test/pleroma/user/user_search_test.exs @@ -0,0 +1,22 @@ +defmodule Pleroma.User.SearchTest do + use Pleroma.DataCase + + describe "sanitise_domain/1" do + test "should remove url-reserved characters" do + examples = [ + ["example.com", "example.com"], + ["no spaces", "nospaces"], + ["no@at", "noat"], + ["dash-is-ok", "dash-is-ok"], + ["underscore_not_so_much", "underscorenotsomuch"], + ["no!", "no"], + ["no?", "no"], + ["a$b%s^o*l(u)t'e#lo/t", "absolutelynot"] + ] + + for [input, expected] <- examples do + assert Pleroma.User.Search.sanitise_domain(input) == expected + end + end + end +end diff --git a/test/pleroma/web/activity_pub/activity_pub_test.exs b/test/pleroma/web/activity_pub/activity_pub_test.exs index 1ba1ad96a..17c52fc91 100644 --- a/test/pleroma/web/activity_pub/activity_pub_test.exs +++ b/test/pleroma/web/activity_pub/activity_pub_test.exs @@ -725,13 +725,19 @@ test "it should return public activities that reference a given hashtag" do user = insert(:user) other_user = insert(:user) - {:ok, normally_visible} = CommonAPI.post(other_user, %{status: "hello :)", visibility: "public"}) + {:ok, normally_visible} = + CommonAPI.post(other_user, %{status: "hello :)", visibility: "public"}) + {:ok, public} = CommonAPI.post(user, %{status: "maji #tenshi", visibility: "public"}) {:ok, _unrelated} = CommonAPI.post(user, %{status: "dai #tensh", visibility: "public"}) {:ok, unlisted} = CommonAPI.post(user, %{status: "maji #tenshi", visibility: "unlisted"}) {:ok, _private} = CommonAPI.post(user, %{status: "maji #tenshi", visibility: "private"}) - activities = ActivityPub.fetch_activities([other_user.follower_address], %{followed_hashtags: [hashtag.id]}) + activities = + ActivityPub.fetch_activities([other_user.follower_address], %{ + followed_hashtags: [hashtag.id] + }) + assert length(activities) == 3 normal_id = normally_visible.id public_id = public.id From fdf33392b37dbff62cc4d76f603b160366a5091c Mon Sep 17 00:00:00 2001 From: ilja Date: Wed, 7 Dec 2022 11:05:35 +0000 Subject: [PATCH 092/631] DOCS: backup restore improvements (#332) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mostly add how to speed up restoration by adding activities_visibility_index later. Also some small other improvements. This is based on what I did on a Pleroma instance. I assume the activities_visibility_index taking so long is still true for Akkoma, but can't really test because I don't have a big enough Akkoma DB yet 🙃 Co-authored-by: ilja Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma/pulls/332 Reviewed-by: floatingghost Co-authored-by: ilja Co-committed-by: ilja --- docs/docs/administration/backup.md | 50 ++++++++++++++++++++++-------- 1 file changed, 37 insertions(+), 13 deletions(-) diff --git a/docs/docs/administration/backup.md b/docs/docs/administration/backup.md index ffc74e1ff..cf2f7d1b0 100644 --- a/docs/docs/administration/backup.md +++ b/docs/docs/administration/backup.md @@ -4,38 +4,62 @@ 1. Stop the Akkoma service. 2. Go to the working directory of Akkoma (default is `/opt/akkoma`) -3. Run `sudo -Hu postgres pg_dump -d --format=custom -f ` (make sure the postgres user has write access to the destination file) -4. Copy `akkoma.pgdump`, `config/prod.secret.exs`, `config/setup_db.psql` (if still available) and the `uploads` folder to your backup destination. If you have other modifications, copy those changes too. +3. Run[¹] `sudo -Hu postgres pg_dump -d akkoma --format=custom -f ` (make sure the postgres user has write access to the destination file) +4. Copy `akkoma.pgdump`, `config/prod.secret.exs`[²], `config/setup_db.psql` (if still available) and the `uploads` folder to your backup destination. If you have other modifications, copy those changes too. 5. Restart the Akkoma service. +[¹]: We assume the database name is "akkoma". If not, you can find the correct name in your config files. +[²]: If you've installed using OTP, you need `config/config.exs` instead of `config/prod.secret.exs`. + ## Restore/Move 1. Optionally reinstall Akkoma (either on the same server or on another server if you want to move servers). 2. Stop the Akkoma service. 3. Go to the working directory of Akkoma (default is `/opt/akkoma`) 4. Copy the above mentioned files back to their original position. -5. Drop the existing database and user if restoring in-place. `sudo -Hu postgres psql -c 'DROP DATABASE ;';` `sudo -Hu postgres psql -c 'DROP USER ;'` -6. Restore the database schema and akkoma postgres role the with the original `setup_db.psql` if you have it: `sudo -Hu postgres psql -f config/setup_db.psql`. - - Alternatively, run the `mix pleroma.instance gen` task again. You can ignore most of the questions, but make the database user, name, and password the same as found in your backup of `config/prod.secret.exs`. Then run the restoration of the akkoma role and schema with of the generated `config/setup_db.psql` as instructed above. You may delete the `config/generated_config.exs` file as it is not needed. - -7. Now restore the Akkoma instance's data into the empty database schema: `sudo -Hu postgres pg_restore -d -v -1 ` -8. If you installed a newer Akkoma version, you should run `mix ecto.migrate`[^1]. This task performs database migrations, if there were any. +5. Drop the existing database and user if restoring in-place[¹]. `sudo -Hu postgres psql -c 'DROP DATABASE akkoma;';` `sudo -Hu postgres psql -c 'DROP USER akkoma;'` +6. Restore the database schema and akkoma role using either of the following options + * You can use the original `setup_db.psql` if you have it[²]: `sudo -Hu postgres psql -f config/setup_db.psql`. + * Or recreate the database and user yourself (replace the password with the one you find in the config file) `sudo -Hu postgres psql -c "CREATE USER akkoma WITH ENCRYPTED PASSWORD ''; CREATE DATABASE akkoma OWNER akkoma;"`. +7. Now restore the Akkoma instance's data into the empty database schema[¹][³]: `sudo -Hu postgres pg_restore -d akkoma -v -1 ` +8. If you installed a newer Akkoma version, you should run `MIX_ENV=prod mix ecto.migrate`[⁴]. This task performs database migrations, if there were any. 9. Restart the Akkoma service. 10. Run `sudo -Hu postgres vacuumdb --all --analyze-in-stages`. This will quickly generate the statistics so that postgres can properly plan queries. 11. If setting up on a new server configure Nginx by using the `installation/akkoma.nginx` config sample or reference the Akkoma installation guide for your OS which contains the Nginx configuration instructions. -[^1]: Prefix with `MIX_ENV=prod` to run it using the production config file. +[¹]: We assume the database name and user are both "akkoma". If not, you can find the correct name in your config files. +[²]: You can recreate the `config/setup_db.psql` by running the `mix pleroma.instance gen` task again. You can ignore most of the questions, but make the database user, name, and password the same as found in your backed up config file. This will also create a new `config/generated_config.exs` file which you may delete as it is not needed. +[³]: `pg_restore` will add data before adding indexes. The indexes are added in alphabetical order. There's one index, `activities_visibility_index` which may take a long time because it can't make use of an index that's only added later. You can significantly speed up restoration by skipping this index and add it afterwards. For that, you can do the following (we assume the akkoma.pgdump is in the directory you're running the commands): + +```sh +pg_restore -l akkoma.pgdump > db.list + +# Comment out the step for creating activities_visibility_index by adding a semi colon at the start of the line +sed -i -E 's/(.*activities_visibility_index.*)/;\1/' db.list + +# We restore the database using the db.list list-file +sudo -Hu postgres pg_restore -L db.list -d akkoma -v -1 akkoma.pgdump + +# You can see the sql statement with which to create the index using +grep -Eao 'CREATE INDEX activities_visibility_index.*' akkoma.pgdump + +# Then create the index manually +# Make sure that the command to create is correct! You never know it has changed since writing this guide +sudo -Hu postgres psql -d pleroma_ynh -c "CREATE INDEX activities_visibility_index ON public.activities USING btree (public.activity_visibility(actor, recipients, data), id DESC NULLS LAST) WHERE ((data ->> 'type'::text) = 'Create'::text);" +``` +[⁴]: Prefix with `MIX_ENV=prod` to run it using the production config file. ## Remove 1. Optionally you can remove the users of your instance. This will trigger delete requests for their accounts and posts. Note that this is 'best effort' and doesn't mean that all traces of your instance will be gone from the fediverse. * You can do this from the admin-FE where you can select all local users and delete the accounts using the *Moderate multiple users* dropdown. - * You can also list local users and delete them individualy using the CLI tasks for [Managing users](./CLI_tasks/user.md). + * You can also list local users and delete them individually using the CLI tasks for [Managing users](./CLI_tasks/user.md). 2. Stop the Akkoma service `systemctl stop akkoma` -3. Disable akkoma from systemd `systemctl disable akkoma` +3. Disable Akkoma from systemd `systemctl disable akkoma` 4. Remove the files and folders you created during installation (see installation guide). This includes the akkoma, nginx and systemd files and folders. 5. Reload nginx now that the configuration is removed `systemctl reload nginx` -6. Remove the database and database user `sudo -Hu postgres psql -c 'DROP DATABASE ;';` `sudo -Hu postgres psql -c 'DROP USER ;'` +6. Remove the database and database user[¹] `sudo -Hu postgres psql -c 'DROP DATABASE akkoma;';` `sudo -Hu postgres psql -c 'DROP USER akkoma;'` 7. Remove the system user `userdel akkoma` 8. Remove the dependencies that you don't need anymore (see installation guide). Make sure you don't remove packages that are still needed for other software that you have running! + +[¹]: We assume the database name and user are both "akkoma". If not, you can find the correct name in your config files. From 09326ffa56cae01f80d0125f4b8770d077e02967 Mon Sep 17 00:00:00 2001 From: floatingghost Date: Wed, 7 Dec 2022 11:12:34 +0000 Subject: [PATCH 093/631] Diagnostics tasks (#348) a bunch of ways to get query plans to help with debugging Co-authored-by: FloatingGhost Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma/pulls/348 --- .../administration/CLI_tasks/diagnostics.md | 30 ++++++++ lib/mix/tasks/pleroma/diagnostics.ex | 77 +++++++++++++++++++ lib/pleroma/web/activity_pub/activity_pub.ex | 4 +- 3 files changed, 109 insertions(+), 2 deletions(-) create mode 100644 docs/docs/administration/CLI_tasks/diagnostics.md create mode 100644 lib/mix/tasks/pleroma/diagnostics.ex diff --git a/docs/docs/administration/CLI_tasks/diagnostics.md b/docs/docs/administration/CLI_tasks/diagnostics.md new file mode 100644 index 000000000..25572da8a --- /dev/null +++ b/docs/docs/administration/CLI_tasks/diagnostics.md @@ -0,0 +1,30 @@ +# Diagnostics + +A few tasks to help with debugging, troubleshooting, and diagnosing problems. + +They mostly relate to common postgres queries. + +## Home timeline query plan + +This task will print a query plan for the home timeline of a given user. + +=== "OTP" + + `./bin/pleroma_ctl diagnostics home_timeline ` + +=== "From Source" + + `mix pleroma.diagnostics home_timeline ` + +## User timeline query plan + +This task will print a query plan for the user timeline of a given user, +from the perspective of another given user. + +=== "OTP" + + `./bin/pleroma_ctl diagnostics user_timeline ` + +=== "From Source" + + `mix pleroma.diagnostics user_timeline ` \ No newline at end of file diff --git a/lib/mix/tasks/pleroma/diagnostics.ex b/lib/mix/tasks/pleroma/diagnostics.ex new file mode 100644 index 000000000..6e83bf6f0 --- /dev/null +++ b/lib/mix/tasks/pleroma/diagnostics.ex @@ -0,0 +1,77 @@ +defmodule Mix.Tasks.Pleroma.Diagnostics do + alias Pleroma.Repo + alias Pleroma.User + + require Logger + require Pleroma.Constants + + import Mix.Pleroma + import Ecto.Query + use Mix.Task + + def run(["home_timeline", nickname]) do + start_pleroma() + user = Repo.get_by!(User, nickname: nickname) + Logger.info("Home timeline query #{user.nickname}") + + followed_hashtags = + user + |> User.followed_hashtags() + |> Enum.map(& &1.id) + + params = + %{limit: 20} + |> Map.put(:type, ["Create", "Announce"]) + |> Map.put(:blocking_user, user) + |> Map.put(:muting_user, user) + |> Map.put(:reply_filtering_user, user) + |> Map.put(:announce_filtering_user, user) + |> Map.put(:user, user) + |> Map.put(:followed_hashtags, followed_hashtags) + |> Map.delete(:local) + + list_memberships = Pleroma.List.memberships(user) + recipients = [user.ap_id | User.following(user)] + + query = + Pleroma.Web.ActivityPub.ActivityPub.fetch_activities_query( + recipients ++ list_memberships, + params + ) + |> limit(20) + + Ecto.Adapters.SQL.explain(Repo, :all, query, analyze: true, timeout: :infinity) + |> IO.puts() + end + + def run(["user_timeline", nickname, reading_nickname]) do + start_pleroma() + user = Repo.get_by!(User, nickname: nickname) + reading_user = Repo.get_by!(User, nickname: reading_nickname) + Logger.info("User timeline query #{user.nickname}") + + params = + %{limit: 20} + |> Map.put(:type, ["Create", "Announce"]) + |> Map.put(:user, reading_user) + |> Map.put(:actor_id, user.ap_id) + |> Map.put(:pinned_object_ids, Map.keys(user.pinned_objects)) + + list_memberships = Pleroma.List.memberships(user) + + recipients = + %{ + godmode: params[:godmode], + reading_user: reading_user + } + |> Pleroma.Web.ActivityPub.ActivityPub.user_activities_recipients() + + query = + (recipients ++ list_memberships) + |> Pleroma.Web.ActivityPub.ActivityPub.fetch_activities_query(params) + |> limit(20) + + Ecto.Adapters.SQL.explain(Repo, :all, query, analyze: true, timeout: :infinity) + |> IO.puts() + end +end diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 3f46a8ecb..d700128c0 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -739,9 +739,9 @@ defp fetch_activities_for_reading_user(reading_user, params) do |> fetch_activities(params, :offset) end - defp user_activities_recipients(%{godmode: true}), do: [] + def user_activities_recipients(%{godmode: true}), do: [] - defp user_activities_recipients(%{reading_user: reading_user}) do + def user_activities_recipients(%{reading_user: reading_user}) do if not is_nil(reading_user) and reading_user.local do [ Constants.as_public(), From 7c4b415929cfef17c409eab095b8e1eb956607cc Mon Sep 17 00:00:00 2001 From: sfr Date: Wed, 7 Dec 2022 11:20:53 +0000 Subject: [PATCH 094/631] static-fe overhaul (#236) makes static-fe look more like pleroma-fe, with the stylesheets matching pleroma-dark and pleroma-light based on `prefers-color-scheme`. - [x] navbar - [x] about sidebar - [x] background image - [x] statuses - [x] "reply to" or "edited" tags - [x] accounts - [x] show more / show less - [x] posts / with replies / media / followers / following - [x] followers/following would require user card snippets - [x] admin/bot indicators - [x] attachments - [x] nsfw attachments - [x] fontawesome icons - [x] clean up and sort css - [x] add pleroma-light - [x] replace hardcoded strings also i forgot - [x] repeated headers how it looks + sneak peek at statuses: ![](https://akkoma.dev/attachments/c0d3a025-6987-4630-8eb9-5f4db6858359) Co-authored-by: Sol Fisher Romanoff Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma/pulls/236 Co-authored-by: sfr Co-committed-by: sfr --- .gitattributes | 5 +- CHANGELOG.md | 1 + lib/pleroma/web/router.ex | 14 +- .../web/static_fe/static_fe_controller.ex | 74 +- lib/pleroma/web/static_fe/static_fe_view.ex | 26 +- .../web/templates/layout/static_fe.html.eex | 31 +- .../static_fe/static_fe/_attachment.html.eex | 23 +- .../static_fe/static_fe/_notice.html.eex | 144 +++- .../static_fe/static_fe/_user_card.html.eex | 28 +- .../static_fe/static_fe/conversation.html.eex | 17 +- .../static_fe/static_fe/error.html.eex | 15 +- .../static_fe/static_fe/profile.html.eex | 177 ++++- lib/pleroma/web/views/layout_view.ex | 7 + priv/static/static-fe/static-fe.css | 715 ++++++++++++++---- priv/static/static-fe/svg/globe-solid.svg | 1 + priv/static/static-fe/svg/lock-open-solid.svg | 1 + priv/static/static-fe/svg/lock-solid.svg | 1 + priv/static/static-fe/svg/reply-solid.svg | 1 + priv/static/static-fe/svg/retweet-solid.svg | 1 + priv/static/static-fe/svg/star-regular.svg | 1 + .../static_fe/static_fe_controller_test.exs | 83 +- 21 files changed, 1104 insertions(+), 262 deletions(-) create mode 100644 priv/static/static-fe/svg/globe-solid.svg create mode 100644 priv/static/static-fe/svg/lock-open-solid.svg create mode 100644 priv/static/static-fe/svg/lock-solid.svg create mode 100644 priv/static/static-fe/svg/reply-solid.svg create mode 100644 priv/static/static-fe/svg/retweet-solid.svg create mode 100644 priv/static/static-fe/svg/star-regular.svg diff --git a/.gitattributes b/.gitattributes index eb0c94757..7273afe43 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,10 +1,11 @@ *.ex diff=elixir *.exs diff=elixir -priv/static/instance/static.css diff=css - # Most of js/css files included in the repo are minified bundles, # and we don't want to search/diff those as text files. *.js binary *.js.map binary *.css binary + +priv/static/instance/static.css diff=css +priv/static/static-fe/static-fe.css diff=css diff --git a/CHANGELOG.md b/CHANGELOG.md index e0946b76d..07ed6653a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - NormalizeMarkup MRF is now on by default - Follow/Block/Mute imports now spin off into *n* tasks to avoid the oban timeout - Transient activities recieved from remote servers are no longer persisted in the database +- Overhauled static-fe view for logged-out users ## Upgrade Notes - If you have an old instance, you will probably want to run `mix pleroma.database prune_task` in the foreground to catch it up with the history of your instance. diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index a34dd26ce..22a35e8e2 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -728,6 +728,12 @@ defmodule Pleroma.Web.Router do get("/users/:nickname/feed", Feed.UserController, :feed, as: :user_feed) end + scope "/", Pleroma.Web.StaticFE do + # Profile pages for static-fe + get("/users/:nickname/with_replies", StaticFEController, :show) + get("/users/:nickname/media", StaticFEController, :show) + end + scope "/", Pleroma.Web do pipe_through(:accepts_html) get("/notice/:id/embed_player", OStatus.OStatusController, :notice_player) @@ -771,10 +777,16 @@ defmodule Pleroma.Web.Router do post("/users/:nickname/outbox", ActivityPubController, :update_outbox) post("/api/ap/upload_media", ActivityPubController, :upload_media) + get("/users/:nickname/collections/featured", ActivityPubController, :pinned) + end + + scope "/", Pleroma.Web.ActivityPub do + # Note: html format is supported only if static FE is enabled + pipe_through([:accepts_html_json, :static_fe, :activitypub_client]) + # The following two are S2S as well, see `ActivityPub.fetch_follow_information_for_user/1`: get("/users/:nickname/followers", ActivityPubController, :followers) get("/users/:nickname/following", ActivityPubController, :following) - get("/users/:nickname/collections/featured", ActivityPubController, :pinned) end scope "/", Pleroma.Web.ActivityPub do diff --git a/lib/pleroma/web/static_fe/static_fe_controller.ex b/lib/pleroma/web/static_fe/static_fe_controller.ex index 827c0a384..6f73b575e 100644 --- a/lib/pleroma/web/static_fe/static_fe_controller.ex +++ b/lib/pleroma/web/static_fe/static_fe_controller.ex @@ -45,7 +45,7 @@ def show(%{assigns: %{notice_id: notice_id}} = conn, _params) do end end - def show(%{assigns: %{username_or_id: username_or_id}} = conn, params) do + def show(%{assigns: %{username_or_id: username_or_id, tab: tab}} = conn, params) do with {_, %User{local: true} = user} <- {:fetch_user, User.get_cached_by_nickname_or_id(username_or_id)}, {_, :visible} <- {:visibility, User.visible_for(user, _reading_user = nil)} do @@ -55,11 +55,36 @@ def show(%{assigns: %{username_or_id: username_or_id}} = conn, params) do params |> Map.take(@page_keys) |> Map.new(fn {k, v} -> {String.to_existing_atom(k), v} end) + |> Map.put(:limit, 20) + + params = + case tab do + "posts" -> + Map.put(params, :exclude_replies, true) + + "media" -> + Map.put(params, :only_media, true) + + _ -> + params + end timeline = - user - |> ActivityPub.fetch_user_activities(_reading_user = nil, params) - |> Enum.map(&represent/1) + case tab do + tab when tab in ["posts", "with_replies", "media"] -> + user + |> ActivityPub.fetch_user_activities(_reading_user = nil, params) + |> Enum.map(&represent/1) + + "following" when not user.hide_follows -> + User.get_friends(user) + + "followers" when not user.hide_followers -> + User.get_followers(user) + + _ -> + [] + end prev_page_id = (params["min_id"] || params["max_id"]) && @@ -75,6 +100,11 @@ def show(%{assigns: %{username_or_id: username_or_id}} = conn, params) do meta: meta }) else + {_, %User{} = user} -> + conn + |> put_status(:found) + |> redirect(external: user.uri || user.ap_id) + _ -> not_found(conn, "User not found.") end @@ -150,6 +180,23 @@ defp represent(%Activity{object: %Object{data: data}} = activity, selected) do nil end + reply_to_user = + if data["inReplyTo"] do + activity + |> Activity.get_in_reply_to_activity() + |> Map.get(:actor) + |> User.get_cached_by_ap_id() + else + nil + end + + total_votes = + if data["oneOf"] do + Enum.sum(for option <- data["oneOf"], do: option["replies"]["totalItems"]) + else + 0 + end + %{ user: User.sanitize_html(user), title: get_title(activity.object), @@ -160,7 +207,13 @@ defp represent(%Activity{object: %Object{data: data}} = activity, selected) do sensitive: data["sensitive"], selected: selected, counts: get_counts(activity), - id: activity.id + id: activity.id, + visibility: Visibility.get_visibility(activity.object), + reply_to: data["inReplyTo"], + reply_to_user: reply_to_user, + edited_at: data["updated"], + poll: data["oneOf"], + total_votes: total_votes } end @@ -177,7 +230,16 @@ defp assign_id(%{path_info: [_nickname, "status", notice_id]} = conn, _opts), do: assign(conn, :notice_id, notice_id) defp assign_id(%{path_info: ["users", user_id]} = conn, _opts), - do: assign(conn, :username_or_id, user_id) + do: + conn + |> assign(:username_or_id, user_id) + |> assign(:tab, "posts") + + defp assign_id(%{path_info: ["users", user_id, tab]} = conn, _opts), + do: + conn + |> assign(:username_or_id, user_id) + |> assign(:tab, tab) defp assign_id(%{path_info: ["objects", object_id]} = conn, _opts), do: assign(conn, :object_id, object_id) diff --git a/lib/pleroma/web/static_fe/static_fe_view.ex b/lib/pleroma/web/static_fe/static_fe_view.ex index c04715337..f0c9ddd22 100644 --- a/lib/pleroma/web/static_fe/static_fe_view.ex +++ b/lib/pleroma/web/static_fe/static_fe_view.ex @@ -8,7 +8,6 @@ defmodule Pleroma.Web.StaticFE.StaticFEView do alias Calendar.Strftime alias Pleroma.Emoji.Formatter alias Pleroma.User - alias Pleroma.Web.Endpoint alias Pleroma.Web.Gettext alias Pleroma.Web.MediaProxy alias Pleroma.Web.Metadata.Utils @@ -22,17 +21,38 @@ def fetch_media_type(%{"mediaType" => mediaType}) do Utils.fetch_media_type(@media_types, mediaType) end + def time_ago(date) do + {:ok, date, _} = DateTime.from_iso8601(date) + now = DateTime.utc_now() + + Timex.from_now(date, now) + end + def format_date(date) do {:ok, date, _} = DateTime.from_iso8601(date) Strftime.strftime!(date, "%Y/%m/%d %l:%M:%S %p UTC") end - def instance_name, do: Pleroma.Config.get([:instance, :name], "Pleroma") + def instance_name, do: Pleroma.Config.get([:instance, :name], "Akkoma") def open_content? do Pleroma.Config.get( [:frontend_configurations, :collapse_message_with_subjects], - true + false ) end + + def get_attachment_name(%{"name" => name}), do: name + + def get_attachment_name(_), do: "" + + def poll_percentage(count, total_votes) do + case count do + 0 -> + "0%" + + _ -> + Integer.to_string(trunc(count / total_votes * 100)) <> "%" + end + end end diff --git a/lib/pleroma/web/templates/layout/static_fe.html.eex b/lib/pleroma/web/templates/layout/static_fe.html.eex index e6adb526b..3d55393f0 100644 --- a/lib/pleroma/web/templates/layout/static_fe.html.eex +++ b/lib/pleroma/web/templates/layout/static_fe.html.eex @@ -6,10 +6,39 @@ <%= Pleroma.Config.get([:instance, :name]) %> <%= Phoenix.HTML.raw(assigns[:meta] || "") %> + +
+
- <%= @inner_content %> +
+
+ <%= @inner_content %> +
+
+ + diff --git a/lib/pleroma/web/templates/static_fe/static_fe/_attachment.html.eex b/lib/pleroma/web/templates/static_fe/static_fe/_attachment.html.eex index 4853e7f4b..f5bbe9a07 100644 --- a/lib/pleroma/web/templates/static_fe/static_fe/_attachment.html.eex +++ b/lib/pleroma/web/templates/static_fe/static_fe/_attachment.html.eex @@ -1,8 +1,15 @@ -<%= case @mediaType do %> -<% "audio" -> %> - -<% "video" -> %> - -<% _ -> %> -<%= @name %> -<% end %> +" title="<%= @name %>"> + <%= if @nsfw do %> +
+
<%= gettext("Hover to show content") %>
+
+ <% end %> + <%= case @mediaType do %> + <% "audio" -> %> + + <% "video" -> %> + + <% _ -> %> + + <% end %> +
diff --git a/lib/pleroma/web/templates/static_fe/static_fe/_notice.html.eex b/lib/pleroma/web/templates/static_fe/static_fe/_notice.html.eex index df0244795..6585e81b6 100644 --- a/lib/pleroma/web/templates/static_fe/static_fe/_notice.html.eex +++ b/lib/pleroma/web/templates/static_fe/static_fe/_notice.html.eex @@ -1,41 +1,109 @@ -
id="selected" <% end %>> -

- - +

id="selected" <% end %>> +
+ +
+ <%= @user.nickname %> +
-

- <%= render("_user_card.html", %{user: @user}) %> -
- <%= if @title != "" do %> -
open<% end %>> - <%= raw @title %> -
<%= raw @content %>
-
- <% else %> -
<%= raw @content %>
- <% end %> - <%= for %{"name" => name, "url" => [url | _]} <- @attachment do %> - <%= if @sensitive do %> -
- <%= Gettext.gettext("sensitive media") %> -
- <%= render("_attachment.html", %{name: name, url: url["href"], - mediaType: fetch_media_type(url)}) %> -
-
- <% else %> - <%= render("_attachment.html", %{name: name, url: url["href"], - mediaType: fetch_media_type(url)}) %> - <% end %> - <% end %>
- <%= if @selected do %> -
-
<%= Gettext.gettext("replies") %>
<%= @counts.replies %>
-
<%= Gettext.gettext("announces") %>
<%= @counts.announces %>
-
<%= Gettext.gettext("likes") %>
<%= @counts.likes %>
-
- <% end %> +
+
+
+
+

+ <%= raw Formatter.emojify(@user.name, @user.emoji) %> +

+ +
+
+ + + + <%= if @visibility == "public" do %> + + <% else %> + <%= if @visibility == "unlisted" do %> + + <% end %> + <% end %> +
+
+ <%= if @reply_to do %> + + <% end %> + <%= if @edited_at do %> +
+ <%= gettext("Edited %{timeago}", timeago: time_ago(@edited_at)) %> +
+ <% end %> +
+
+ <%= if @title && @title != "" do %> + <%= raw @title %> +
open<% end %>> + <%= gettext("Show content") %> + <% end %> +
+ <%= raw @content %> + <%= if @poll && length(@poll) > 0 do %> +
+ <%= for %{"name" => option, "replies" => %{"totalItems" => count}} <- @poll do %> +
+ <%= poll_percentage(count, @total_votes) %> + <%= raw option %> +
+
+ <% end %> +
+ <% end %> + <%= if length(@attachment) > 0 do %> +
+ <%= for attachment = %{"url" => [url | _]} <- @attachment do %> + <%= render("_attachment.html", %{name: get_attachment_name(attachment), + url: url["href"], mediaType: fetch_media_type(url), nsfw: @sensitive}) %> + <% end %> +
+ <% end %> +
+ <%= if @title && @title != "" do %> +
+ <% end %> +
+ +
+
+ + <%= @counts.replies %> +
+
+ + <%= @counts.announces %> +
+
+ + <%= @counts.likes %> +
+
+
diff --git a/lib/pleroma/web/templates/static_fe/static_fe/_user_card.html.eex b/lib/pleroma/web/templates/static_fe/static_fe/_user_card.html.eex index 977b894d3..dc8717ea0 100644 --- a/lib/pleroma/web/templates/static_fe/static_fe/_user_card.html.eex +++ b/lib/pleroma/web/templates/static_fe/static_fe/_user_card.html.eex @@ -1,11 +1,21 @@ -
- -
- +
+ +
+
+ <%= raw Formatter.emojify(@user.name, @user.emoji) %>
- - <%= raw Formatter.emojify(@user.name, @user.emoji) %> - <%= @user.nickname %> - - + +
diff --git a/lib/pleroma/web/templates/static_fe/static_fe/conversation.html.eex b/lib/pleroma/web/templates/static_fe/static_fe/conversation.html.eex index 2acd84828..b825c85e7 100644 --- a/lib/pleroma/web/templates/static_fe/static_fe/conversation.html.eex +++ b/lib/pleroma/web/templates/static_fe/static_fe/conversation.html.eex @@ -1,11 +1,8 @@ -
-

<%= link instance_name(), to: "/" %>

-
- -
-
- <%= for activity <- @activities do %> - <%= render("_notice.html", activity) %> - <% end %> +
+
+ <%= gettext("Conversation") %>
-
+ <%= for activity <- @activities do %> + <%= render("_notice.html", activity) %> + <% end %> +
diff --git a/lib/pleroma/web/templates/static_fe/static_fe/error.html.eex b/lib/pleroma/web/templates/static_fe/static_fe/error.html.eex index d98a1eba7..a9dbbf427 100644 --- a/lib/pleroma/web/templates/static_fe/static_fe/error.html.eex +++ b/lib/pleroma/web/templates/static_fe/static_fe/error.html.eex @@ -1,7 +1,8 @@ -
-

<%= gettext("Oops") %>

-
- -
-

<%= @message %>

-
+
+
+ <%= gettext("Error") %> +
+
+ <%= @message %> +
+
diff --git a/lib/pleroma/web/templates/static_fe/static_fe/profile.html.eex b/lib/pleroma/web/templates/static_fe/static_fe/profile.html.eex index a14ca305e..3d1cf77e5 100644 --- a/lib/pleroma/web/templates/static_fe/static_fe/profile.html.eex +++ b/lib/pleroma/web/templates/static_fe/static_fe/profile.html.eex @@ -1,31 +1,148 @@ -
-

<%= link instance_name(), to: "/" %>

- -

-
- - - -
- <%= raw Formatter.emojify(@user.name, @user.emoji) %> | - <%= link "@#{@user.nickname}@#{Endpoint.host()}", to: (@user.uri || @user.ap_id) %> -

-

<%= raw @user.bio %>

-
- -
-
- <%= for activity <- @timeline do %> - <%= render("_notice.html", Map.put(activity, :selected, false)) %> - <% end %> -

- <%= if @prev_page_id do %> - <%= link "«", to: "?min_id=" <> @prev_page_id %> - <% end %> - <%= if @prev_page_id && @next_page_id, do: " | " %> - <%= if @next_page_id do %> - <%= link "»", to: "?max_id=" <> @next_page_id %> - <% end %> -

+
+
+
+ +
+
+
<%= gettext("Posts") %>
+ <%= @user.note_count %> +
+
+
<%= gettext("Following") %>
+ <%= if @user.hide_follows_count do gettext("Hidden") else @user.following_count end %> +
+
+
<%= gettext("Followers") %>
+ <%= if @user.hide_followers_count do gettext("Hidden") else @user.follower_count end %> +
+
+ <%= raw Formatter.emojify(@user.bio, @user.emoji) %>
-
+ + + <%= if @prev_page_id do %> + <%= link gettext("Show newer"), to: "?min_id=" <> @prev_page_id, class: "load-posts" %> + <% end %> +
+ <%= if @tab in ["posts", "with_replies", "media"] do %> + <%= for activity <- @timeline do %> + <%= if(activity.user.id != @user.id) do %> +
+ + +
+ <% end %> + <%= render("_notice.html", Map.put(activity, :selected, false)) %> + <% end %> + <% else %> + <%= for user <- @timeline do %> + <%= render("_user_card.html", %{user: user}) %> + <% end %> + <% end %> +
+ <%= if @next_page_id do %> + <%= link gettext("Show older"), to: "?max_id=" <> @next_page_id, class: "load-posts" %> + <% end %> +
+ + diff --git a/lib/pleroma/web/views/layout_view.ex b/lib/pleroma/web/views/layout_view.ex index c2da10f04..ac13cf962 100644 --- a/lib/pleroma/web/views/layout_view.ex +++ b/lib/pleroma/web/views/layout_view.ex @@ -4,4 +4,11 @@ defmodule Pleroma.Web.LayoutView do use Pleroma.Web, :view + import Phoenix.HTML + + def render_html(file) do + case :httpc.request(Pleroma.Web.Endpoint.url() <> file) do + {:ok, {{_, 200, _}, _headers, body}} -> body + end + end end diff --git a/priv/static/static-fe/static-fe.css b/priv/static/static-fe/static-fe.css index 89e9f4877..657556077 100644 --- a/priv/static/static-fe/static-fe.css +++ b/priv/static/static-fe/static-fe.css @@ -1,59 +1,278 @@ +/* pleroma-light and pleroma-dark themes from pleroma-fe */ +:root { + --icon-filter: invert(38%) sepia(11%) saturate(209%) hue-rotate(179deg) brightness(99%) contrast(89%); + --wallpaper: rgba(11, 16, 23, 1); + --alertNeutral: rgba(185, 185, 186, 0.5); + --alertNeutralText: rgba(255, 255, 255, 1); + --avatarShadow: 0px 1px 8px 0px rgba(0, 0, 0, 0.7); + --loadPostsSelected: rgba(23, 34, 46, 1); + --loadPostsSelectedText: rgba(185, 185, 186, 1); + --profileBg: rgba(7, 12, 17, 1); + --profileTint: rgba(15, 22, 30, 0.5); + --btnText: rgba(185, 185, 186, 1); + --btn: rgba(21, 30, 43, 1); + --btnShadow: 0px 0px 2px 0px rgba(0, 0, 0, 1) , 0px 1px 0px 0px rgba(255, 255, 255, 0.2) inset, 0px -1px 0px 0px rgba(0, 0, 0, 0.2) inset; + --btnHoverShadow: 0px 0px 1px 2px rgba(185, 185, 186, 0.4) inset, 0px 1px 0px 0px rgba(255, 255, 255, 0.2) inset, 0px -1px 0px 0px rgba(0, 0, 0, 0.2) inset; + --lightText: rgba(236, 236, 236, 1); + --panelShadow: 0px 0px 3px 0px rgba(0, 0, 0, 0.5) , 0px 4px 6px 3px rgba(0, 0, 0, 0.3); + --panelHeaderShadow: 0px 1px 3px 0px rgba(0, 0, 0, 0.4) , 0px 1px 0px 0px rgba(255, 255, 255, 0.2) inset; + --topBar: rgba(21, 30, 43, 1); + --topBarText: rgba(159, 159, 161, 1); + --topBarShadow: 0px 1px 4px 0px rgba(0, 0, 0, 0.4) , 0px 2px 7px 0px rgba(0, 0, 0, 0.3); + --underlay: rgba(9, 14, 20, 0.6); + --background: rgba(15, 22, 30, 1); + --faint: rgba(185, 185, 186, 0.5); + --selectedPost: rgba(23, 34, 46, 1); + --link: rgba(226, 177, 136, 1); + --text: rgba(185, 185, 186, 1); + --border: rgba(26, 37, 53, 1); + --poll: rgba(99, 84, 72, 1); +} +@media (prefers-color-scheme: light) { + :root { + --icon-filter: invert(67%) sepia(7%) saturate(525%) hue-rotate(173deg) brightness(90%) contrast(92%);; + --wallpaper: rgba(248, 250, 252, 1); + --alertNeutral: rgba(48, 64, 85, 0.5); + --alertNeutralText: rgba(0, 0, 0, 1); + --avatarShadow: 0px 1px 8px 0px rgba(0, 0, 0, 0.7); + --loadPostsSelected: rgba(224, 233, 240, 1); + --loadPostsSelectedText: rgba(48, 64, 85, 1); + --profileBg: rgba(128, 137, 146, 1); + --profileTint: rgba(242, 246, 249, 0.5); + --btnText: rgba(48, 64, 85, 1); + --btn: rgba(214, 223, 237, 1); + --btnShadow: 0px 0px 2px 0px rgba(0, 0, 0, 0.2) , 0px 1px 0px 0px rgba(255, 255, 255, 0.5) inset, 0px -1px 0px 0px rgba(0, 0, 0, 0.2) inset; + --btnHoverShadow: 0px 0px 2px 0px rgba(0, 0, 0, 0.2) , 0px 0px 1px 2px rgba(255, 195, 159, 1) inset, 0px -1px 0px 0px rgba(0, 0, 0, 0.2) inset; + --lightText: rgba(11, 14, 19, 1); + --panelShadow: 0px 1px 3px 0px rgba(0, 0, 0, 0.5) , 0px 3px 6px 1px rgba(0, 0, 0, 0.2); + --panelHeaderShadow: 0px 1px 0px 0px rgba(255, 255, 255, 0.5) inset, 0px 1px 3px 0px rgba(0, 0, 0, 0.3); + --topBar: rgba(214, 223, 237, 1); + --topBarText: rgba(48, 64, 85, 1); + --topBarShadow: 0px 0px 4px 0px rgba(0, 0, 0, 0.6); + --underlay: rgba(93, 96, 134, 0.4); + --background: rgba(242, 246, 249, 1); + --faint: rgba(48, 64, 85, 0.5); + --selectedPost: rgba(224, 233, 240, 1); + --link: rgba(245, 91, 27, 1); + --text: rgba(48, 64, 85, 1); + --border: rgba(216, 230, 249, 1); + --poll: rgba(243, 184, 160, 1); + } +} + +html { + height: 100%; + overflow-y: auto; +} + body { - background-color: #282c37; + overflow: auto; + margin: 0; + height: 100%; font-family: sans-serif; - color: white; + color: var(--text); } -main { - margin: 50px auto; - max-width: 960px; - padding: 40px; - background-color: #313543; - border-radius: 4px; -} - -header { - margin: 50px auto; - max-width: 960px; - padding: 40px; - background-color: #313543; - border-radius: 4px; -} - -.activity { - border-radius: 4px; - padding: 1em; - padding-bottom: 2em; - margin-bottom: 1em; -} - -.avatar { - cursor: pointer; -} - -.avatar img { - float: left; - border-radius: 4px; - margin-right: 4px; -} - -.activity-content img, video, audio { - padding: 1em; - max-width: 800px; - max-height: 800px; -} - -#selected { - background-color: #1b2735; -} - -.counts dt, .counts dd { - float: left; - margin-left: 1em; +.background-image { + position: fixed; + height: 100%; + top: 3.5em; + z-index: -1000; + left: 0; + right: -20px; + background-size: cover; + background-repeat: no-repeat; + background-color: var(--wallpaper); + background-image: var(--background-image); + background-position: 50%; } a { - color: white; + text-decoration: none; + color: var(--link); +} + +nav { + position: sticky; + top: 0; + width: 100%; + height: 3.5em; + background-color: var(--topBar); + box-shadow: var(--topBarShadow); + z-index: 2000; +} + +.inner-nav { + padding: 0 1.2em; + margin: auto; + max-width: 1110px; +} + +.inner-nav a { + line-height: 3.5em; + color: var(--topBarText); +} + +.inner-nav img { + height: 28px; + vertical-align: middle; + padding-right: 5px +} + +body > .container { + display: grid; + grid-template-columns: minmax(25em, 45em) 25em; + grid-template-areas: "content sidebar"; + height: calc(100vh - 3.5em); + justify-content: center; +} + +.underlay { + grid-column-start: 1; + grid-column-end: span 2; + grid-row-start: 1; + grid-row-end: 1; + background-color: var(--underlay); + z-index: -1000; +} + +.column { + padding: 1em; + margin: -0.5em; +} + +.panel { + background-color: var(--background); + border-radius: 3px; + box-shadow: var(--panelShadow); +} + +.panel-heading { + background-color: var(--topBar); + font-size: 1.3em; + padding: 0.6em; + border-radius: 3px 3px 0 0; + box-shadow: var(--panelHeaderShadow); +} + +.about-content { + padding: 0.6em; +} + +.main { + grid-area: content; + position: relative; +} + +.sidebar { + grid-area: sidebar; + padding-left: 0.5em; +} + +.status-container, +.repeat-header, +.user-card { + display: flex; + padding: 0.75em; +} + +.left-side { + margin-right: 0.75em; +} + +.right-side { + flex: 1; + min-width: 0; +} + +.repeat-header { + padding: 0.4em 0.75em; + margin-bottom: -0.75em; +} + +.repeat-header .right-side { + color: var(--faint); +} +.repeat-header .u-photo { + height: 20px; + width: 20px; + margin-left: 28px; +} + +.status-heading { + margin-bottom: 0.5em; + line-height: 1.3; +} + +.status-heading a { + display: inline-block; + word-break: break-all; +} + +.heading-left { + display: flex; + flex: 1; + overflow: hidden; +} + +.heading-right { + display: flex; + align-items: center; +} + +.heading-name-row .account-name { + min-width: 1.6em; + margin-right: 0.4em; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + flex: 1 1 0; +} + +.heading-name-row .username, +.repeat-header .username { + white-space: nowrap; + overflow: hidden; + max-width: 85%; + font-weight: bold; + flex-shrink: 1; + margin: 0; + margin-right: 0.4em; + text-overflow: ellipsis; +} + +.heading-name-row { + display: flex; + justify-content: space-between; +} + +.heading-edited-row, +.heading-reply-row { + font-size: 0.85em; + margin-top: 0.2em; +} + +.reply-to-link { + color: var(--faint); +} +.reply-to-link:hover { + text-decoration: underline; +} + +#selected { + background-color: var(--selectedPost); +} + +.timeago { + color: var(--faint); +} + +#selected .timeago { + color: var(--text); +} + +.timeago :hover { + text-decoration: underline; } .h-card { @@ -69,116 +288,340 @@ header a:hover, .h-card a:hover { text-decoration: underline; } -.display-name { - padding-top: 4px; +.attachments { + margin-top: 0.5em; + flex-direction: row; + display: flex; + flex-wrap: nowrap; + align-content: stretch; + max-height: 24em; +} + +.attachment { + border: 1px solid var(--border); + border-radius: 3px; + display: flex; + flex-grow: 1; + justify-content: center; + position: relative; + min-width: 0; +} + +.attachment > * { + width: 100%; + object-fit: contain; +} + +.attachment:not(:last-child) { + margin-right: 0.5em; +} + +.nsfw-banner { + position: absolute; + height: 100%; + display: flex; + align-items: center; +} +.nsfw-banner div { + width: 100%; + text-align: center; +} + +.nsfw-banner:not(:hover) { + background-color: var(--background); +} +.nsfw-banner:hover div { + display: none; +} + +.poll-option { + position: relative; + display: flex; + margin: 0.75em 0.5em; + padding: 0.1em 0.25em; + word-break: break-word; + z-index: 1; +} +.poll-option .percentage { + width: 3.5em; + flex-shrink: 0; +} +.poll-option .fill { + height: 100%; + position: absolute; + background-color: var(--poll); + border-radius: 3px; + top: 0; + left: 0; + z-index: -1; +} + +.status-actions { + position: relative; + width: 100%; + display: flex; + margin-top: 0.75em; +} +.status-actions > * { + max-width: 4em; + flex: 1; + display: flex; +} + +.status-summary { display: block; + font-style: italic; + padding-bottom: 0.5em; + margin-bottom: 0.5em; + border-style: solid; + border-width: 0 0 1px 0; + border-color: var(--border, #222); +} + +summary { + text-align: center; + color: var(--link); + cursor: pointer; +} + +.status-body { + word-wrap: break-word; + word-break: break-word; + line-height: 1.4; +} + +.user-info { + padding: 0.5em 26px; +} + +.user-info .container { + padding: 18px 0 6px 0; + display: flex; + align-items: flex-start; + max-height: 56px; +} + +.user-info a { + color: var(--lightText); +} + +.user-info .avatar img { + height: 56px; + width: 56px; +} + +.avatar img { + border-radius: 3px; + box-shadow: var(--avatarShadow); +} + +.user-summary { + display: block; + margin-left: 0.6em; + text-align: left; text-overflow: ellipsis; - overflow: hidden; - color: white; + white-space: nowrap; + flex: 1 1 0; + z-index: 1; + line-height: 2em; + color: var(--lightText); } -/* keep emoji from being hilariously huge */ -.display-name img { - max-height: 1em; - max-width: 1em; +.button-default { + user-select: none; + color: var(--btnText); + background-color: var(--btn); + border: none; + border-radius: 4px; + box-shadow: var(--btnShadow); + font-size: 1em; + min-height: 2em; } -.display-name .nickname { - padding-top: 4px; +.button-default:hover { + box-shadow: var(--btnHoverShadow); + cursor: pointer; +} + +.user-bio { + text-align: center; display: block; -} - -.nickname:hover { - text-decoration: none; -} - -.pull-right { - float: right; -} - -.collapse { - margin: 0; - width: auto; -} - -h1 { + line-height: 1.3; + padding: 1em; margin: 0; } -h2 { - color: #9baec8; - font-weight: normal; - font-size: 20px; - margin-bottom: 40px; +.user-banner { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-image: linear-gradient(to bottom, var(--profileTint), var(--profileTint)), + var(--user-banner); + background-size: cover; + background-color: var(--profileBg); + -webkit-mask: linear-gradient(to top, white, transparent) bottom no-repeat, + linear-gradient(to top, white, white); + -webkit-mask-composite: xor; + -webkit-mask-size: 100% 60%; + z-index: -2; } -form { - width: 100%; +.user-header { + position: relative; + z-index: 1; } -input { +.user-role { + color: var(--alertNeutralText); + background-color: var(--alertNeutral); + margin: 0 0.35em; + padding: 0 0.25em; + border-radius: 2px; +} + +.user-profile-fields { + margin: 0 0.5em; +} + +.user-profile-field { + display: flex; + margin: 0.25em; + border: 1px solid var(--border, #222); + border-radius: 3px; + line-height: 1.3; + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; +} + +.user-profile-field dt { + padding: 0.5em 1.5em; box-sizing: border-box; - width: 100%; - padding: 10px; - margin-top: 20px; - background-color: rgba(0,0,0,.1); - color: white; - border: 0; - border-bottom: 2px solid #9baec8; - font-size: 14px; -} - -input:focus { - border-bottom: 2px solid #4b8ed8; -} - -input[type="checkbox"] { - width: auto; -} - -button { - box-sizing: border-box; - width: 100%; - color: white; - background-color: #419bdd; - border-radius: 4px; - border: none; - padding: 10px; - margin-top: 30px; - text-transform: uppercase; + flex: 0 1 30%; font-weight: 500; - font-size: 16px; + color: var(--lightText); + border-right: 1px solid var(--border); + text-align: right; } -.alert-danger { +.user-profile-field dd { + padding: 0.5em 1.5em; box-sizing: border-box; - width: 100%; - color: #D8000C; - background-color: #FFD2D2; - border-radius: 4px; - border: none; - padding: 10px; - margin-top: 20px; - font-weight: 500; - font-size: 16px; + flex: 1 1 30%; + margin: 0 0 0 0.25em; } -.alert-info { +.user-counts { + display: flex; + line-height: 1em; + padding: 0.5em 1.5em 0 1.5em; + text-align: center; + justify-content: space-between; + color: var(--lightText); + flex-wrap: wrap; +} + +.user-count { + flex: 1 0 auto; + padding: 0.5em 0; + margin: 0 0.5em; +} + +.user-count h5 { + font-size: 1em; + font-weight: bolder; + margin: 0 0 0.25em; +} + +.tab-switcher { + display: flex; + padding-top: 5px; + overflow-x: auto; + overflow-y: hidden; + border-bottom: 1px solid var(--border); +} + +.tab-switcher::before, +.tab-switcher::after { + flex: 1 1 auto; + content: ''; +} + +.tab { + flex: 0 0 auto; + padding: 6px 1em; + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; +} + +.tab.active { + background: transparent; +} + +.profile .status-container { + border-bottom: 1px solid var(--border); +} + +.bottom-line { + display: flex; +} + +.load-posts { + display: block; box-sizing: border-box; + height: 3.5em; + line-height: 3.5em; + padding: 0 1em; width: 100%; - color: #00529B; - background-color: #BDE5F8; - border-radius: 4px; - border: none; - padding: 10px; - margin-top: 20px; - font-weight: 500; - font-size: 16px; + text-align: center; } -img.emoji { - width: 32px; - height: 32px; - padding: 0; - vertical-align: middle; +.load-posts:hover { + background-color: var(--loadPostsSelected); + color: var(--loadPostsSelectedText); +} + + +.fa-icon { + height: 0.875em; + margin: 0 0.3em; + filter: var(--icon-filter); + align-self: center; +} + +.status-actions .fa-icon { + height: 1.1em; +} + +.reply-to-link .fa-icon { + transform: scale(-1, 1); +} + +@media (max-width: 800px) { + body > .container { + display: block; + } + + .column { + padding: 0; + margin: 0; + } + + .sidebar { + display: none; + } +} + +img:not(.u-photo, .fa-icon) { + width: 32px; + height: 32px; + padding: 0; + vertical-align: middle; +} + +.username img:not(.u-photo) { + width: 16px; + height: 16px; } diff --git a/priv/static/static-fe/svg/globe-solid.svg b/priv/static/static-fe/svg/globe-solid.svg new file mode 100644 index 000000000..06aa71e62 --- /dev/null +++ b/priv/static/static-fe/svg/globe-solid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/priv/static/static-fe/svg/lock-open-solid.svg b/priv/static/static-fe/svg/lock-open-solid.svg new file mode 100644 index 000000000..a122cc414 --- /dev/null +++ b/priv/static/static-fe/svg/lock-open-solid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/priv/static/static-fe/svg/lock-solid.svg b/priv/static/static-fe/svg/lock-solid.svg new file mode 100644 index 000000000..3fdea7a51 --- /dev/null +++ b/priv/static/static-fe/svg/lock-solid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/priv/static/static-fe/svg/reply-solid.svg b/priv/static/static-fe/svg/reply-solid.svg new file mode 100644 index 000000000..a798b7666 --- /dev/null +++ b/priv/static/static-fe/svg/reply-solid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/priv/static/static-fe/svg/retweet-solid.svg b/priv/static/static-fe/svg/retweet-solid.svg new file mode 100644 index 000000000..260976770 --- /dev/null +++ b/priv/static/static-fe/svg/retweet-solid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/priv/static/static-fe/svg/star-regular.svg b/priv/static/static-fe/svg/star-regular.svg new file mode 100644 index 000000000..71d15e95d --- /dev/null +++ b/priv/static/static-fe/svg/star-regular.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/test/pleroma/web/static_fe/static_fe_controller_test.exs b/test/pleroma/web/static_fe/static_fe_controller_test.exs index 5752cffda..25ed6e193 100644 --- a/test/pleroma/web/static_fe/static_fe_controller_test.exs +++ b/test/pleroma/web/static_fe/static_fe_controller_test.exs @@ -6,6 +6,8 @@ defmodule Pleroma.Web.StaticFE.StaticFEControllerTest do use Pleroma.Web.ConnCase alias Pleroma.Activity + alias Pleroma.User + alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.ActivityPub.Transmogrifier alias Pleroma.Web.ActivityPub.Utils alias Pleroma.Web.CommonAPI @@ -42,8 +44,67 @@ test "profile does not include private messages", %{conn: conn, user: user} do html = html_response(conn, 200) - assert html =~ ">public<" - refute html =~ ">private<" + assert html =~ "\npublic\n" + refute html =~ "\nprivate\n" + end + + test "main page does not include replies", %{conn: conn, user: user} do + {:ok, op} = CommonAPI.post(user, %{status: "beep"}) + CommonAPI.post(user, %{status: "boop", in_reply_to_id: op}) + + conn = get(conn, "/users/#{user.nickname}") + + html = html_response(conn, 200) + + assert html =~ "\nbeep\n" + refute html =~ "\nboop\n" + end + + test "media page only includes posts with attachments", %{conn: conn, user: user} do + file = %Plug.Upload{ + content_type: "image/jpeg", + path: Path.absname("test/fixtures/image.jpg"), + filename: "an_image.jpg" + } + + {:ok, %{id: media_id}} = ActivityPub.upload(file, actor: user.ap_id) + + CommonAPI.post(user, %{status: "virgin text post"}) + CommonAPI.post(user, %{status: "chad post with attachment", media_ids: [media_id]}) + + conn = get(conn, "/users/#{user.nickname}/media") + + html = html_response(conn, 200) + + assert html =~ "\nchad post with attachment\n" + refute html =~ "\nvirgin text post\n" + end + + test "show follower list", %{conn: conn, user: user} do + follower = insert(:user) + CommonAPI.follow(follower, user) + + conn = get(conn, "/users/#{user.nickname}/followers") + + html = html_response(conn, 200) + + assert html =~ "user-card" + end + + test "don't show followers if hidden", %{conn: conn, user: user} do + follower = insert(:user) + CommonAPI.follow(follower, user) + + {:ok, user} = + user + |> User.update_changeset(%{hide_followers: true}) + |> User.update_and_set_cache() + + conn = get(conn, "/users/#{user.nickname}/followers") + + html = html_response(conn, 200) + + refute html =~ "user-card" end test "pagination", %{conn: conn, user: user} do @@ -53,10 +114,10 @@ test "pagination", %{conn: conn, user: user} do html = html_response(conn, 200) - assert html =~ ">test30<" - assert html =~ ">test11<" - refute html =~ ">test10<" - refute html =~ ">test1<" + assert html =~ "\ntest30\n" + assert html =~ "\ntest11\n" + refute html =~ "\ntest10\n" + refute html =~ "\ntest1\n" end test "pagination, page 2", %{conn: conn, user: user} do @@ -67,10 +128,10 @@ test "pagination, page 2", %{conn: conn, user: user} do html = html_response(conn, 200) - assert html =~ ">test1<" - assert html =~ ">test10<" - refute html =~ ">test20<" - refute html =~ ">test29<" + assert html =~ "\ntest1\n" + assert html =~ "\ntest10\n" + refute html =~ "\ntest20\n" + refute html =~ "\ntest29\n" end test "does not require authentication on non-federating instances", %{ @@ -104,7 +165,7 @@ test "single notice page", %{conn: conn, user: user} do conn = get(conn, "/notice/#{activity.id}") html = html_response(conn, 200) - assert html =~ "
" + assert html =~ "
" assert html =~ user.nickname assert html =~ "testing a thing!" end From c7369d6d0345259e65d843c1533b8c82864e1110 Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Wed, 7 Dec 2022 11:41:24 +0000 Subject: [PATCH 095/631] GOOGLE --- lib/pleroma/web/views/manifest_view.ex | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/pleroma/web/views/manifest_view.ex b/lib/pleroma/web/views/manifest_view.ex index 5177b0eba..c85d76d42 100644 --- a/lib/pleroma/web/views/manifest_view.ex +++ b/lib/pleroma/web/views/manifest_view.ex @@ -21,6 +21,11 @@ def render("manifest.json", _params) do sizes: "512x512", type: "image/png", purpose: "maskable" + }, + %{ + src: "/static/logo-512.png", + sizes: "512x512", + type: "image/png" } ], theme_color: Config.get([:manifest, :theme_color]), From 221a95b860a6e0f06159ab14cb4dea5248a3913a Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Wed, 7 Dec 2022 11:45:53 +0000 Subject: [PATCH 096/631] Document custom.css --- docs/docs/configuration/static_dir.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/docs/configuration/static_dir.md b/docs/docs/configuration/static_dir.md index 0653dc2a3..30d7ced40 100644 --- a/docs/docs/configuration/static_dir.md +++ b/docs/docs/configuration/static_dir.md @@ -100,3 +100,12 @@ the `frontends` directory. ## Styling rendered pages To overwrite the CSS stylesheet of the OAuth form and other static pages, you can upload your own CSS file to `instance/static/static.css`. This will completely replace the CSS used by those pages, so it might be a good idea to copy the one from `priv/static/instance/static.css` and make your changes. + +## Overriding pleroma-fe styles + +To overwrite the CSS stylesheet of pleroma-fe, you can put a file at +`$static_dir/static/custom.css` containing your styles. These will be loaded +with the rest of the CSS. + +You will probably have to put `!important` on most/all your styles to override the +default ones, due to the specificity precedence of CSS. \ No newline at end of file From 1afba644641da3befb7cdb0e14484cf5ad19fc8c Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Wed, 7 Dec 2022 13:35:00 +0000 Subject: [PATCH 097/631] Redirect to standard FE if logged in --- lib/pleroma/web/plugs/static_fe_plug.ex | 5 +++- lib/pleroma/web/router.ex | 2 ++ .../web/static_fe/static_fe_controller.ex | 24 ++++++++++++------- 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/lib/pleroma/web/plugs/static_fe_plug.ex b/lib/pleroma/web/plugs/static_fe_plug.ex index 9ba9dc5ff..049a4ffbe 100644 --- a/lib/pleroma/web/plugs/static_fe_plug.ex +++ b/lib/pleroma/web/plugs/static_fe_plug.ex @@ -9,7 +9,7 @@ defmodule Pleroma.Web.Plugs.StaticFEPlug do def init(options), do: options def call(conn, _) do - if enabled?() and requires_html?(conn) do + if enabled?() and requires_html?(conn) and not_logged_in?(conn) do conn |> StaticFEController.call(:show) |> halt() @@ -23,4 +23,7 @@ defp enabled?, do: Pleroma.Config.get([:static_fe, :enabled], false) defp requires_html?(conn) do Phoenix.Controller.get_format(conn) == "html" end + + defp not_logged_in?(%{assigns: %{user: %Pleroma.User{}}}), do: false + defp not_logged_in?(_), do: true end diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 22a35e8e2..f2ea679a0 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -150,6 +150,8 @@ defmodule Pleroma.Web.Router do end pipeline :static_fe do + plug(:fetch_session) + plug(:authenticate) plug(Pleroma.Web.Plugs.StaticFEPlug) end diff --git a/lib/pleroma/web/static_fe/static_fe_controller.ex b/lib/pleroma/web/static_fe/static_fe_controller.ex index 6f73b575e..0a4327a56 100644 --- a/lib/pleroma/web/static_fe/static_fe_controller.ex +++ b/lib/pleroma/web/static_fe/static_fe_controller.ex @@ -180,15 +180,7 @@ defp represent(%Activity{object: %Object{data: data}} = activity, selected) do nil end - reply_to_user = - if data["inReplyTo"] do - activity - |> Activity.get_in_reply_to_activity() - |> Map.get(:actor) - |> User.get_cached_by_ap_id() - else - nil - end + reply_to_user = in_reply_to_user(activity) total_votes = if data["oneOf"] do @@ -217,6 +209,20 @@ defp represent(%Activity{object: %Object{data: data}} = activity, selected) do } end + defp in_reply_to_user(%Activity{object: %Object{data: %{"inReplyTo" => inReplyTo}}} = activity) when is_binary(inReplyTo) do + in_reply_to_activity = Activity.get_in_reply_to_activity(activity) + + if in_reply_to_activity do + in_reply_to_activity + |> Map.get(:actor) + |> User.get_cached_by_ap_id() + else + nil + end + end + + defp in_reply_to_user(_), do: nil + defp assign_id(%{path_info: ["notice", notice_id]} = conn, _opts), do: assign(conn, :notice_id, notice_id) From cb3ccf5f47b2e7a30cf89aae9d0c7b5a7be5307d Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Wed, 7 Dec 2022 13:41:12 +0000 Subject: [PATCH 098/631] Add check for null reply_to_user --- .../web/templates/static_fe/static_fe/_notice.html.eex | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/pleroma/web/templates/static_fe/static_fe/_notice.html.eex b/lib/pleroma/web/templates/static_fe/static_fe/_notice.html.eex index 6585e81b6..793f4ad51 100644 --- a/lib/pleroma/web/templates/static_fe/static_fe/_notice.html.eex +++ b/lib/pleroma/web/templates/static_fe/static_fe/_notice.html.eex @@ -46,9 +46,11 @@ <%= gettext("Reply to") %> - - @<%= @reply_to_user.nickname %> - + <%= if @reply_to_user do %> + + @<%= @reply_to_user.nickname %> + + <% end %>
<% end %> From 4e4bd248137b3efb6f2d0c444fecbd56b1770dbc Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Wed, 7 Dec 2022 15:39:19 +0000 Subject: [PATCH 099/631] Add misskey markdown to format suggestions Fixes #345 --- config/description.exs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/config/description.exs b/config/description.exs index 001a21cba..a73d2a06b 100644 --- a/config/description.exs +++ b/config/description.exs @@ -723,7 +723,8 @@ "text/plain", "text/html", "text/markdown", - "text/bbcode" + "text/bbcode", + "text/x.misskeymarkdown" ] }, %{ @@ -1294,7 +1295,7 @@ label: "Post Content Type", type: {:dropdown, :atom}, description: "Default post formatting option", - suggestions: ["text/plain", "text/html", "text/markdown", "text/bbcode"] + suggestions: ["text/plain", "text/html", "text/markdown", "text/bbcode", "text/x.misskeymarkdown"] }, %{ key: :redirectRootNoLogin, From 3f1c84d3001c0b9f2fa6044d865ccc2c75e27645 Mon Sep 17 00:00:00 2001 From: floatingghost Date: Wed, 7 Dec 2022 22:27:00 +0000 Subject: [PATCH 100/631] Add issue template --- ISSUE_TEMPLATE.md | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 ISSUE_TEMPLATE.md diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md new file mode 100644 index 000000000..6b9a5f3d8 --- /dev/null +++ b/ISSUE_TEMPLATE.md @@ -0,0 +1,27 @@ +--- + +name: "Issue" +about: "Something isn't working as expected" + +--- + +## Your setup + +[] OTP +[x] From Source + [] Distro: +[] Docker (what setup?) + +Postgres version: + +## What were you trying to do? + +## What did you expect to happen? + +## What actually happened? + +## Relative severity (does this prevent you from using the software as normal?) + +[] High - I cannot use the software +[] Medium - I cannot use it as easily as I'd like +[] Low - I can get by \ No newline at end of file From 104d8dcc1f0fe4f8e346cb27c6f2c0c276e5a3bd Mon Sep 17 00:00:00 2001 From: floatingghost Date: Wed, 7 Dec 2022 22:37:23 +0000 Subject: [PATCH 101/631] Update 'ISSUE_TEMPLATE.md' --- ISSUE_TEMPLATE.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md index 6b9a5f3d8..9e81c3ef4 100644 --- a/ISSUE_TEMPLATE.md +++ b/ISSUE_TEMPLATE.md @@ -8,7 +8,7 @@ about: "Something isn't working as expected" ## Your setup [] OTP -[x] From Source +[] From Source [] Distro: [] Docker (what setup?) @@ -22,6 +22,6 @@ Postgres version: ## Relative severity (does this prevent you from using the software as normal?) -[] High - I cannot use the software -[] Medium - I cannot use it as easily as I'd like -[] Low - I can get by \ No newline at end of file +[] I cannot use the software +[] I cannot use it as easily as I'd like +[] I can manage \ No newline at end of file From 067bd17e1e7cfcb55b3c29801facd012dca66b12 Mon Sep 17 00:00:00 2001 From: Sol Fisher Romanoff Date: Thu, 8 Dec 2022 18:07:24 +0200 Subject: [PATCH 102/631] Add YAML issue templates for bug and feat --- .gitea/issue_template/bug.yml | 85 ++++++++++++++++++++++++++++++++++ .gitea/issue_template/feat.yml | 29 ++++++++++++ ISSUE_TEMPLATE.md | 27 ----------- 3 files changed, 114 insertions(+), 27 deletions(-) create mode 100644 .gitea/issue_template/bug.yml create mode 100644 .gitea/issue_template/feat.yml delete mode 100644 ISSUE_TEMPLATE.md diff --git a/.gitea/issue_template/bug.yml b/.gitea/issue_template/bug.yml new file mode 100644 index 000000000..6ed1fa1ae --- /dev/null +++ b/.gitea/issue_template/bug.yml @@ -0,0 +1,85 @@ +name: "Bug report" +about: "Something isn't working as expected" +title: "[bug] " +body: + - type: markdown + attributes: + value: | + Thanks for taking the time to file this bug report! Please try to be as specific and detailed as you can, so we can track down the issue and fix it as soon as possible. + + # General information + - type: dropdown + id: installation + attributes: + label: "Your setup" + description: "What sort of installation are you using?" + options: + - "OTP" + - "From source" + - "Docker" + validations: + required: true + - type: input + id: setup-details + attributes: + label: "Extra details" + description: "If installing from source or docker, please specify your distro or docker setup." + placeholder: "e.g. Alpine Linux edge" + - type: input + id: version + attributes: + label: "Version" + description: "Which version of Akkoma are you running? If running develop, specify the commit hash." + placeholder: "e.g. 2022.11, 4e4bd248" + - type: input + id: postgres + attributes: + label: "PostgreSQL version" + placeholder: "14" + validations: + required: true + - type: markdown + attributes: + value: "# The issue" + - type: textarea + id: attempt + attributes: + label: "What were you trying to do?" + validations: + required: true + - type: textarea + id: expectation + attributes: + label: "What did you expect to happen?" + validations: + required: true + - type: textarea + id: reality + attributes: + label: "What actually happened?" + validations: + required: true + - type: textarea + id: logs + attributes: + label: "Logs" + description: "Please copy and paste any relevant log output, if applicable." + render: shell + - type: dropdown + id: severity + attributes: + label: "Severity" + description: "Does this issue prevent you from using the software as normal?" + options: + - "I cannot use the software" + - "I cannot use it as easily as I'd like" + - "I can manage" + validations: + required: true + - type: checkboxes + id: searched + attributes: + label: "Have you searched for this issue?" + description: "Please double-check that your issue is not already being tracked on [the forums](https://meta.akkoma.dev) or [the issue tracker](https://akkoma.dev/AkkomaGang/akkoma/issues)." + options: + - label: "I have double-checked and have not found this issue mentioned anywhere." diff --git a/.gitea/issue_template/feat.yml b/.gitea/issue_template/feat.yml new file mode 100644 index 000000000..fc1adbbc2 --- /dev/null +++ b/.gitea/issue_template/feat.yml @@ -0,0 +1,29 @@ +name: "Feature request" +about: "I'd like something to be added to Akkoma" +title: "[feat] " +body: + - type: markdown + attributes: + value: "Thanks for taking the time to request a new feature! Please be as concise and clear as you can in your proposal, so we could understand what you're going for." + - type: textarea + id: idea + attributes: + label: "The idea" + description: "What do you think you should be able to do in Akkoma?" + validations: + required: true + - type: textarea + id: reason + attributes: + label: "The reasoning" + description: "Why would this be a worthwhile feature? Does it solve any problems? Have people talked about wanting it?" + validations: + required: true + - type: checkboxes + id: searched + attributes: + label: "Have you searched for this feature request?" + description: "Please double-check that your issue is not already being tracked on [the forums](https://meta.akkoma.dev), [the issue tracker](https://akkoma.dev/AkkomaGang/akkoma/issues), or the one for [pleroma-fe](https://akkoma.dev/AkkomaGang/pleroma-fe/issues)." + options: + - label: "I have double-checked and have not found this feature request mentioned anywhere." + - label: "This feature is related to the Akkoma backend specifically, and not pleroma-fe." diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md deleted file mode 100644 index 9e81c3ef4..000000000 --- a/ISSUE_TEMPLATE.md +++ /dev/null @@ -1,27 +0,0 @@ ---- - -name: "Issue" -about: "Something isn't working as expected" - ---- - -## Your setup - -[] OTP -[] From Source - [] Distro: -[] Docker (what setup?) - -Postgres version: - -## What were you trying to do? - -## What did you expect to happen? - -## What actually happened? - -## Relative severity (does this prevent you from using the software as normal?) - -[] I cannot use the software -[] I cannot use it as easily as I'd like -[] I can manage \ No newline at end of file From ce517ff4e5a9cc144853ec8112bfac2a38a3a68a Mon Sep 17 00:00:00 2001 From: ilja Date: Thu, 8 Dec 2022 21:53:42 +0100 Subject: [PATCH 103/631] Fix tagpolicy to also work with Update Objects who got updated would just pass the TagPolicy, undoing the moderation that was set in place for the Actor. Now we check not only for Create activities, but also Update activities. --- .../web/activity_pub/mrf/tag_policy.ex | 18 +++--- .../web/activity_pub/mrf/tag_policy_test.exs | 60 +++++++++++++++++++ 2 files changed, 69 insertions(+), 9 deletions(-) diff --git a/lib/pleroma/web/activity_pub/mrf/tag_policy.ex b/lib/pleroma/web/activity_pub/mrf/tag_policy.ex index 56ae654f2..65a358c59 100644 --- a/lib/pleroma/web/activity_pub/mrf/tag_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/tag_policy.ex @@ -27,22 +27,22 @@ defp get_tags(_), do: [] defp process_tag( "mrf_tag:media-force-nsfw", %{ - "type" => "Create", + "type" => type, "object" => %{"attachment" => child_attachment} } = message ) - when length(child_attachment) > 0 do + when length(child_attachment) > 0 and type in ["Create", "Update"] do {:ok, Kernel.put_in(message, ["object", "sensitive"], true)} end defp process_tag( "mrf_tag:media-strip", %{ - "type" => "Create", + "type" => type, "object" => %{"attachment" => child_attachment} = object } = message ) - when length(child_attachment) > 0 do + when length(child_attachment) > 0 and type in ["Create", "Update"] do object = Map.delete(object, "attachment") message = Map.put(message, "object", object) @@ -52,13 +52,13 @@ defp process_tag( defp process_tag( "mrf_tag:force-unlisted", %{ - "type" => "Create", + "type" => type, "to" => to, "cc" => cc, "actor" => actor, "object" => object } = message - ) do + ) when type in ["Create", "Update"] do user = User.get_cached_by_ap_id(actor) if Enum.member?(to, Pleroma.Constants.as_public()) do @@ -85,13 +85,13 @@ defp process_tag( defp process_tag( "mrf_tag:sandbox", %{ - "type" => "Create", + "type" => type, "to" => to, "cc" => cc, "actor" => actor, "object" => object } = message - ) do + ) when type in ["Create", "Update"] do user = User.get_cached_by_ap_id(actor) if Enum.member?(to, Pleroma.Constants.as_public()) or @@ -152,7 +152,7 @@ def filter(%{"object" => target_actor, "type" => "Follow"} = message), do: filter_message(target_actor, message) @impl true - def filter(%{"actor" => actor, "type" => "Create"} = message), + def filter(%{"actor" => actor, "type" => type} = message) when type in ["Create", "Update"], do: filter_message(actor, message) @impl true diff --git a/test/pleroma/web/activity_pub/mrf/tag_policy_test.exs b/test/pleroma/web/activity_pub/mrf/tag_policy_test.exs index faaadff79..0c84b5bf3 100644 --- a/test/pleroma/web/activity_pub/mrf/tag_policy_test.exs +++ b/test/pleroma/web/activity_pub/mrf/tag_policy_test.exs @@ -53,7 +53,24 @@ test "removes from public timelines" do "cc" => ["d"] } + edit_message = %{ + "actor" => actor.ap_id, + "type" => "Update", + "object" => %{}, + "to" => [@public, "f"], + "cc" => [@public, "d"] + } + + edit_expect_message = %{ + "actor" => actor.ap_id, + "type" => "Update", + "object" => %{"to" => ["f", actor.follower_address], "cc" => ["d"]}, + "to" => ["f", actor.follower_address], + "cc" => ["d"] + } + assert TagPolicy.filter(message) == {:ok, except_message} + assert TagPolicy.filter(edit_message) == {:ok, edit_expect_message} end end @@ -77,7 +94,24 @@ test "removes from the federated timeline" do "cc" => ["d", @public] } + edit_message = %{ + "actor" => actor.ap_id, + "type" => "Update", + "object" => %{}, + "to" => [@public, "f"], + "cc" => [actor.follower_address, "d"] + } + + edit_expect_message = %{ + "actor" => actor.ap_id, + "type" => "Update", + "object" => %{"to" => ["f", actor.follower_address], "cc" => ["d", @public]}, + "to" => ["f", actor.follower_address], + "cc" => ["d", @public] + } + assert TagPolicy.filter(message) == {:ok, except_message} + assert TagPolicy.filter(edit_message) == {:ok, edit_expect_message} end end @@ -97,7 +131,20 @@ test "removes attachments" do "object" => %{} } + edit_message = %{ + "actor" => actor.ap_id, + "type" => "Update", + "object" => %{"attachment" => ["file1"]} + } + + edit_expect_message = %{ + "actor" => actor.ap_id, + "type" => "Update", + "object" => %{} + } + assert TagPolicy.filter(message) == {:ok, except_message} + assert TagPolicy.filter(edit_message) == {:ok, edit_expect_message} end end @@ -117,7 +164,20 @@ test "Mark as sensitive on presence of attachments" do "object" => %{"tag" => ["test"], "attachment" => ["file1"], "sensitive" => true} } + edit_message = %{ + "actor" => actor.ap_id, + "type" => "Update", + "object" => %{"tag" => ["test"], "attachment" => ["file1"]} + } + + edit_expect_message = %{ + "actor" => actor.ap_id, + "type" => "Update", + "object" => %{"tag" => ["test"], "attachment" => ["file1"], "sensitive" => true} + } + assert TagPolicy.filter(message) == {:ok, except_message} + assert TagPolicy.filter(edit_message) == {:ok, edit_expect_message} end end end From 1f863f0a36ebb0648c3d39ecb7ea9e3d01deab60 Mon Sep 17 00:00:00 2001 From: ilja Date: Thu, 8 Dec 2022 23:12:27 +0100 Subject: [PATCH 104/631] Fix MRF policies to also work with Update Objects who got updated would just pass through several of the MRF policies, undoing moderation in some situations. In the relevant cases we now check not only for Create activities, but also Update activities. I checked which ones checked explicitly on type Create using `grep '"type" => "Create"' lib/pleroma/web/activity_pub/mrf/*`. The following from that list have not been changed: * lib/pleroma/web/activity_pub/mrf/follow_bot_policy.ex * Not relevant for moderation * lib/pleroma/web/activity_pub/mrf/keyword_policy.ex * Already had a test for Update * lib/pleroma/web/activity_pub/mrf/object_age_policy.ex * In practice only relevant when fetching old objects (e.g. through Like or Announce). These are always wrapped in a Create. * lib/pleroma/web/activity_pub/mrf/reject_non_public.ex * We don't allow changing scope with Update, so not relevant here --- .../mrf/activity_expiration_policy.ex | 11 ++- .../activity_pub/mrf/anti_link_spam_policy.ex | 3 +- .../mrf/force_bot_unlisted_policy.ex | 5 +- .../web/activity_pub/mrf/hellthread_policy.ex | 4 +- .../web/activity_pub/mrf/mention_policy.ex | 2 +- .../web/activity_pub/mrf/simple_policy.ex | 9 +- .../web/activity_pub/mrf/tag_policy.ex | 6 +- .../mrf/activity_expiration_policy_test.exs | 42 +++++++- .../mrf/anti_link_spam_policy_test.exs | 95 +++++++++++++++++++ .../mrf/force_bot_unlisted_policy_test.exs | 25 +++++ .../mrf/hellthread_policy_test.exs | 44 +++++++-- .../activity_pub/mrf/mention_policy_test.exs | 48 ++++++++++ .../activity_pub/mrf/simple_policy_test.exs | 36 +++++++ 13 files changed, 308 insertions(+), 22 deletions(-) diff --git a/lib/pleroma/web/activity_pub/mrf/activity_expiration_policy.ex b/lib/pleroma/web/activity_pub/mrf/activity_expiration_policy.ex index e78254280..5f412566d 100644 --- a/lib/pleroma/web/activity_pub/mrf/activity_expiration_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/activity_expiration_policy.ex @@ -3,7 +3,7 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.ActivityPub.MRF.ActivityExpirationPolicy do - @moduledoc "Adds expiration to all local Create activities" + @moduledoc "Adds expiration to all local Create/Update activities" @behaviour Pleroma.Web.ActivityPub.MRF.Policy @impl true @@ -25,8 +25,13 @@ defp local?(%{"actor" => actor}) do String.starts_with?(actor, Pleroma.Web.Endpoint.url()) end - defp note?(activity) do - match?(%{"type" => "Create", "object" => %{"type" => "Note"}}, activity) + defp note?(%{"type" => type, "object" => %{"type" => "Note"}}) + when type in ["Create", "Update"] do + true + end + + defp note?(_) do + false end defp maybe_add_expiration(activity) do diff --git a/lib/pleroma/web/activity_pub/mrf/anti_link_spam_policy.ex b/lib/pleroma/web/activity_pub/mrf/anti_link_spam_policy.ex index ba7c8400b..6885df863 100644 --- a/lib/pleroma/web/activity_pub/mrf/anti_link_spam_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/anti_link_spam_policy.ex @@ -29,7 +29,8 @@ defp contains_links?(%{"content" => content} = _object) do defp contains_links?(_), do: false @impl true - def filter(%{"type" => "Create", "actor" => actor, "object" => object} = message) do + def filter(%{"type" => type, "actor" => actor, "object" => object} = message) + when type in ["Create", "Update"] do with {:ok, %User{local: false} = u} <- User.get_or_fetch_by_ap_id(actor), {:contains_links, true} <- {:contains_links, contains_links?(object)}, {:old_user, true} <- {:old_user, old_user?(u)} do diff --git a/lib/pleroma/web/activity_pub/mrf/force_bot_unlisted_policy.ex b/lib/pleroma/web/activity_pub/mrf/force_bot_unlisted_policy.ex index 11871375e..fa6b93333 100644 --- a/lib/pleroma/web/activity_pub/mrf/force_bot_unlisted_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/force_bot_unlisted_policy.ex @@ -17,13 +17,14 @@ defp check_if_bot(user), do: check_by_actor_type(user) or check_by_nickname(user @impl true def filter( %{ - "type" => "Create", + "type" => type, "to" => to, "cc" => cc, "actor" => actor, "object" => object } = message - ) do + ) + when type in ["Create", "Update"] do user = User.get_cached_by_ap_id(actor) isbot = check_if_bot(user) diff --git a/lib/pleroma/web/activity_pub/mrf/hellthread_policy.ex b/lib/pleroma/web/activity_pub/mrf/hellthread_policy.ex index 504bd4d57..18704fc2c 100644 --- a/lib/pleroma/web/activity_pub/mrf/hellthread_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/hellthread_policy.ex @@ -73,8 +73,8 @@ defp get_recipient_count(message) do end @impl true - def filter(%{"type" => "Create", "object" => %{"type" => object_type}} = message) - when object_type in ~w{Note Article} do + def filter(%{"type" => type, "object" => %{"type" => object_type}} = message) + when type in ~w{Create Update} and object_type in ~w{Note Article} do reject_threshold = Pleroma.Config.get( [:mrf_hellthread, :reject_threshold], diff --git a/lib/pleroma/web/activity_pub/mrf/mention_policy.ex b/lib/pleroma/web/activity_pub/mrf/mention_policy.ex index 05b28e4f5..11e9bd478 100644 --- a/lib/pleroma/web/activity_pub/mrf/mention_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/mention_policy.ex @@ -8,7 +8,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.MentionPolicy do @behaviour Pleroma.Web.ActivityPub.MRF.Policy @impl true - def filter(%{"type" => "Create"} = message) do + def filter(%{"type" => type} = message) when type in ["Create", "Update"] do reject_actors = Pleroma.Config.get([:mrf_mention, :actors], []) recipients = (message["to"] || []) ++ (message["cc"] || []) diff --git a/lib/pleroma/web/activity_pub/mrf/simple_policy.ex b/lib/pleroma/web/activity_pub/mrf/simple_policy.ex index 415c5d2dd..a59212db4 100644 --- a/lib/pleroma/web/activity_pub/mrf/simple_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/simple_policy.ex @@ -40,9 +40,9 @@ defp check_reject(%{host: actor_host} = _actor_info, object) do defp check_media_removal( %{host: actor_host} = _actor_info, - %{"type" => "Create", "object" => %{"attachment" => child_attachment}} = object + %{"type" => type, "object" => %{"attachment" => child_attachment}} = object ) - when length(child_attachment) > 0 do + when type in ["Create", "Update"] and length(child_attachment) > 0 do media_removal = instance_list(:media_removal) |> MRF.subdomains_regex() @@ -63,10 +63,11 @@ defp check_media_removal(_actor_info, object), do: {:ok, object} defp check_media_nsfw( %{host: actor_host} = _actor_info, %{ - "type" => "Create", + "type" => type, "object" => %{} = _child_object } = object - ) do + ) + when type in ["Create", "Update"] do media_nsfw = instance_list(:media_nsfw) |> MRF.subdomains_regex() diff --git a/lib/pleroma/web/activity_pub/mrf/tag_policy.ex b/lib/pleroma/web/activity_pub/mrf/tag_policy.ex index 65a358c59..634b6a62f 100644 --- a/lib/pleroma/web/activity_pub/mrf/tag_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/tag_policy.ex @@ -58,7 +58,8 @@ defp process_tag( "actor" => actor, "object" => object } = message - ) when type in ["Create", "Update"] do + ) + when type in ["Create", "Update"] do user = User.get_cached_by_ap_id(actor) if Enum.member?(to, Pleroma.Constants.as_public()) do @@ -91,7 +92,8 @@ defp process_tag( "actor" => actor, "object" => object } = message - ) when type in ["Create", "Update"] do + ) + when type in ["Create", "Update"] do user = User.get_cached_by_ap_id(actor) if Enum.member?(to, Pleroma.Constants.as_public()) or diff --git a/test/pleroma/web/activity_pub/mrf/activity_expiration_policy_test.exs b/test/pleroma/web/activity_pub/mrf/activity_expiration_policy_test.exs index 47b07fdd9..a3c23a85c 100644 --- a/test/pleroma/web/activity_pub/mrf/activity_expiration_policy_test.exs +++ b/test/pleroma/web/activity_pub/mrf/activity_expiration_policy_test.exs @@ -19,6 +19,16 @@ test "adds `expires_at` property" do }) assert Timex.diff(expires_at, DateTime.utc_now(), :days) == 364 + + assert {:ok, %{"type" => "Update", "expires_at" => expires_at}} = + ActivityExpirationPolicy.filter(%{ + "id" => @id, + "actor" => @local_actor, + "type" => "Update", + "object" => %{"type" => "Note"} + }) + + assert Timex.diff(expires_at, DateTime.utc_now(), :days) == 364 end test "keeps existing `expires_at` if it less than the config setting" do @@ -32,6 +42,15 @@ test "keeps existing `expires_at` if it less than the config setting" do "expires_at" => expires_at, "object" => %{"type" => "Note"} }) + + assert {:ok, %{"type" => "Update", "expires_at" => ^expires_at}} = + ActivityExpirationPolicy.filter(%{ + "id" => @id, + "actor" => @local_actor, + "type" => "Update", + "expires_at" => expires_at, + "object" => %{"type" => "Note"} + }) end test "overwrites existing `expires_at` if it greater than the config setting" do @@ -47,6 +66,17 @@ test "overwrites existing `expires_at` if it greater than the config setting" do }) assert Timex.diff(expires_at, DateTime.utc_now(), :days) == 364 + + assert {:ok, %{"type" => "Update", "expires_at" => expires_at}} = + ActivityExpirationPolicy.filter(%{ + "id" => @id, + "actor" => @local_actor, + "type" => "Update", + "expires_at" => too_distant_future, + "object" => %{"type" => "Note"} + }) + + assert Timex.diff(expires_at, DateTime.utc_now(), :days) == 364 end test "ignores remote activities" do @@ -59,9 +89,19 @@ test "ignores remote activities" do }) refute Map.has_key?(activity, "expires_at") + + assert {:ok, activity} = + ActivityExpirationPolicy.filter(%{ + "id" => "https://example.com/123", + "actor" => "https://example.com/users/cofe", + "type" => "Update", + "object" => %{"type" => "Note"} + }) + + refute Map.has_key?(activity, "expires_at") end - test "ignores non-Create/Note activities" do + test "ignores non-Create/Update/Note activities" do assert {:ok, activity} = ActivityExpirationPolicy.filter(%{ "id" => "https://example.com/123", diff --git a/test/pleroma/web/activity_pub/mrf/anti_link_spam_policy_test.exs b/test/pleroma/web/activity_pub/mrf/anti_link_spam_policy_test.exs index c3ee03a05..6182e9717 100644 --- a/test/pleroma/web/activity_pub/mrf/anti_link_spam_policy_test.exs +++ b/test/pleroma/web/activity_pub/mrf/anti_link_spam_policy_test.exs @@ -32,6 +32,28 @@ defmodule Pleroma.Web.ActivityPub.MRF.AntiLinkSpamPolicyTest do } } + @linkless_update_message %{ + "type" => "Update", + "object" => %{ + "content" => "hi world!" + } + } + + @linkful_update_message %{ + "type" => "Update", + "object" => %{ + "content" => "hi world!" + } + } + + @response_update_message %{ + "type" => "Update", + "object" => %{ + "name" => "yes", + "type" => "Answer" + } + } + describe "with new user" do test "it allows posts without links" do user = insert(:user, local: false) @@ -42,7 +64,12 @@ test "it allows posts without links" do @linkless_message |> Map.put("actor", user.ap_id) + update_message = + @linkless_update_message + |> Map.put("actor", user.ap_id) + {:ok, _message} = AntiLinkSpamPolicy.filter(message) + {:ok, _update_message} = AntiLinkSpamPolicy.filter(update_message) end test "it disallows posts with links" do @@ -66,7 +93,24 @@ test "it disallows posts with links" do } } + update_message = %{ + "type" => "Update", + "actor" => user.ap_id, + "object" => %{ + "formerRepresentations" => %{ + "type" => "OrderedCollection", + "orderedItems" => [ + %{ + "content" => "hi world!" + } + ] + }, + "content" => "mew" + } + } + {:reject, _} = MRF.filter_one(AntiLinkSpamPolicy, message) + {:reject, _} = MRF.filter_one(AntiLinkSpamPolicy, update_message) end test "it allows posts with links for local users" do @@ -78,7 +122,12 @@ test "it allows posts with links for local users" do @linkful_message |> Map.put("actor", user.ap_id) + update_message = + @linkful_update_message + |> Map.put("actor", user.ap_id) + {:ok, _message} = AntiLinkSpamPolicy.filter(message) + {:ok, _update_message} = AntiLinkSpamPolicy.filter(update_message) end test "it disallows posts with links in history" do @@ -90,7 +139,12 @@ test "it disallows posts with links in history" do @linkful_message |> Map.put("actor", user.ap_id) + update_message = + @linkful_update_message + |> Map.put("actor", user.ap_id) + {:reject, _} = AntiLinkSpamPolicy.filter(message) + {:reject, _} = AntiLinkSpamPolicy.filter(update_message) end end @@ -104,7 +158,12 @@ test "it allows posts without links" do @linkless_message |> Map.put("actor", user.ap_id) + update_message = + @linkless_update_message + |> Map.put("actor", user.ap_id) + {:ok, _message} = AntiLinkSpamPolicy.filter(message) + {:ok, _update_message} = AntiLinkSpamPolicy.filter(update_message) end test "it allows posts with links" do @@ -116,7 +175,12 @@ test "it allows posts with links" do @linkful_message |> Map.put("actor", user.ap_id) + update_message = + @linkful_update_message + |> Map.put("actor", user.ap_id) + {:ok, _message} = AntiLinkSpamPolicy.filter(message) + {:ok, _update_message} = AntiLinkSpamPolicy.filter(update_message) end end @@ -130,7 +194,12 @@ test "it allows posts without links" do @linkless_message |> Map.put("actor", user.ap_id) + update_message = + @linkless_update_message + |> Map.put("actor", user.ap_id) + {:ok, _message} = AntiLinkSpamPolicy.filter(message) + {:ok, _update_message} = AntiLinkSpamPolicy.filter(update_message) end test "it allows posts with links" do @@ -142,7 +211,12 @@ test "it allows posts with links" do @linkful_message |> Map.put("actor", user.ap_id) + update_message = + @linkful_update_message + |> Map.put("actor", user.ap_id) + {:ok, _message} = AntiLinkSpamPolicy.filter(message) + {:ok, _update_message} = AntiLinkSpamPolicy.filter(update_message) end end @@ -161,9 +235,17 @@ test "it rejects posts without links" do @linkless_message |> Map.put("actor", "http://invalid.actor") + update_message = + @linkless_update_message + |> Map.put("actor", "http://invalid.actor") + assert capture_log(fn -> {:reject, _} = AntiLinkSpamPolicy.filter(message) end) =~ "[error] Could not decode user at fetch http://invalid.actor" + + assert capture_log(fn -> + {:reject, _} = AntiLinkSpamPolicy.filter(update_message) + end) =~ "[error] Could not decode user at fetch http://invalid.actor" end test "it rejects posts with links" do @@ -171,9 +253,17 @@ test "it rejects posts with links" do @linkful_message |> Map.put("actor", "http://invalid.actor") + update_message = + @linkful_update_message + |> Map.put("actor", "http://invalid.actor") + assert capture_log(fn -> {:reject, _} = AntiLinkSpamPolicy.filter(message) end) =~ "[error] Could not decode user at fetch http://invalid.actor" + + assert capture_log(fn -> + {:reject, _} = AntiLinkSpamPolicy.filter(update_message) + end) =~ "[error] Could not decode user at fetch http://invalid.actor" end end @@ -185,7 +275,12 @@ test "it does not reject them or error out" do @response_message |> Map.put("actor", user.ap_id) + update_message = + @response_update_message + |> Map.put("actor", user.ap_id) + {:ok, _message} = AntiLinkSpamPolicy.filter(message) + {:ok, _update_message} = AntiLinkSpamPolicy.filter(update_message) end end end diff --git a/test/pleroma/web/activity_pub/mrf/force_bot_unlisted_policy_test.exs b/test/pleroma/web/activity_pub/mrf/force_bot_unlisted_policy_test.exs index e3325d144..aa88f2f93 100644 --- a/test/pleroma/web/activity_pub/mrf/force_bot_unlisted_policy_test.exs +++ b/test/pleroma/web/activity_pub/mrf/force_bot_unlisted_policy_test.exs @@ -26,35 +26,60 @@ defp generate_messages(actor) do }} end + defp generate_update_messages(actor) do + {%{ + "actor" => actor.ap_id, + "type" => "Update", + "object" => %{}, + "to" => [@public, "f"], + "cc" => [actor.follower_address, "d"] + }, + %{ + "actor" => actor.ap_id, + "type" => "Update", + "object" => %{"to" => ["f", actor.follower_address], "cc" => ["d", @public]}, + "to" => ["f", actor.follower_address], + "cc" => ["d", @public] + }} + end + test "removes from the federated timeline by nickname heuristics 1" do actor = insert(:user, %{nickname: "annoying_ebooks@example.com"}) {message, except_message} = generate_messages(actor) + {update_message, except_update_message} = generate_update_messages(actor) assert ForceBotUnlistedPolicy.filter(message) == {:ok, except_message} + assert ForceBotUnlistedPolicy.filter(update_message) == {:ok, except_update_message} end test "removes from the federated timeline by nickname heuristics 2" do actor = insert(:user, %{nickname: "cirnonewsnetworkbot@meow.cat"}) {message, except_message} = generate_messages(actor) + {update_message, except_update_message} = generate_update_messages(actor) assert ForceBotUnlistedPolicy.filter(message) == {:ok, except_message} + assert ForceBotUnlistedPolicy.filter(update_message) == {:ok, except_update_message} end test "removes from the federated timeline by actor type Application" do actor = insert(:user, %{actor_type: "Application"}) {message, except_message} = generate_messages(actor) + {update_message, except_update_message} = generate_update_messages(actor) assert ForceBotUnlistedPolicy.filter(message) == {:ok, except_message} + assert ForceBotUnlistedPolicy.filter(update_message) == {:ok, except_update_message} end test "removes from the federated timeline by actor type Service" do actor = insert(:user, %{actor_type: "Service"}) {message, except_message} = generate_messages(actor) + {update_message, except_update_message} = generate_update_messages(actor) assert ForceBotUnlistedPolicy.filter(message) == {:ok, except_message} + assert ForceBotUnlistedPolicy.filter(update_message) == {:ok, except_update_message} end end diff --git a/test/pleroma/web/activity_pub/mrf/hellthread_policy_test.exs b/test/pleroma/web/activity_pub/mrf/hellthread_policy_test.exs index a88e1fa2e..2bcf49bc5 100644 --- a/test/pleroma/web/activity_pub/mrf/hellthread_policy_test.exs +++ b/test/pleroma/web/activity_pub/mrf/hellthread_policy_test.exs @@ -26,54 +26,86 @@ defmodule Pleroma.Web.ActivityPub.MRF.HellthreadPolicyTest do } } - [user: user, message: message] + update_message = %{ + "actor" => user.ap_id, + "cc" => [user.follower_address], + "type" => "Update", + "to" => [ + "https://www.w3.org/ns/activitystreams#Public", + "https://instance.tld/users/user1", + "https://instance.tld/users/user2", + "https://instance.tld/users/user3" + ], + "object" => %{ + "type" => "Note" + } + } + + [user: user, message: message, update_message: update_message] end setup do: clear_config(:mrf_hellthread) describe "reject" do test "rejects the message if the recipient count is above reject_threshold", %{ - message: message + message: message, + update_message: update_message } do clear_config([:mrf_hellthread], %{delist_threshold: 0, reject_threshold: 2}) assert {:reject, "[HellthreadPolicy] 3 recipients is over the limit of 2"} == filter(message) + + assert {:reject, "[HellthreadPolicy] 3 recipients is over the limit of 2"} == + filter(update_message) end test "does not reject the message if the recipient count is below reject_threshold", %{ - message: message + message: message, + update_message: update_message } do clear_config([:mrf_hellthread], %{delist_threshold: 0, reject_threshold: 3}) assert {:ok, ^message} = filter(message) + assert {:ok, ^update_message} = filter(update_message) end end describe "delist" do test "delists the message if the recipient count is above delist_threshold", %{ user: user, - message: message + message: message, + update_message: update_message } do clear_config([:mrf_hellthread], %{delist_threshold: 2, reject_threshold: 0}) {:ok, message} = filter(message) assert user.follower_address in message["to"] assert "https://www.w3.org/ns/activitystreams#Public" in message["cc"] + + {:ok, update_message} = filter(update_message) + assert user.follower_address in update_message["to"] + assert "https://www.w3.org/ns/activitystreams#Public" in update_message["cc"] end test "does not delist the message if the recipient count is below delist_threshold", %{ - message: message + message: message, + update_message: update_message } do clear_config([:mrf_hellthread], %{delist_threshold: 4, reject_threshold: 0}) assert {:ok, ^message} = filter(message) + assert {:ok, ^update_message} = filter(update_message) end end - test "excludes follower collection and public URI from threshold count", %{message: message} do + test "excludes follower collection and public URI from threshold count", %{ + message: message, + update_message: update_message + } do clear_config([:mrf_hellthread], %{delist_threshold: 0, reject_threshold: 3}) assert {:ok, ^message} = filter(message) + assert {:ok, ^update_message} = filter(update_message) end end diff --git a/test/pleroma/web/activity_pub/mrf/mention_policy_test.exs b/test/pleroma/web/activity_pub/mrf/mention_policy_test.exs index 80ddcacbe..8aef8bb1a 100644 --- a/test/pleroma/web/activity_pub/mrf/mention_policy_test.exs +++ b/test/pleroma/web/activity_pub/mrf/mention_policy_test.exs @@ -18,7 +18,14 @@ test "pass filter if allow list is empty" do "cc" => ["https://example.com/blocked"] } + update_message = %{ + "type" => "Update", + "to" => ["https://example.com/ok"], + "cc" => ["https://example.com/blocked"] + } + assert MentionPolicy.filter(message) == {:ok, message} + assert MentionPolicy.filter(update_message) == {:ok, update_message} end describe "allow" do @@ -29,7 +36,12 @@ test "empty" do "type" => "Create" } + update_message = %{ + "type" => "Update" + } + assert MentionPolicy.filter(message) == {:ok, message} + assert MentionPolicy.filter(update_message) == {:ok, update_message} end test "to" do @@ -40,7 +52,13 @@ test "to" do "to" => ["https://example.com/ok"] } + update_message = %{ + "type" => "Update", + "to" => ["https://example.com/ok"] + } + assert MentionPolicy.filter(message) == {:ok, message} + assert MentionPolicy.filter(update_message) == {:ok, update_message} end test "cc" do @@ -51,7 +69,13 @@ test "cc" do "cc" => ["https://example.com/ok"] } + update_message = %{ + "type" => "Update", + "cc" => ["https://example.com/ok"] + } + assert MentionPolicy.filter(message) == {:ok, message} + assert MentionPolicy.filter(update_message) == {:ok, update_message} end test "both" do @@ -63,7 +87,14 @@ test "both" do "cc" => ["https://example.com/ok2"] } + update_message = %{ + "type" => "Update", + "to" => ["https://example.com/ok"], + "cc" => ["https://example.com/ok2"] + } + assert MentionPolicy.filter(message) == {:ok, message} + assert MentionPolicy.filter(update_message) == {:ok, update_message} end end @@ -76,8 +107,16 @@ test "to" do "to" => ["https://example.com/blocked"] } + update_message = %{ + "type" => "Update", + "to" => ["https://example.com/blocked"] + } + assert MentionPolicy.filter(message) == {:reject, "[MentionPolicy] Rejected for mention of https://example.com/blocked"} + + assert MentionPolicy.filter(update_message) == + {:reject, "[MentionPolicy] Rejected for mention of https://example.com/blocked"} end test "cc" do @@ -89,8 +128,17 @@ test "cc" do "cc" => ["https://example.com/blocked"] } + update_message = %{ + "type" => "Update", + "to" => ["https://example.com/ok"], + "cc" => ["https://example.com/blocked"] + } + assert MentionPolicy.filter(message) == {:reject, "[MentionPolicy] Rejected for mention of https://example.com/blocked"} + + assert MentionPolicy.filter(update_message) == + {:reject, "[MentionPolicy] Rejected for mention of https://example.com/blocked"} end end end diff --git a/test/pleroma/web/activity_pub/mrf/simple_policy_test.exs b/test/pleroma/web/activity_pub/mrf/simple_policy_test.exs index 0569bfed3..036573171 100644 --- a/test/pleroma/web/activity_pub/mrf/simple_policy_test.exs +++ b/test/pleroma/web/activity_pub/mrf/simple_policy_test.exs @@ -26,15 +26,18 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do test "is empty" do clear_config([:mrf_simple, :media_removal], []) media_message = build_media_message() + media_update_message = build_media_update_message() local_message = build_local_message() assert SimplePolicy.filter(media_message) == {:ok, media_message} + assert SimplePolicy.filter(media_update_message) == {:ok, media_update_message} assert SimplePolicy.filter(local_message) == {:ok, local_message} end test "has a matching host" do clear_config([:mrf_simple, :media_removal], [{"remote.instance", "Some reason"}]) media_message = build_media_message() + media_update_message = build_media_update_message() local_message = build_local_message() assert SimplePolicy.filter(media_message) == @@ -42,12 +45,18 @@ test "has a matching host" do media_message |> Map.put("object", Map.delete(media_message["object"], "attachment"))} + assert SimplePolicy.filter(media_update_message) == + {:ok, + media_update_message + |> Map.put("object", Map.delete(media_update_message["object"], "attachment"))} + assert SimplePolicy.filter(local_message) == {:ok, local_message} end test "match with wildcard domain" do clear_config([:mrf_simple, :media_removal], [{"*.remote.instance", "Whatever reason"}]) media_message = build_media_message() + media_update_message = build_media_update_message() local_message = build_local_message() assert SimplePolicy.filter(media_message) == @@ -55,6 +64,11 @@ test "match with wildcard domain" do media_message |> Map.put("object", Map.delete(media_message["object"], "attachment"))} + assert SimplePolicy.filter(media_update_message) == + {:ok, + media_update_message + |> Map.put("object", Map.delete(media_update_message["object"], "attachment"))} + assert SimplePolicy.filter(local_message) == {:ok, local_message} end end @@ -63,31 +77,41 @@ test "match with wildcard domain" do test "is empty" do clear_config([:mrf_simple, :media_nsfw], []) media_message = build_media_message() + media_update_message = build_media_update_message() local_message = build_local_message() assert SimplePolicy.filter(media_message) == {:ok, media_message} + assert SimplePolicy.filter(media_update_message) == {:ok, media_update_message} assert SimplePolicy.filter(local_message) == {:ok, local_message} end test "has a matching host" do clear_config([:mrf_simple, :media_nsfw], [{"remote.instance", "Whetever"}]) media_message = build_media_message() + media_update_message = build_media_update_message() local_message = build_local_message() assert SimplePolicy.filter(media_message) == {:ok, put_in(media_message, ["object", "sensitive"], true)} + assert SimplePolicy.filter(media_update_message) == + {:ok, put_in(media_update_message, ["object", "sensitive"], true)} + assert SimplePolicy.filter(local_message) == {:ok, local_message} end test "match with wildcard domain" do clear_config([:mrf_simple, :media_nsfw], [{"*.remote.instance", "yeah yeah"}]) media_message = build_media_message() + media_update_message = build_media_update_message() local_message = build_local_message() assert SimplePolicy.filter(media_message) == {:ok, put_in(media_message, ["object", "sensitive"], true)} + assert SimplePolicy.filter(media_update_message) == + {:ok, put_in(media_update_message, ["object", "sensitive"], true)} + assert SimplePolicy.filter(local_message) == {:ok, local_message} end end @@ -104,6 +128,18 @@ defp build_media_message do } end + defp build_media_update_message do + %{ + "actor" => "https://remote.instance/users/bob", + "type" => "Update", + "object" => %{ + "attachment" => [%{}], + "tag" => ["foo"], + "sensitive" => false + } + } + end + describe "when :report_removal" do test "is empty" do clear_config([:mrf_simple, :report_removal], []) From 0eaec57d3f097b915ef5b4e88bd96069145d7184 Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Fri, 9 Dec 2022 10:24:38 +0000 Subject: [PATCH 105/631] mix format --- config/description.exs | 8 +++++++- lib/pleroma/web/static_fe/static_fe_controller.ex | 3 ++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/config/description.exs b/config/description.exs index a73d2a06b..a6b7231d0 100644 --- a/config/description.exs +++ b/config/description.exs @@ -1295,7 +1295,13 @@ label: "Post Content Type", type: {:dropdown, :atom}, description: "Default post formatting option", - suggestions: ["text/plain", "text/html", "text/markdown", "text/bbcode", "text/x.misskeymarkdown"] + suggestions: [ + "text/plain", + "text/html", + "text/markdown", + "text/bbcode", + "text/x.misskeymarkdown" + ] }, %{ key: :redirectRootNoLogin, diff --git a/lib/pleroma/web/static_fe/static_fe_controller.ex b/lib/pleroma/web/static_fe/static_fe_controller.ex index 0a4327a56..8e454f7a0 100644 --- a/lib/pleroma/web/static_fe/static_fe_controller.ex +++ b/lib/pleroma/web/static_fe/static_fe_controller.ex @@ -209,7 +209,8 @@ defp represent(%Activity{object: %Object{data: data}} = activity, selected) do } end - defp in_reply_to_user(%Activity{object: %Object{data: %{"inReplyTo" => inReplyTo}}} = activity) when is_binary(inReplyTo) do + defp in_reply_to_user(%Activity{object: %Object{data: %{"inReplyTo" => inReplyTo}}} = activity) + when is_binary(inReplyTo) do in_reply_to_activity = Activity.get_in_reply_to_activity(activity) if in_reply_to_activity do From 4c0911592b7f76e75d6741511a07bc39573d6d6a Mon Sep 17 00:00:00 2001 From: sn0w Date: Thu, 8 Dec 2022 10:04:20 +0100 Subject: [PATCH 106/631] Skip posts in indexer where publish date is nil --- lib/pleroma/search/elasticsearch/document_mappings/activity.ex | 2 +- lib/pleroma/search/meilisearch.ex | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pleroma/search/elasticsearch/document_mappings/activity.ex b/lib/pleroma/search/elasticsearch/document_mappings/activity.ex index 3a84e991b..b77c6e0d2 100644 --- a/lib/pleroma/search/elasticsearch/document_mappings/activity.ex +++ b/lib/pleroma/search/elasticsearch/document_mappings/activity.ex @@ -30,7 +30,7 @@ def object_to_search_data(object) do trimmed end - if String.length(content) > 1 do + if String.length(content) > 1 and not is_nil(data["published"]) do {:ok, published, _} = DateTime.from_iso8601(data["published"]) %{ diff --git a/lib/pleroma/search/meilisearch.ex b/lib/pleroma/search/meilisearch.ex index 770557858..c36b8f751 100644 --- a/lib/pleroma/search/meilisearch.ex +++ b/lib/pleroma/search/meilisearch.ex @@ -128,7 +128,7 @@ def object_to_search_data(object) do trimmed end - if String.length(content) > 1 do + if String.length(content) > 1 and not is_nil(data["published"]) do {:ok, published, _} = DateTime.from_iso8601(data["published"]) %{ From 6f83ae27aa924db1da2189cf495bd83cb41ba408 Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Fri, 9 Dec 2022 19:57:29 +0000 Subject: [PATCH 107/631] extend reject MRF to check if originating instance is blocked --- CHANGELOG.md | 1 + config/config.exs | 3 +- lib/pleroma/config/deprecation_warnings.ex | 3 +- .../web/activity_pub/mrf/simple_policy.ex | 209 ++++++++++++------ .../activity_pub/mrf/simple_policy_test.exs | 80 +++++++ 5 files changed, 224 insertions(+), 72 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 07ed6653a..017ec6a8c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Regular task to prune local transient activities - Task to manually run the transient prune job (pleroma.database prune\_task) - Ability to follow hashtags +- Option to extend `reject` in MRF-Simple to apply to entire threads, where the originating instance is rejected ## Changed - MastoAPI: Accept BooleanLike input on `/api/v1/accounts/:id/follow` (fixes follows with mastodon.py) diff --git a/config/config.exs b/config/config.exs index 8e0104400..4d6150634 100644 --- a/config/config.exs +++ b/config/config.exs @@ -391,7 +391,8 @@ accept: [], avatar_removal: [], banner_removal: [], - reject_deletes: [] + reject_deletes: [], + handle_threads: true config :pleroma, :mrf_keyword, reject: [], diff --git a/lib/pleroma/config/deprecation_warnings.ex b/lib/pleroma/config/deprecation_warnings.ex index 8a336c35a..73ef41145 100644 --- a/lib/pleroma/config/deprecation_warnings.ex +++ b/lib/pleroma/config/deprecation_warnings.ex @@ -25,7 +25,7 @@ defmodule Pleroma.Config.DeprecationWarnings do def check_simple_policy_tuples do has_strings = Config.get([:mrf_simple]) - |> Enum.any?(fn {_, v} -> Enum.any?(v, &is_binary/1) end) + |> Enum.any?(fn {_, v} -> is_list(v) and Enum.any?(v, &is_binary/1) end) if has_strings do Logger.warn(""" @@ -66,6 +66,7 @@ def check_simple_policy_tuples do new_config = Config.get([:mrf_simple]) + |> Enum.filter(fn {k, v} -> not is_atom(v) end) |> Enum.map(fn {k, v} -> {k, Enum.map(v, fn diff --git a/lib/pleroma/web/activity_pub/mrf/simple_policy.ex b/lib/pleroma/web/activity_pub/mrf/simple_policy.ex index a59212db4..f7eb0f159 100644 --- a/lib/pleroma/web/activity_pub/mrf/simple_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/simple_policy.ex @@ -13,20 +13,20 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do require Pleroma.Constants - defp check_accept(%{host: actor_host} = _actor_info, object) do + defp check_accept(%{host: actor_host} = _actor_info) do accepts = instance_list(:accept) |> MRF.subdomains_regex() cond do - accepts == [] -> {:ok, object} - actor_host == Config.get([Pleroma.Web.Endpoint, :url, :host]) -> {:ok, object} - MRF.subdomain_match?(accepts, actor_host) -> {:ok, object} + accepts == [] -> {:ok, nil} + actor_host == Config.get([Pleroma.Web.Endpoint, :url, :host]) -> {:ok, nil} + MRF.subdomain_match?(accepts, actor_host) -> {:ok, nil} true -> {:reject, "[SimplePolicy] host not in accept list"} end end - defp check_reject(%{host: actor_host} = _actor_info, object) do + defp check_reject(%{host: actor_host} = _actor_info) do rejects = instance_list(:reject) |> MRF.subdomains_regex() @@ -34,7 +34,7 @@ defp check_reject(%{host: actor_host} = _actor_info, object) do if MRF.subdomain_match?(rejects, actor_host) do {:reject, "[SimplePolicy] host in reject list"} else - {:ok, object} + {:ok, nil} end end @@ -178,6 +178,55 @@ defp check_banner_removal(%{host: actor_host} = _actor_info, %{"image" => _image defp check_banner_removal(_actor_info, object), do: {:ok, object} + defp extract_context_uri(%{"conversation" => "tag:" <> rest}) do + rest + |> String.split(",", parts: 2, trim: true) + |> hd() + |> case do + nil -> nil + hostname -> URI.parse("//" <> hostname) + end + end + + defp extract_context_uri(%{"context" => "http" <> _ = context}), do: URI.parse(context) + + defp extract_context_uri(_), do: nil + + defp check_context(activity) do + uri = extract_context_uri(activity) + + with {:uri, true} <- {:uri, Kernel.match?(%URI{}, uri)}, + {:ok, _} <- check_accept(uri), + {:ok, _} <- check_reject(uri) do + {:ok, activity} + else + # Can't check. + {:uri, false} -> {:ok, activity} + {:reject, nil} -> {:reject, "[SimplePolicy]"} + {:reject, _} = e -> e + _ -> {:reject, "[SimplePolicy]"} + end + end + + defp check_reply_to(%{"object" => %{"inReplyTo" => in_reply_to}} = activity) do + with {:ok, _} <- filter(in_reply_to) do + {:ok, activity} + end + end + + defp check_reply_to(activity), do: {:ok, activity} + + defp maybe_check_thread(activity) do + if Config.get([:mrf_simple, :handle_threads], true) do + with {:ok, _} <- check_context(activity), + {:ok, _} <- check_reply_to(activity) do + {:ok, activity} + end + else + {:ok, activity} + end + end + defp check_object(%{"object" => object} = activity) do with {:ok, _object} <- filter(object) do {:ok, activity} @@ -210,13 +259,14 @@ def filter(%{"type" => "Delete", "actor" => actor} = object) do def filter(%{"actor" => actor} = object) do actor_info = URI.parse(actor) - with {:ok, object} <- check_accept(actor_info, object), - {:ok, object} <- check_reject(actor_info, object), + with {:ok, _} <- check_accept(actor_info), + {:ok, _} <- check_reject(actor_info), {:ok, object} <- check_media_removal(actor_info, object), {:ok, object} <- check_media_nsfw(actor_info, object), {:ok, object} <- check_ftl_removal(actor_info, object), {:ok, object} <- check_followers_only(actor_info, object), {:ok, object} <- check_report_removal(actor_info, object), + {:ok, object} <- maybe_check_thread(object), {:ok, object} <- check_object(object) do {:ok, object} else @@ -230,8 +280,8 @@ def filter(%{"id" => actor, "type" => obj_type} = object) when obj_type in ["Application", "Group", "Organization", "Person", "Service"] do actor_info = URI.parse(actor) - with {:ok, object} <- check_accept(actor_info, object), - {:ok, object} <- check_reject(actor_info, object), + with {:ok, _} <- check_accept(actor_info), + {:ok, _} <- check_reject(actor_info), {:ok, object} <- check_avatar_removal(actor_info, object), {:ok, object} <- check_banner_removal(actor_info, object) do {:ok, object} @@ -242,11 +292,17 @@ def filter(%{"id" => actor, "type" => obj_type} = object) end end + def filter(%{"id" => id} = object) do + with {:ok, _} <- filter(id) do + {:ok, object} + end + end + def filter(object) when is_binary(object) do uri = URI.parse(object) - with {:ok, object} <- check_accept(uri, object), - {:ok, object} <- check_reject(uri, object) do + with {:ok, _} <- check_accept(uri), + {:ok, _} <- check_reject(uri) do {:ok, object} else {:reject, nil} -> {:reject, "[SimplePolicy]"} @@ -288,6 +344,7 @@ def describe do mrf_simple_excluded = Config.get(:mrf_simple) + |> Enum.filter(fn {_, v} -> is_list(v) end) |> Enum.map(fn {rule, instances} -> {rule, Enum.reject(instances, fn {host, _} -> host in exclusions end)} end) @@ -332,66 +389,78 @@ def config_description do label: "MRF Simple", description: "Simple ingress policies", children: - [ - %{ - key: :media_removal, - description: - "List of instances to strip media attachments from and the reason for doing so" - }, - %{ - key: :media_nsfw, - label: "Media NSFW", - description: - "List of instances to tag all media as NSFW (sensitive) from and the reason for doing so" - }, - %{ - key: :federated_timeline_removal, - description: - "List of instances to remove from the Federated (aka The Whole Known Network) Timeline and the reason for doing so" - }, - %{ - key: :reject, - description: - "List of instances to reject activities from (except deletes) and the reason for doing so" - }, - %{ - key: :accept, - description: - "List of instances to only accept activities from (except deletes) and the reason for doing so" - }, - %{ - key: :followers_only, - description: - "Force posts from the given instances to be visible by followers only and the reason for doing so" - }, - %{ - key: :report_removal, - description: "List of instances to reject reports from and the reason for doing so" - }, - %{ - key: :avatar_removal, - description: "List of instances to strip avatars from and the reason for doing so" - }, - %{ - key: :banner_removal, - description: "List of instances to strip banners from and the reason for doing so" - }, - %{ - key: :reject_deletes, - description: "List of instances to reject deletions from and the reason for doing so" - } - ] - |> Enum.map(fn setting -> - Map.merge( - setting, + ([ + %{ + key: :media_removal, + description: + "List of instances to strip media attachments from and the reason for doing so" + }, + %{ + key: :media_nsfw, + label: "Media NSFW", + description: + "List of instances to tag all media as NSFW (sensitive) from and the reason for doing so" + }, + %{ + key: :federated_timeline_removal, + description: + "List of instances to remove from the Federated (aka The Whole Known Network) Timeline and the reason for doing so" + }, + %{ + key: :reject, + description: + "List of instances to reject activities from (except deletes) and the reason for doing so" + }, + %{ + key: :accept, + description: + "List of instances to only accept activities from (except deletes) and the reason for doing so" + }, + %{ + key: :followers_only, + description: + "Force posts from the given instances to be visible by followers only and the reason for doing so" + }, + %{ + key: :report_removal, + description: "List of instances to reject reports from and the reason for doing so" + }, + %{ + key: :avatar_removal, + description: "List of instances to strip avatars from and the reason for doing so" + }, + %{ + key: :banner_removal, + description: "List of instances to strip banners from and the reason for doing so" + }, + %{ + key: :reject_deletes, + description: "List of instances to reject deletions from and the reason for doing so" + } + ] + |> Enum.map(fn setting -> + Map.merge( + setting, + %{ + type: {:list, :tuple}, + key_placeholder: "instance", + value_placeholder: "reason", + suggestions: [ + {"example.com", "Some reason"}, + {"*.example.com", "Another reason"} + ] + } + ) + end)) ++ + [ %{ - type: {:list, :tuple}, - key_placeholder: "instance", - value_placeholder: "reason", - suggestions: [{"example.com", "Some reason"}, {"*.example.com", "Another reason"}] + key: :handle_threads, + label: "Apply to entire threads", + type: :boolean, + description: + "Enable to filter replies to threads based from their originating instance, using the reject and accept rules" } - ) - end) + ] } end end diff --git a/test/pleroma/web/activity_pub/mrf/simple_policy_test.exs b/test/pleroma/web/activity_pub/mrf/simple_policy_test.exs index 036573171..875cf8f43 100644 --- a/test/pleroma/web/activity_pub/mrf/simple_policy_test.exs +++ b/test/pleroma/web/activity_pub/mrf/simple_policy_test.exs @@ -356,6 +356,86 @@ test "reject by URI object" do assert {:reject, _} = SimplePolicy.filter(announce) end + + test "accept by matching context URI if :handle_threads is disabled" do + clear_config([:mrf_simple, :reject], [{"blocked.tld", ""}]) + clear_config([:mrf_simple, :handle_threads], false) + + remote_message = + build_remote_message() + |> Map.put("context", "https://blocked.tld/contexts/abc") + + assert {:ok, _} = SimplePolicy.filter(remote_message) + end + + test "accept by matching conversation field if :handle_threads is disabled" do + clear_config([:mrf_simple, :reject], [{"blocked.tld", ""}]) + clear_config([:mrf_simple, :handle_threads], false) + + remote_message = + build_remote_message() + |> Map.put( + "conversation", + "tag:blocked.tld,1997-06-25:objectId=12345:objectType=Conversation" + ) + + assert {:ok, _} = SimplePolicy.filter(remote_message) + end + + test "accept by matching reply ID if :handle_threads is disabled" do + clear_config([:mrf_simple, :reject], [{"blocked.tld", ""}]) + clear_config([:mrf_simple, :handle_threads], false) + + remote_message = + build_remote_message() + |> Map.put("type", "Create") + |> Map.put("object", %{ + "type" => "Note", + "inReplyTo" => "https://blocked.tld/objects/1" + }) + + assert {:ok, _} = SimplePolicy.filter(remote_message) + end + + test "reject by matching context URI if :handle_threads is enabled" do + clear_config([:mrf_simple, :reject], [{"blocked.tld", ""}]) + clear_config([:mrf_simple, :handle_threads], true) + + remote_message = + build_remote_message() + |> Map.put("context", "https://blocked.tld/contexts/abc") + + assert {:reject, _} = SimplePolicy.filter(remote_message) + end + + test "reject by matching conversation field if :handle_threads is enabled" do + clear_config([:mrf_simple, :reject], [{"blocked.tld", ""}]) + clear_config([:mrf_simple, :handle_threads], true) + + remote_message = + build_remote_message() + |> Map.put( + "conversation", + "tag:blocked.tld,1997-06-25:objectId=12345:objectType=Conversation" + ) + + assert {:reject, _} = SimplePolicy.filter(remote_message) + end + + test "reject by matching reply ID if :handle_threads is enabled" do + clear_config([:mrf_simple, :reject], [{"blocked.tld", ""}]) + clear_config([:mrf_simple, :handle_threads], true) + + remote_message = + build_remote_message() + |> Map.put("type", "Create") + |> Map.put("object", %{ + "type" => "Note", + "inReplyTo" => "https://blocked.tld/objects/1" + }) + + assert {:reject, _} = SimplePolicy.filter(remote_message) + end end describe "when :followers_only" do From 9db4c2429fce2d9f56cc59de64b3d6b62e1a7071 Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Fri, 9 Dec 2022 19:59:27 +0000 Subject: [PATCH 108/631] Remove FollowBotPolicy --- CHANGELOG.md | 3 + docs/docs/configuration/cheatsheet.md | 5 - .../web/activity_pub/mrf/follow_bot_policy.ex | 59 -------- .../mrf/follow_bot_policy_test.exs | 126 ------------------ 4 files changed, 3 insertions(+), 190 deletions(-) delete mode 100644 lib/pleroma/web/activity_pub/mrf/follow_bot_policy.ex delete mode 100644 test/pleroma/web/activity_pub/mrf/follow_bot_policy_test.exs diff --git a/CHANGELOG.md b/CHANGELOG.md index 017ec6a8c..4f266d514 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Transient activities recieved from remote servers are no longer persisted in the database - Overhauled static-fe view for logged-out users +## Removed +- FollowBotPolicy + ## Upgrade Notes - If you have an old instance, you will probably want to run `mix pleroma.database prune_task` in the foreground to catch it up with the history of your instance. diff --git a/docs/docs/configuration/cheatsheet.md b/docs/docs/configuration/cheatsheet.md index 12c044d67..3c8bbcf84 100644 --- a/docs/docs/configuration/cheatsheet.md +++ b/docs/docs/configuration/cheatsheet.md @@ -221,11 +221,6 @@ Notes: - The hashtags in the configuration do not have a leading `#`. - This MRF Policy is always enabled, if you want to disable it you have to set empty lists -#### :mrf_follow_bot - -* `follower_nickname`: The name of the bot account to use for following newly discovered users. Using `followbot` or similar is strongly suggested. - - ### :activitypub * `unfollow_blocked`: Whether blocks result in people getting unfollowed * `outgoing_blocks`: Whether to federate blocks to other instances diff --git a/lib/pleroma/web/activity_pub/mrf/follow_bot_policy.ex b/lib/pleroma/web/activity_pub/mrf/follow_bot_policy.ex deleted file mode 100644 index 7cf7de068..000000000 --- a/lib/pleroma/web/activity_pub/mrf/follow_bot_policy.ex +++ /dev/null @@ -1,59 +0,0 @@ -defmodule Pleroma.Web.ActivityPub.MRF.FollowBotPolicy do - @behaviour Pleroma.Web.ActivityPub.MRF.Policy - alias Pleroma.Config - alias Pleroma.User - alias Pleroma.Web.CommonAPI - - require Logger - - @impl true - def filter(message) do - with follower_nickname <- Config.get([:mrf_follow_bot, :follower_nickname]), - %User{actor_type: "Service"} = follower <- - User.get_cached_by_nickname(follower_nickname), - %{"type" => "Create", "object" => %{"type" => "Note"}} <- message do - try_follow(follower, message) - else - nil -> - Logger.warn( - "#{__MODULE__} skipped because of missing `:mrf_follow_bot, :follower_nickname` configuration, the :follower_nickname - account does not exist, or the account is not correctly configured as a bot." - ) - - {:ok, message} - - _ -> - {:ok, message} - end - end - - defp try_follow(follower, message) do - to = Map.get(message, "to", []) - cc = Map.get(message, "cc", []) - actor = [message["actor"]] - - Enum.concat([to, cc, actor]) - |> List.flatten() - |> Enum.uniq() - |> User.get_all_by_ap_id() - |> Enum.each(fn user -> - with false <- user.local, - false <- User.following?(follower, user), - false <- User.locked?(user), - false <- (user.bio || "") |> String.downcase() |> String.contains?("nobot") do - Logger.debug( - "#{__MODULE__}: Follow request from #{follower.nickname} to #{user.nickname}" - ) - - CommonAPI.follow(follower, user) - end - end) - - {:ok, message} - end - - @impl true - def describe do - {:ok, %{}} - end -end diff --git a/test/pleroma/web/activity_pub/mrf/follow_bot_policy_test.exs b/test/pleroma/web/activity_pub/mrf/follow_bot_policy_test.exs deleted file mode 100644 index a61562558..000000000 --- a/test/pleroma/web/activity_pub/mrf/follow_bot_policy_test.exs +++ /dev/null @@ -1,126 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2021 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.ActivityPub.MRF.FollowBotPolicyTest do - use Pleroma.DataCase, async: true - - alias Pleroma.User - alias Pleroma.Web.ActivityPub.MRF.FollowBotPolicy - - import Pleroma.Factory - - describe "FollowBotPolicy" do - test "follows remote users" do - bot = insert(:user, actor_type: "Service") - remote_user = insert(:user, local: false) - clear_config([:mrf_follow_bot, :follower_nickname], bot.nickname) - - message = %{ - "@context" => "https://www.w3.org/ns/activitystreams", - "to" => [remote_user.follower_address], - "cc" => ["https://www.w3.org/ns/activitystreams#Public"], - "type" => "Create", - "object" => %{ - "content" => "Test post", - "type" => "Note", - "attributedTo" => remote_user.ap_id, - "inReplyTo" => nil - }, - "actor" => remote_user.ap_id - } - - refute User.following?(bot, remote_user) - - assert User.get_follow_requests(remote_user) |> length == 0 - - FollowBotPolicy.filter(message) - - assert User.get_follow_requests(remote_user) |> length == 1 - end - - test "does not follow users with #nobot in bio" do - bot = insert(:user, actor_type: "Service") - remote_user = insert(:user, %{local: false, bio: "go away bots! #nobot"}) - clear_config([:mrf_follow_bot, :follower_nickname], bot.nickname) - - message = %{ - "@context" => "https://www.w3.org/ns/activitystreams", - "to" => [remote_user.follower_address], - "cc" => ["https://www.w3.org/ns/activitystreams#Public"], - "type" => "Create", - "object" => %{ - "content" => "I don't like follow bots", - "type" => "Note", - "attributedTo" => remote_user.ap_id, - "inReplyTo" => nil - }, - "actor" => remote_user.ap_id - } - - refute User.following?(bot, remote_user) - - assert User.get_follow_requests(remote_user) |> length == 0 - - FollowBotPolicy.filter(message) - - assert User.get_follow_requests(remote_user) |> length == 0 - end - - test "does not follow local users" do - bot = insert(:user, actor_type: "Service") - local_user = insert(:user, local: true) - clear_config([:mrf_follow_bot, :follower_nickname], bot.nickname) - - message = %{ - "@context" => "https://www.w3.org/ns/activitystreams", - "to" => [local_user.follower_address], - "cc" => ["https://www.w3.org/ns/activitystreams#Public"], - "type" => "Create", - "object" => %{ - "content" => "Hi I'm a local user", - "type" => "Note", - "attributedTo" => local_user.ap_id, - "inReplyTo" => nil - }, - "actor" => local_user.ap_id - } - - refute User.following?(bot, local_user) - - assert User.get_follow_requests(local_user) |> length == 0 - - FollowBotPolicy.filter(message) - - assert User.get_follow_requests(local_user) |> length == 0 - end - - test "does not follow users requiring follower approval" do - bot = insert(:user, actor_type: "Service") - remote_user = insert(:user, %{local: false, is_locked: true}) - clear_config([:mrf_follow_bot, :follower_nickname], bot.nickname) - - message = %{ - "@context" => "https://www.w3.org/ns/activitystreams", - "to" => [remote_user.follower_address], - "cc" => ["https://www.w3.org/ns/activitystreams#Public"], - "type" => "Create", - "object" => %{ - "content" => "I don't like randos following me", - "type" => "Note", - "attributedTo" => remote_user.ap_id, - "inReplyTo" => nil - }, - "actor" => remote_user.ap_id - } - - refute User.following?(bot, remote_user) - - assert User.get_follow_requests(remote_user) |> length == 0 - - FollowBotPolicy.filter(message) - - assert User.get_follow_requests(remote_user) |> length == 0 - end - end -end From dcf58a3c532d22bc13505b84a50c2c1ddfdaa960 Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Fri, 9 Dec 2022 20:01:38 +0000 Subject: [PATCH 109/631] Do not pass transient undo-y activities through MRF --- CHANGELOG.md | 1 + lib/pleroma/web/activity_pub/mrf.ex | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4f266d514..6956912a7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## Removed - FollowBotPolicy +- Passing of undo/block into MRF ## Upgrade Notes - If you have an old instance, you will probably want to run `mix pleroma.database prune_task` in the foreground to catch it up with the history of your instance. diff --git a/lib/pleroma/web/activity_pub/mrf.ex b/lib/pleroma/web/activity_pub/mrf.ex index 064ffc527..dae6d7f6a 100644 --- a/lib/pleroma/web/activity_pub/mrf.ex +++ b/lib/pleroma/web/activity_pub/mrf.ex @@ -63,6 +63,12 @@ defmodule Pleroma.Web.ActivityPub.MRF do @required_description_keys [:key, :related_policy] + def filter_one(policy, %{"type" => type} = message) + when type in ["Undo", "Block", "Delete"] and + policy != Pleroma.Web.ActivityPub.MRF.SimplePolicy do + {:ok, message} + end + def filter_one(policy, message) do should_plug_history? = if function_exported?(policy, :history_awareness, 0) do From bc265bfd541ea437481786504c0334444626f06f Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Fri, 9 Dec 2022 20:04:48 +0000 Subject: [PATCH 110/631] Underscore unused variable --- lib/pleroma/config/deprecation_warnings.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pleroma/config/deprecation_warnings.ex b/lib/pleroma/config/deprecation_warnings.ex index 73ef41145..c213f3ce6 100644 --- a/lib/pleroma/config/deprecation_warnings.ex +++ b/lib/pleroma/config/deprecation_warnings.ex @@ -66,7 +66,7 @@ def check_simple_policy_tuples do new_config = Config.get([:mrf_simple]) - |> Enum.filter(fn {k, v} -> not is_atom(v) end) + |> Enum.filter(fn {_k, v} -> not is_atom(v) end) |> Enum.map(fn {k, v} -> {k, Enum.map(v, fn From f5a315f04cc4e07ff951a2c084525d899291df92 Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Fri, 9 Dec 2022 20:13:31 +0000 Subject: [PATCH 111/631] Add URL and code to :not_found errors Ref #355 --- CHANGELOG.md | 1 + lib/pleroma/collections/fetcher.ex | 2 +- lib/pleroma/object/fetcher.ex | 4 ++-- lib/pleroma/web/activity_pub/activity_pub.ex | 2 +- test/pleroma/object/fetcher_test.exs | 6 ++++-- 5 files changed, 9 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6956912a7..eef3c53b8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Task to manually run the transient prune job (pleroma.database prune\_task) - Ability to follow hashtags - Option to extend `reject` in MRF-Simple to apply to entire threads, where the originating instance is rejected +- Extra information to failed HTTP requests ## Changed - MastoAPI: Accept BooleanLike input on `/api/v1/accounts/:id/follow` (fixes follows with mastodon.py) diff --git a/lib/pleroma/collections/fetcher.ex b/lib/pleroma/collections/fetcher.ex index ab69f4b84..a2fcb7794 100644 --- a/lib/pleroma/collections/fetcher.ex +++ b/lib/pleroma/collections/fetcher.ex @@ -68,7 +68,7 @@ defp fetch_page_items(id, items \\ []) do items end else - {:error, "Object has been deleted"} -> + {:error, {"Object has been deleted", _, _}} -> items {:error, error} -> diff --git a/lib/pleroma/object/fetcher.ex b/lib/pleroma/object/fetcher.ex index a9dfa18e7..cde4e5039 100644 --- a/lib/pleroma/object/fetcher.ex +++ b/lib/pleroma/object/fetcher.ex @@ -180,7 +180,7 @@ def fetch_object_from_id!(id, options \\ []) do {:error, %Tesla.Mock.Error{}} -> nil - {:error, "Object has been deleted"} -> + {:error, {"Object has been deleted", _id, _code}} -> nil {:reject, reason} -> @@ -284,7 +284,7 @@ defp get_object(id) do end {:ok, %{status: code}} when code in [404, 410] -> - {:error, "Object has been deleted"} + {:error, {"Object has been deleted", id, code}} {:error, e} -> {:error, e} diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index d700128c0..521c8b852 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -1711,7 +1711,7 @@ def fetch_and_prepare_user_from_ap_id(ap_id, additional \\ []) do {:ok, maybe_update_follow_information(data)} else # If this has been deleted, only log a debug and not an error - {:error, "Object has been deleted" = e} -> + {:error, {"Object has been deleted" = e, _, _}} -> Logger.debug("Could not decode user at fetch #{ap_id}, #{inspect(e)}") {:error, e} diff --git a/test/pleroma/object/fetcher_test.exs b/test/pleroma/object/fetcher_test.exs index 71306cdfe..22192d98f 100644 --- a/test/pleroma/object/fetcher_test.exs +++ b/test/pleroma/object/fetcher_test.exs @@ -216,14 +216,16 @@ test "all objects with fake directions are rejected by the object fetcher" do end test "handle HTTP 410 Gone response" do - assert {:error, "Object has been deleted"} == + assert {:error, + {"Object has been deleted", "https://mastodon.example.org/users/userisgone", 410}} == Fetcher.fetch_and_contain_remote_object_from_id( "https://mastodon.example.org/users/userisgone" ) end test "handle HTTP 404 response" do - assert {:error, "Object has been deleted"} == + assert {:error, + {"Object has been deleted", "https://mastodon.example.org/users/userisgone404", 404}} == Fetcher.fetch_and_contain_remote_object_from_id( "https://mastodon.example.org/users/userisgone404" ) From e49b583147748be73062acc92ea510f6f55a503a Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Fri, 9 Dec 2022 20:27:54 +0000 Subject: [PATCH 112/631] mandate published on notes fixes #356 --- CHANGELOG.md | 1 + lib/mix/tasks/pleroma/search/meilisearch.ex | 3 +- .../article_note_page_validator.ex | 2 +- .../mastodon/note-without-published.json | 44 +++++++++++++++++++ .../article_note_page_validator_test.exs | 7 +++ 5 files changed, 55 insertions(+), 2 deletions(-) create mode 100644 test/fixtures/mastodon/note-without-published.json diff --git a/CHANGELOG.md b/CHANGELOG.md index eef3c53b8..c0aa002a1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Follow/Block/Mute imports now spin off into *n* tasks to avoid the oban timeout - Transient activities recieved from remote servers are no longer persisted in the database - Overhauled static-fe view for logged-out users +- `published` is now a mandatory field in Note objects ## Removed - FollowBotPolicy diff --git a/lib/mix/tasks/pleroma/search/meilisearch.ex b/lib/mix/tasks/pleroma/search/meilisearch.ex index 27a31afcf..caeeb58d5 100644 --- a/lib/mix/tasks/pleroma/search/meilisearch.ex +++ b/lib/mix/tasks/pleroma/search/meilisearch.ex @@ -60,7 +60,8 @@ def run(["index"]) do where: fragment("data->>'type' = 'Note'") and (fragment("data->'to' \\? ?", ^Pleroma.Constants.as_public()) or - fragment("data->'cc' \\? ?", ^Pleroma.Constants.as_public())), + fragment("data->'cc' \\? ?", ^Pleroma.Constants.as_public())) and + fragment("data->>'published' IS NOT NULL"), order_by: [desc: fragment("data->'published'")] ) diff --git a/lib/pleroma/web/activity_pub/object_validators/article_note_page_validator.ex b/lib/pleroma/web/activity_pub/object_validators/article_note_page_validator.ex index 0d45421e2..0967f557a 100644 --- a/lib/pleroma/web/activity_pub/object_validators/article_note_page_validator.ex +++ b/lib/pleroma/web/activity_pub/object_validators/article_note_page_validator.ex @@ -172,7 +172,7 @@ def changeset(struct, data) do defp validate_data(data_cng) do data_cng |> validate_inclusion(:type, ["Article", "Note", "Page"]) - |> validate_required([:id, :actor, :attributedTo, :type, :context]) + |> validate_required([:id, :actor, :attributedTo, :type, :context, :published]) |> CommonValidations.validate_any_presence([:cc, :to]) |> CommonValidations.validate_fields_match([:actor, :attributedTo]) |> CommonValidations.validate_actor_presence() diff --git a/test/fixtures/mastodon/note-without-published.json b/test/fixtures/mastodon/note-without-published.json new file mode 100644 index 000000000..c721ecef5 --- /dev/null +++ b/test/fixtures/mastodon/note-without-published.json @@ -0,0 +1,44 @@ +{ + "@context" : [ + "https://www.w3.org/ns/activitystreams", + "https://w3id.org/security/v1", + { + "Emoji" : "toot:Emoji", + "Hashtag" : "as:Hashtag", + "atomUri" : "ostatus:atomUri", + "conversation" : "ostatus:conversation", + "inReplyToAtomUri" : "ostatus:inReplyToAtomUri", + "manuallyApprovesFollowers" : "as:manuallyApprovesFollowers", + "movedTo" : "as:movedTo", + "ostatus" : "http://ostatus.org#", + "sensitive" : "as:sensitive", + "toot" : "http://joinmastodon.org/ns#" + } + ], + "atomUri" : "http://mastodon.example.org/users/admin/statuses/99541947525187367", + "attachment" : [ + { + "mediaType" : "image/jpeg", + "name" : null, + "type" : "Document", + "url" : "http://mastodon.example.org/system/media_attachments/files/000/000/002/original/334ce029e7bfb920.jpg" + } + ], + "attributedTo" : "http://mastodon.example.org/users/admin", + "cc" : [ + "http://mastodon.example.org/users/admin/followers" + ], + "content" : "

yeah.

", + "conversation" : "tag:mastodon.example.org,2018-02-17:objectId=59:objectType=Conversation", + "id" : "http://mastodon.example.org/users/admin/statuses/99541947525187367", + "inReplyTo" : null, + "inReplyToAtomUri" : null, + "sensitive" : false, + "summary" : null, + "tag" : [], + "to" : [ + "https://www.w3.org/ns/activitystreams#Public" + ], + "type" : "Note", + "url" : "http://mastodon.example.org/@admin/99541947525187367" +} diff --git a/test/pleroma/web/activity_pub/object_validators/article_note_page_validator_test.exs b/test/pleroma/web/activity_pub/object_validators/article_note_page_validator_test.exs index 5b95ebc51..0ddc3c76d 100644 --- a/test/pleroma/web/activity_pub/object_validators/article_note_page_validator_test.exs +++ b/test/pleroma/web/activity_pub/object_validators/article_note_page_validator_test.exs @@ -28,6 +28,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.ArticleNotePageValidatorTest "to" => [user.follower_address], "cc" => [], "content" => "Hellow this is content.", + "published" => "2021-01-01T00:00:00Z", "context" => "xxx", "summary" => "a post" } @@ -65,6 +66,12 @@ test "a note with a remote replies collection should validate", _ do ArticleNotePageValidator.cast_and_validate(note) end + test "a note without a published field should not validate", _ do + insert(:user, %{ap_id: "http://mastodon.example.org/users/admin"}) + note = Jason.decode!(File.read!("test/fixtures/mastodon/note-without-published.json")) + %{valid?: false} = ArticleNotePageValidator.cast_and_validate(note) + end + test "a note with an attachment should work", _ do insert(:user, %{ap_id: "https://owncast.localhost.localdomain/federation/user/streamer"}) From 739ed14f54eea3bf6e5ddabdf3fa7f60b9618aff Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Fri, 9 Dec 2022 20:59:26 +0000 Subject: [PATCH 113/631] Revert "mandate published on notes" This reverts commit e49b583147748be73062acc92ea510f6f55a503a. --- CHANGELOG.md | 1 - lib/mix/tasks/pleroma/search/meilisearch.ex | 3 +- .../article_note_page_validator.ex | 2 +- .../mastodon/note-without-published.json | 44 ------------------- .../article_note_page_validator_test.exs | 7 --- 5 files changed, 2 insertions(+), 55 deletions(-) delete mode 100644 test/fixtures/mastodon/note-without-published.json diff --git a/CHANGELOG.md b/CHANGELOG.md index c0aa002a1..eef3c53b8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,7 +23,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Follow/Block/Mute imports now spin off into *n* tasks to avoid the oban timeout - Transient activities recieved from remote servers are no longer persisted in the database - Overhauled static-fe view for logged-out users -- `published` is now a mandatory field in Note objects ## Removed - FollowBotPolicy diff --git a/lib/mix/tasks/pleroma/search/meilisearch.ex b/lib/mix/tasks/pleroma/search/meilisearch.ex index caeeb58d5..27a31afcf 100644 --- a/lib/mix/tasks/pleroma/search/meilisearch.ex +++ b/lib/mix/tasks/pleroma/search/meilisearch.ex @@ -60,8 +60,7 @@ def run(["index"]) do where: fragment("data->>'type' = 'Note'") and (fragment("data->'to' \\? ?", ^Pleroma.Constants.as_public()) or - fragment("data->'cc' \\? ?", ^Pleroma.Constants.as_public())) and - fragment("data->>'published' IS NOT NULL"), + fragment("data->'cc' \\? ?", ^Pleroma.Constants.as_public())), order_by: [desc: fragment("data->'published'")] ) diff --git a/lib/pleroma/web/activity_pub/object_validators/article_note_page_validator.ex b/lib/pleroma/web/activity_pub/object_validators/article_note_page_validator.ex index 0967f557a..0d45421e2 100644 --- a/lib/pleroma/web/activity_pub/object_validators/article_note_page_validator.ex +++ b/lib/pleroma/web/activity_pub/object_validators/article_note_page_validator.ex @@ -172,7 +172,7 @@ def changeset(struct, data) do defp validate_data(data_cng) do data_cng |> validate_inclusion(:type, ["Article", "Note", "Page"]) - |> validate_required([:id, :actor, :attributedTo, :type, :context, :published]) + |> validate_required([:id, :actor, :attributedTo, :type, :context]) |> CommonValidations.validate_any_presence([:cc, :to]) |> CommonValidations.validate_fields_match([:actor, :attributedTo]) |> CommonValidations.validate_actor_presence() diff --git a/test/fixtures/mastodon/note-without-published.json b/test/fixtures/mastodon/note-without-published.json deleted file mode 100644 index c721ecef5..000000000 --- a/test/fixtures/mastodon/note-without-published.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "@context" : [ - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/v1", - { - "Emoji" : "toot:Emoji", - "Hashtag" : "as:Hashtag", - "atomUri" : "ostatus:atomUri", - "conversation" : "ostatus:conversation", - "inReplyToAtomUri" : "ostatus:inReplyToAtomUri", - "manuallyApprovesFollowers" : "as:manuallyApprovesFollowers", - "movedTo" : "as:movedTo", - "ostatus" : "http://ostatus.org#", - "sensitive" : "as:sensitive", - "toot" : "http://joinmastodon.org/ns#" - } - ], - "atomUri" : "http://mastodon.example.org/users/admin/statuses/99541947525187367", - "attachment" : [ - { - "mediaType" : "image/jpeg", - "name" : null, - "type" : "Document", - "url" : "http://mastodon.example.org/system/media_attachments/files/000/000/002/original/334ce029e7bfb920.jpg" - } - ], - "attributedTo" : "http://mastodon.example.org/users/admin", - "cc" : [ - "http://mastodon.example.org/users/admin/followers" - ], - "content" : "

yeah.

", - "conversation" : "tag:mastodon.example.org,2018-02-17:objectId=59:objectType=Conversation", - "id" : "http://mastodon.example.org/users/admin/statuses/99541947525187367", - "inReplyTo" : null, - "inReplyToAtomUri" : null, - "sensitive" : false, - "summary" : null, - "tag" : [], - "to" : [ - "https://www.w3.org/ns/activitystreams#Public" - ], - "type" : "Note", - "url" : "http://mastodon.example.org/@admin/99541947525187367" -} diff --git a/test/pleroma/web/activity_pub/object_validators/article_note_page_validator_test.exs b/test/pleroma/web/activity_pub/object_validators/article_note_page_validator_test.exs index 0ddc3c76d..5b95ebc51 100644 --- a/test/pleroma/web/activity_pub/object_validators/article_note_page_validator_test.exs +++ b/test/pleroma/web/activity_pub/object_validators/article_note_page_validator_test.exs @@ -28,7 +28,6 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.ArticleNotePageValidatorTest "to" => [user.follower_address], "cc" => [], "content" => "Hellow this is content.", - "published" => "2021-01-01T00:00:00Z", "context" => "xxx", "summary" => "a post" } @@ -66,12 +65,6 @@ test "a note with a remote replies collection should validate", _ do ArticleNotePageValidator.cast_and_validate(note) end - test "a note without a published field should not validate", _ do - insert(:user, %{ap_id: "http://mastodon.example.org/users/admin"}) - note = Jason.decode!(File.read!("test/fixtures/mastodon/note-without-published.json")) - %{valid?: false} = ArticleNotePageValidator.cast_and_validate(note) - end - test "a note with an attachment should work", _ do insert(:user, %{ap_id: "https://owncast.localhost.localdomain/federation/user/streamer"}) From c33f0065f2c7c812c7602c7d1c9a5a46dfa1bd9c Mon Sep 17 00:00:00 2001 From: Weblate Date: Wed, 7 Dec 2022 15:39:41 +0000 Subject: [PATCH 114/631] Translated using Weblate (Indonesian) Currently translated at 21.6% (18 of 83 strings) Added translation using Weblate (Indonesian) Co-authored-by: Weblate Co-authored-by: t1 Translate-URL: http://translate.akkoma.dev/projects/akkoma/akkoma-backend-static-pages/id/ Translation: Pleroma fe/Akkoma Backend (Static pages) --- priv/gettext/id/LC_MESSAGES/static_pages.po | 526 ++++++++++++++++++++ 1 file changed, 526 insertions(+) create mode 100644 priv/gettext/id/LC_MESSAGES/static_pages.po diff --git a/priv/gettext/id/LC_MESSAGES/static_pages.po b/priv/gettext/id/LC_MESSAGES/static_pages.po new file mode 100644 index 000000000..c6189214d --- /dev/null +++ b/priv/gettext/id/LC_MESSAGES/static_pages.po @@ -0,0 +1,526 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2022-12-07 13:44+0000\n" +"PO-Revision-Date: 2022-12-07 15:39+0000\n" +"Last-Translator: t1 \n" +"Language-Team: Indonesian \n" +"Language: id\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Generator: Weblate 4.14\n" + +## This file is a PO Template file. +## +## "msgid"s here are often extracted from source code. +## Add new translations manually only if they're dynamic +## translations that can't be statically extracted. +## +## Run "mix gettext.extract" to bring this file up to +## date. Leave "msgstr"s empty as changing them here as no +## effect: edit them in PO (.po) files instead. +#: lib/pleroma/web/templates/twitter_api/remote_follow/follow.html.eex:9 +#, elixir-autogen, elixir-format +msgctxt "remote follow authorization button" +msgid "Authorize" +msgstr "" + +#: lib/pleroma/web/templates/twitter_api/remote_follow/follow.html.eex:2 +#, elixir-autogen, elixir-format +msgctxt "remote follow error" +msgid "Error fetching user" +msgstr "Gagal memuat pengguna" + +#: lib/pleroma/web/templates/twitter_api/remote_follow/follow.html.eex:4 +#, elixir-autogen, elixir-format +msgctxt "remote follow header" +msgid "Remote follow" +msgstr "" + +#: lib/pleroma/web/templates/twitter_api/remote_follow/follow_mfa.html.eex:8 +#, elixir-autogen, elixir-format +msgctxt "placeholder text for auth code entry" +msgid "Authentication code" +msgstr "Kode autentikasi" + +#: lib/pleroma/web/templates/twitter_api/remote_follow/follow_login.html.eex:10 +#, elixir-autogen, elixir-format +msgctxt "placeholder text for password entry" +msgid "Password" +msgstr "Kata sandi" + +#: lib/pleroma/web/templates/twitter_api/remote_follow/follow_login.html.eex:8 +#, elixir-autogen, elixir-format +msgctxt "placeholder text for username entry" +msgid "Username" +msgstr "Nama pengguna" + +#: lib/pleroma/web/templates/twitter_api/remote_follow/follow_login.html.eex:13 +#, elixir-autogen, elixir-format +msgctxt "remote follow authorization button for login" +msgid "Authorize" +msgstr "" + +#: lib/pleroma/web/templates/twitter_api/remote_follow/follow_mfa.html.eex:12 +#, elixir-autogen, elixir-format +msgctxt "remote follow authorization button for mfa" +msgid "Authorize" +msgstr "" + +#: lib/pleroma/web/templates/twitter_api/remote_follow/followed.html.eex:2 +#, elixir-autogen, elixir-format +msgctxt "remote follow error" +msgid "Error following account" +msgstr "Gagal mengikuti akun" + +#: lib/pleroma/web/templates/twitter_api/remote_follow/follow_login.html.eex:4 +#, elixir-autogen, elixir-format +msgctxt "remote follow header, need login" +msgid "Log in to follow" +msgstr "Masuk untuk mengikuti" + +#: lib/pleroma/web/templates/twitter_api/remote_follow/follow_mfa.html.eex:4 +#, elixir-autogen, elixir-format +msgctxt "remote follow mfa header" +msgid "Two-factor authentication" +msgstr "Autentikasi dua faktor" + +#: lib/pleroma/web/templates/twitter_api/remote_follow/followed.html.eex:4 +#, elixir-autogen, elixir-format +msgctxt "remote follow success" +msgid "Account followed!" +msgstr "Akun diikuti!" + +#: lib/pleroma/web/templates/twitter_api/util/subscribe.html.eex:7 +#, elixir-autogen, elixir-format +msgctxt "placeholder text for account id" +msgid "Your account ID, e.g. lain@quitter.se" +msgstr "ID akunmu, cth. lain@quitter.se" + +#: lib/pleroma/web/templates/twitter_api/util/subscribe.html.eex:8 +#, elixir-autogen, elixir-format +msgctxt "remote follow authorization button for following with a remote account" +msgid "Follow" +msgstr "Ikuti" + +#: lib/pleroma/web/templates/twitter_api/util/subscribe.html.eex:2 +#, elixir-autogen, elixir-format +msgctxt "remote follow error" +msgid "Error: %{error}" +msgstr "Kesalahan: %{error}" + +#: lib/pleroma/web/templates/twitter_api/util/subscribe.html.eex:4 +#, elixir-autogen, elixir-format +msgctxt "remote follow header" +msgid "Remotely follow %{nickname}" +msgstr "" + +#: lib/pleroma/web/templates/twitter_api/password/reset.html.eex:12 +#, elixir-autogen, elixir-format +msgctxt "password reset button" +msgid "Reset" +msgstr "" + +#: lib/pleroma/web/templates/twitter_api/password/reset_failed.html.eex:4 +#, elixir-autogen, elixir-format +msgctxt "password reset failed homepage link" +msgid "Homepage" +msgstr "Beranda" + +#: lib/pleroma/web/templates/twitter_api/password/reset_failed.html.eex:1 +#, elixir-autogen, elixir-format +msgctxt "password reset failed message" +msgid "Password reset failed" +msgstr "Gagal mengatur ulang kata sandi" + +#: lib/pleroma/web/templates/twitter_api/password/reset.html.eex:8 +#, elixir-autogen, elixir-format +msgctxt "password reset form confirm password prompt" +msgid "Confirmation" +msgstr "Konfirmasi" + +#: lib/pleroma/web/templates/twitter_api/password/reset.html.eex:4 +#, elixir-autogen, elixir-format +msgctxt "password reset form password prompt" +msgid "Password" +msgstr "Kata sandi" + +#: lib/pleroma/web/templates/twitter_api/password/invalid_token.html.eex:1 +#, elixir-autogen, elixir-format +msgctxt "password reset invalid token message" +msgid "Invalid Token" +msgstr "Token Tidak Sah" + +#: lib/pleroma/web/templates/twitter_api/password/reset_success.html.eex:2 +#, elixir-autogen, elixir-format +msgctxt "password reset successful homepage link" +msgid "Homepage" +msgstr "Beranda" + +#: lib/pleroma/web/templates/twitter_api/password/reset_success.html.eex:1 +#, elixir-autogen, elixir-format +msgctxt "password reset successful message" +msgid "Password changed!" +msgstr "Kata sandi diubah!" + +#: lib/pleroma/web/templates/feed/feed/tag.atom.eex:15 +#: lib/pleroma/web/templates/feed/feed/tag.rss.eex:7 +#, elixir-autogen, elixir-format +msgctxt "tag feed description" +msgid "These are public toots tagged with #%{tag}. You can interact with them if you have an account anywhere in the fediverse." +msgstr "" + +#: lib/pleroma/web/templates/o_auth/o_auth/oob_token_exists.html.eex:1 +#, elixir-autogen, elixir-format +msgctxt "oauth authorization exists page title" +msgid "Authorization exists" +msgstr "" + +#: lib/pleroma/web/templates/o_auth/o_auth/show.html.eex:32 +#, elixir-autogen, elixir-format +msgctxt "oauth authorize approve button" +msgid "Approve" +msgstr "" + +#: lib/pleroma/web/templates/o_auth/o_auth/show.html.eex:30 +#, elixir-autogen, elixir-format +msgctxt "oauth authorize cancel button" +msgid "Cancel" +msgstr "" + +#: lib/pleroma/web/templates/o_auth/o_auth/show.html.eex:23 +#, elixir-autogen, elixir-format +msgctxt "oauth authorize message" +msgid "Application %{client_name} is requesting access to your account." +msgstr "" + +#: lib/pleroma/web/templates/o_auth/o_auth/oob_authorization_created.html.eex:1 +#, elixir-autogen, elixir-format +msgctxt "oauth authorized page title" +msgid "Successfully authorized" +msgstr "" + +#: lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex:1 +#, elixir-autogen, elixir-format +msgctxt "oauth external provider page title" +msgid "Sign in with external provider" +msgstr "" + +#: lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex:13 +#, elixir-autogen, elixir-format +msgctxt "oauth external provider sign in button" +msgid "Sign in with %{strategy}" +msgstr "" + +#: lib/pleroma/web/templates/o_auth/o_auth/show.html.eex:54 +#, elixir-autogen, elixir-format +msgctxt "oauth login button" +msgid "Log In" +msgstr "" + +#: lib/pleroma/web/templates/o_auth/o_auth/show.html.eex:51 +#, elixir-autogen, elixir-format +msgctxt "oauth login password prompt" +msgid "Password" +msgstr "" + +#: lib/pleroma/web/templates/o_auth/o_auth/show.html.eex:47 +#, elixir-autogen, elixir-format +msgctxt "oauth login username prompt" +msgid "Username" +msgstr "" + +#: lib/pleroma/web/templates/o_auth/o_auth/show.html.eex:39 +#, elixir-autogen, elixir-format +msgctxt "oauth register nickname prompt" +msgid "Pleroma Handle" +msgstr "" + +#: lib/pleroma/web/templates/o_auth/o_auth/show.html.eex:37 +#, elixir-autogen, elixir-format +msgctxt "oauth register nickname unchangeable warning" +msgid "Choose carefully! You won't be able to change this later. You will be able to change your display name, though." +msgstr "" + +#: lib/pleroma/web/templates/o_auth/o_auth/register.html.eex:18 +#, elixir-autogen, elixir-format +msgctxt "oauth register page email prompt" +msgid "Email" +msgstr "" + +#: lib/pleroma/web/templates/o_auth/o_auth/register.html.eex:10 +#, elixir-autogen, elixir-format +msgctxt "oauth register page fill form prompt" +msgid "If you'd like to register a new account, please provide the details below." +msgstr "" + +#: lib/pleroma/web/templates/o_auth/o_auth/register.html.eex:35 +#, elixir-autogen, elixir-format +msgctxt "oauth register page login button" +msgid "Proceed as existing user" +msgstr "" + +#: lib/pleroma/web/templates/o_auth/o_auth/register.html.eex:31 +#, elixir-autogen, elixir-format +msgctxt "oauth register page login password prompt" +msgid "Password" +msgstr "" + +#: lib/pleroma/web/templates/o_auth/o_auth/register.html.eex:24 +#, elixir-autogen, elixir-format +msgctxt "oauth register page login prompt" +msgid "Alternatively, sign in to connect to existing account." +msgstr "" + +#: lib/pleroma/web/templates/o_auth/o_auth/register.html.eex:27 +#, elixir-autogen, elixir-format +msgctxt "oauth register page login username prompt" +msgid "Name or email" +msgstr "" + +#: lib/pleroma/web/templates/o_auth/o_auth/register.html.eex:14 +#, elixir-autogen, elixir-format +msgctxt "oauth register page nickname prompt" +msgid "Nickname" +msgstr "" + +#: lib/pleroma/web/templates/o_auth/o_auth/register.html.eex:22 +#, elixir-autogen, elixir-format +msgctxt "oauth register page register button" +msgid "Proceed as new user" +msgstr "" + +#: lib/pleroma/web/templates/o_auth/o_auth/register.html.eex:8 +#, elixir-autogen, elixir-format +msgctxt "oauth register page title" +msgid "Registration Details" +msgstr "" + +#: lib/pleroma/web/templates/o_auth/o_auth/show.html.eex:36 +#, elixir-autogen, elixir-format +msgctxt "oauth register page title" +msgid "This is the first time you visit! Please enter your Pleroma handle." +msgstr "" + +#: lib/pleroma/web/templates/o_auth/o_auth/_scopes.html.eex:2 +#, elixir-autogen, elixir-format +msgctxt "oauth scopes message" +msgid "The following permissions will be granted" +msgstr "" + +#: lib/pleroma/web/templates/o_auth/o_auth/oob_authorization_created.html.eex:2 +#: lib/pleroma/web/templates/o_auth/o_auth/oob_token_exists.html.eex:2 +#, elixir-autogen, elixir-format +msgctxt "oauth token code message" +msgid "Token code is
%{token}" +msgstr "" + +#: lib/pleroma/web/templates/o_auth/mfa/totp.html.eex:12 +#, elixir-autogen, elixir-format +msgctxt "mfa auth code prompt" +msgid "Authentication code" +msgstr "" + +#: lib/pleroma/web/templates/o_auth/mfa/totp.html.eex:8 +#, elixir-autogen, elixir-format +msgctxt "mfa auth page title" +msgid "Two-factor authentication" +msgstr "" + +#: lib/pleroma/web/templates/o_auth/mfa/totp.html.eex:23 +#, elixir-autogen, elixir-format +msgctxt "mfa auth page use recovery code link" +msgid "Enter a two-factor recovery code" +msgstr "" + +#: lib/pleroma/web/templates/o_auth/mfa/totp.html.eex:20 +#, elixir-autogen, elixir-format +msgctxt "mfa auth verify code button" +msgid "Verify" +msgstr "" + +#: lib/pleroma/web/templates/o_auth/mfa/recovery.html.eex:8 +#, elixir-autogen, elixir-format +msgctxt "mfa recover page title" +msgid "Two-factor recovery" +msgstr "" + +#: lib/pleroma/web/templates/o_auth/mfa/recovery.html.eex:12 +#, elixir-autogen, elixir-format +msgctxt "mfa recover recovery code prompt" +msgid "Recovery code" +msgstr "" + +#: lib/pleroma/web/templates/o_auth/mfa/recovery.html.eex:23 +#, elixir-autogen, elixir-format +msgctxt "mfa recover use 2fa code link" +msgid "Enter a two-factor code" +msgstr "" + +#: lib/pleroma/web/templates/o_auth/mfa/recovery.html.eex:20 +#, elixir-autogen, elixir-format +msgctxt "mfa recover verify recovery code button" +msgid "Verify" +msgstr "" + +#: lib/pleroma/web/templates/static_fe/static_fe/profile.html.eex:8 +#, elixir-autogen, elixir-format +msgctxt "static fe profile page remote follow button" +msgid "Remote follow" +msgstr "" + +#: lib/pleroma/web/templates/email/digest.html.eex:163 +#, elixir-autogen, elixir-format +msgctxt "digest email header line" +msgid "Hey %{nickname}, here is what you've missed!" +msgstr "" + +#: lib/pleroma/web/templates/email/digest.html.eex:544 +#, elixir-autogen, elixir-format +msgctxt "digest email receiver address" +msgid "The email address you are subscribed as is %{email}. " +msgstr "" + +#: lib/pleroma/web/templates/email/digest.html.eex:538 +#, elixir-autogen, elixir-format +msgctxt "digest email sending reason" +msgid "You have received this email because you have signed up to receive digest emails from %{instance} Pleroma instance." +msgstr "" + +#: lib/pleroma/web/templates/email/digest.html.eex:547 +#, elixir-autogen, elixir-format +msgctxt "digest email unsubscribe action" +msgid "To unsubscribe, please go %{here}." +msgstr "" + +#: lib/pleroma/web/templates/email/digest.html.eex:547 +#, elixir-autogen, elixir-format +msgctxt "digest email unsubscribe action link text" +msgid "here" +msgstr "" + +#: lib/pleroma/web/templates/mailer/subscription/unsubscribe_failure.html.eex:1 +#, elixir-autogen, elixir-format +msgctxt "mailer unsubscribe failed message" +msgid "UNSUBSCRIBE FAILURE" +msgstr "" + +#: lib/pleroma/web/templates/mailer/subscription/unsubscribe_success.html.eex:1 +#, elixir-autogen, elixir-format +msgctxt "mailer unsubscribe successful message" +msgid "UNSUBSCRIBE SUCCESSFUL" +msgstr "" + +#: lib/pleroma/web/templates/email/digest.html.eex:385 +#, elixir-format +msgctxt "new followers count header" +msgid "%{count} New Follower" +msgid_plural "%{count} New Followers" +msgstr[0] "" +msgstr[1] "" + +#: lib/pleroma/emails/user_email.ex:356 +#, elixir-autogen, elixir-format +msgctxt "account archive email body - self-requested" +msgid "

You requested a full backup of your Pleroma account. It's ready for download:

\n

%{download_url}

\n" +msgstr "" + +#: lib/pleroma/emails/user_email.ex:384 +#, elixir-autogen, elixir-format +msgctxt "account archive email subject" +msgid "Your account archive is ready" +msgstr "" + +#: lib/pleroma/emails/user_email.ex:188 +#, elixir-autogen, elixir-format +msgctxt "approval pending email body" +msgid "

Awaiting Approval

\n

Your account at %{instance_name} is being reviewed by staff. You will receive another email once your account is approved.

\n" +msgstr "" + +#: lib/pleroma/emails/user_email.ex:202 +#, elixir-autogen, elixir-format +msgctxt "approval pending email subject" +msgid "Your account is awaiting approval" +msgstr "" + +#: lib/pleroma/emails/user_email.ex:158 +#, elixir-autogen, elixir-format +msgctxt "confirmation email body" +msgid "

Thank you for registering on %{instance_name}

\n

Email confirmation is required to activate the account.

\n

Please click the following link to activate your account.

\n" +msgstr "" + +#: lib/pleroma/emails/user_email.ex:174 +#, elixir-autogen, elixir-format +msgctxt "confirmation email subject" +msgid "%{instance_name} account confirmation" +msgstr "" + +#: lib/pleroma/emails/user_email.ex:310 +#, elixir-autogen, elixir-format +msgctxt "digest email subject" +msgid "Your digest from %{instance_name}" +msgstr "" + +#: lib/pleroma/emails/user_email.ex:81 +#, elixir-autogen, elixir-format +msgctxt "password reset email body" +msgid "

Reset your password at %{instance_name}

\n

Someone has requested password change for your account at %{instance_name}.

\n

If it was you, visit the following link to proceed: reset password.

\n

If it was someone else, nothing to worry about: your data is secure and your password has not been changed.

\n" +msgstr "" + +#: lib/pleroma/emails/user_email.ex:98 +#, elixir-autogen, elixir-format +msgctxt "password reset email subject" +msgid "Password reset" +msgstr "" + +#: lib/pleroma/emails/user_email.ex:215 +#, elixir-autogen, elixir-format +msgctxt "successful registration email body" +msgid "

Hello @%{nickname},

\n

Your account at %{instance_name} has been registered successfully.

\n

No further action is required to activate your account.

\n" +msgstr "" + +#: lib/pleroma/emails/user_email.ex:231 +#, elixir-autogen, elixir-format +msgctxt "successful registration email subject" +msgid "Account registered on %{instance_name}" +msgstr "" + +#: lib/pleroma/emails/user_email.ex:119 +#, elixir-autogen, elixir-format +msgctxt "user invitation email body" +msgid "

You are invited to %{instance_name}

\n

%{inviter_name} invites you to join %{instance_name}, an instance of Pleroma federated social networking platform.

\n

Click the following link to register: accept invitation.

\n" +msgstr "" + +#: lib/pleroma/emails/user_email.ex:136 +#, elixir-autogen, elixir-format +msgctxt "user invitation email subject" +msgid "Invitation to %{instance_name}" +msgstr "" + +#: lib/pleroma/emails/user_email.ex:53 +#, elixir-autogen, elixir-format +msgctxt "welcome email html body" +msgid "Welcome to %{instance_name}!" +msgstr "" + +#: lib/pleroma/emails/user_email.ex:41 +#, elixir-autogen, elixir-format +msgctxt "welcome email subject" +msgid "Welcome to %{instance_name}!" +msgstr "" + +#: lib/pleroma/emails/user_email.ex:65 +#, elixir-autogen, elixir-format +msgctxt "welcome email text body" +msgid "Welcome to %{instance_name}!" +msgstr "" + +#: lib/pleroma/emails/user_email.ex:368 +#, elixir-autogen, elixir-format +msgctxt "account archive email body - admin requested" +msgid "

Admin @%{admin_nickname} requested a full backup of your Pleroma account. It's ready for download:

\n

%{download_url}

\n" +msgstr "" From 021b0864a544704c901c84c2d19eb6d22512b5a1 Mon Sep 17 00:00:00 2001 From: Weblate Date: Wed, 7 Dec 2022 15:39:41 +0000 Subject: [PATCH 115/631] Update translation files Updated by "Squash Git commits" hook in Weblate. Translation: Pleroma fe/Akkoma Backend (Static pages) Translate-URL: http://translate.akkoma.dev/projects/akkoma/akkoma-backend-static-pages/ --- .../ca/LC_MESSAGES/config_descriptions.po | 4 +- .../es/LC_MESSAGES/config_descriptions.po | 3560 ++++++++++------- .../nl/LC_MESSAGES/config_descriptions.po | 3560 ++++++++++------- 3 files changed, 4280 insertions(+), 2844 deletions(-) diff --git a/priv/gettext/ca/LC_MESSAGES/config_descriptions.po b/priv/gettext/ca/LC_MESSAGES/config_descriptions.po index ad2177a9b..958c1ee44 100644 --- a/priv/gettext/ca/LC_MESSAGES/config_descriptions.po +++ b/priv/gettext/ca/LC_MESSAGES/config_descriptions.po @@ -5,8 +5,8 @@ msgstr "" "POT-Creation-Date: 2022-07-28 09:35+0000\n" "PO-Revision-Date: 2022-08-08 15:48+0000\n" "Last-Translator: sola \n" -"Language-Team: Catalan \n" +"Language-Team: Catalan \n" "Language: ca\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" diff --git a/priv/gettext/es/LC_MESSAGES/config_descriptions.po b/priv/gettext/es/LC_MESSAGES/config_descriptions.po index f3602ce46..d4720fc46 100644 --- a/priv/gettext/es/LC_MESSAGES/config_descriptions.po +++ b/priv/gettext/es/LC_MESSAGES/config_descriptions.po @@ -5,8 +5,8 @@ msgstr "" "POT-Creation-Date: 2022-08-06 22:23+0000\n" "PO-Revision-Date: 2022-08-06 22:24+0000\n" "Last-Translator: Anonymous \n" -"Language-Team: Spanish \n" +"Language-Team: Spanish \n" "Language: es\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -14,40 +14,47 @@ msgstr "" "Plural-Forms: nplurals=2; plural=n != 1;\n" "X-Generator: Weblate 4.13.1\n" -## This file is a PO Template file. -## -## "msgid"s here are often extracted from source code. -## Add new translations manually only if they're dynamic -## translations that can't be statically extracted. -## -## Run "mix gettext.extract" to bring this file up to -## date. Leave "msgstr"s empty as changing them here has no -## effect: edit them in PO (.po) files instead. +# # This file is a PO Template file. +# # +# # "msgid"s here are often extracted from source code. +# # Add new translations manually only if they're dynamic +# # translations that can't be statically extracted. +# # +# # Run "mix gettext.extract" to bring this file up to +# # date. Leave "msgstr"s empty as changing them here has no +# # effect: edit them in PO (.po) files instead. #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :esshd" -msgid "Before enabling this you must add :esshd to mix.exs as one of the extra_applications and generate host keys in your priv dir with ssh-keygen -m PEM -N \"\" -b 2048 -t rsa -f ssh_host_rsa_key" +msgid "" +"Before enabling this you must add :esshd to mix.exs as one of the " +"extra_applications and generate host keys in your priv dir with ssh-keygen -" +"m PEM -N \"\" -b 2048 -t rsa -f ssh_host_rsa_key" msgstr "" "Before enabling this you must add :esshd to mix.exs as one of the " "extra_applications and generate host keys in your priv dir with ssh-keygen -" "m PEM -N \"\" -b 2048 -t rsa -f ssh_host_rsa_key" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :logger" msgid "Logger-related settings" msgstr "Logger-related settings" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :mime" msgid "Mime Types settings" msgstr "Mime Types settings" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma" -msgid "Allows setting a token that can be used to authenticate requests with admin privileges without a normal user account token. Append the `admin_token` parameter to requests to utilize it. (Please reconsider using HTTP Basic Auth or OAuth-based authentication if possible)" +msgid "" +"Allows setting a token that can be used to authenticate requests with admin " +"privileges without a normal user account token. Append the `admin_token` " +"parameter to requests to utilize it. (Please reconsider using HTTP Basic " +"Auth or OAuth-based authentication if possible)" msgstr "" "Allows setting a token that can be used to authenticate requests with admin " "privileges without a normal user account token. Append the `admin_token` " @@ -55,119 +62,125 @@ msgstr "" "Auth or OAuth-based authentication if possible)" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma" msgid "Authenticator" msgstr "Authenticator" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :quack" msgid "Quack-related settings" msgstr "Quack-related settings" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :cors_plug" msgid "CORS plug config" msgstr "CORS plug config" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :esshd" msgid "ESSHD" msgstr "ESSHD" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :logger" msgid "Logger" msgstr "Logger" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :mime" msgid "Mime Types" msgstr "Mime Types" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma" msgid "Pleroma Admin Token" msgstr "Pleroma Admin Token" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma" msgid "Pleroma Authenticator" msgstr "Pleroma Authenticator" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :quack" msgid "Quack Logger" msgstr "Quack Logger" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :logger-:console" msgid "Console logger settings" msgstr "Console logger settings" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :logger-:ex_syslogger" msgid "ExSyslogger-related settings" msgstr "ExSyslogger-related settings" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:activitypub" msgid "ActivityPub-related settings" msgstr "ActivityPub-related settings" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:assets" -msgid "This section configures assets to be used with various frontends. Currently the only option relates to mascots on the mastodon frontend" +msgid "" +"This section configures assets to be used with various frontends. Currently " +"the only option relates to mascots on the mastodon frontend" msgstr "" "This section configures assets to be used with various frontends. Currently " "the only option relates to mascots on the mastodon frontend" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:auth" msgid "Authentication / authorization settings" msgstr "Authentication / authorization settings" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:connections_pool" msgid "Advanced settings for `Gun` connections pool" msgstr "Advanced settings for `Gun` connections pool" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:email_notifications" msgid "Email notifications settings" msgstr "Email notifications settings" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:features" msgid "Customizable features" msgstr "Customizable features" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:feed" msgid "Configure feed rendering" msgstr "Configure feed rendering" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:frontend_configurations" -msgid "This form can be used to configure a keyword list that keeps the configuration data for any kind of frontend. By default, settings for pleroma_fe are configured. If you want to add your own configuration your settings all fields must be complete." +msgid "" +"This form can be used to configure a keyword list that keeps the " +"configuration data for any kind of frontend. By default, settings for " +"pleroma_fe are configured. If you want to add your own configuration your " +"settings all fields must be complete." msgstr "" "This form can be used to configure a keyword list that keeps the " "configuration data for any kind of frontend. By default, settings for " @@ -175,51 +188,56 @@ msgstr "" "settings all fields must be complete." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:frontends" msgid "Installed frontends management" msgstr "Installed frontends management" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:gopher" msgid "Gopher settings" msgstr "Gopher settings" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:hackney_pools" msgid "Advanced settings for `Hackney` connections pools" msgstr "Advanced settings for `Hackney` connections pools" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:http" msgid "HTTP settings" msgstr "HTTP settings" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:http_security" msgid "HTTP security settings" msgstr "HTTP security settings" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance" msgid "Instance-related settings" msgstr "Instance-related settings" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instances_favicons" msgid "Control favicons for instances" msgstr "Control favicons for instances" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:ldap" -msgid "Use LDAP for user authentication. When a user logs in to the Pleroma instance, the name and password will be verified by trying to authenticate (bind) to a LDAP server. If a user exists in the LDAP directory but there is no account with the same name yet on the Pleroma instance then a new Pleroma account will be created with the same name as the LDAP user name." +msgid "" +"Use LDAP for user authentication. When a user logs in to the Pleroma " +"instance, the name and password will be verified by trying to authenticate " +"(bind) to a LDAP server. If a user exists in the LDAP directory but there is " +"no account with the same name yet on the Pleroma instance then a new Pleroma " +"account will be created with the same name as the LDAP user name." msgstr "" "Use LDAP for user authentication. When a user logs in to the Pleroma " "instance, the name and password will be verified by trying to authenticate " @@ -228,340 +246,378 @@ msgstr "" "account will be created with the same name as the LDAP user name." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:majic_pool" msgid "Majic/libmagic configuration" msgstr "Majic/libmagic configuration" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:manifest" -msgid "This section describe PWA manifest instance-specific values. Currently this option relate only for MastoFE." +msgid "" +"This section describe PWA manifest instance-specific values. Currently this " +"option relate only for MastoFE." msgstr "" "This section describe PWA manifest instance-specific values. Currently this " "option relate only for MastoFE." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:media_preview_proxy" msgid "Media preview proxy" msgstr "Media preview proxy" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:media_proxy" msgid "Media proxy" msgstr "Media proxy" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:modules" msgid "Custom Runtime Modules" msgstr "Custom Runtime Modules" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf" msgid "General MRF settings" msgstr "General MRF settings" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_activity_expiration" msgid "Adds automatic expiration to all local activities" msgstr "Adds automatic expiration to all local activities" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_follow_bot" msgid "Automatically follows newly discovered accounts." msgstr "Automatically follows newly discovered accounts." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_hashtag" -msgid "Reject, TWKN-remove or Set-Sensitive messsages with specific hashtags (without the leading #)\n\nNote: This MRF Policy is always enabled, if you want to disable it you have to set empty lists.\n" +msgid "" +"Reject, TWKN-remove or Set-Sensitive messsages with specific hashtags " +"(without the leading #)\n" +"\n" +"Note: This MRF Policy is always enabled, if you want to disable it you have " +"to set empty lists.\n" msgstr "" -"Reject, TWKN-remove or Set-Sensitive messsages with specific hashtags (" -"without the leading #)\n" +"Reject, TWKN-remove or Set-Sensitive messsages with specific hashtags " +"(without the leading #)\n" "\n" "Note: This MRF Policy is always enabled, if you want to disable it you have " "to set empty lists.\n" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_hellthread" msgid "Block messages with excessive user mentions" msgstr "Block messages with excessive user mentions" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_keyword" -msgid "Reject or Word-Replace messages matching a keyword or [Regex](https://hexdocs.pm/elixir/Regex.html)." +msgid "" +"Reject or Word-Replace messages matching a keyword or [Regex](https://" +"hexdocs.pm/elixir/Regex.html)." msgstr "" -"Reject or Word-Replace messages matching a keyword or [Regex](https://hexdocs" -".pm/elixir/Regex.html)." +"Reject or Word-Replace messages matching a keyword or [Regex](https://" +"hexdocs.pm/elixir/Regex.html)." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_mention" msgid "Block messages which mention a specific user" msgstr "Block messages which mention a specific user" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_normalize_markup" msgid "MRF NormalizeMarkup settings. Scrub configured hypertext markup." msgstr "MRF NormalizeMarkup settings. Scrub configured hypertext markup." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_object_age" -msgid "Rejects or delists posts based on their timestamp deviance from your server's clock." +msgid "" +"Rejects or delists posts based on their timestamp deviance from your " +"server's clock." msgstr "" "Rejects or delists posts based on their timestamp deviance from your " "server's clock." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_rejectnonpublic" msgid "RejectNonPublic drops posts with non-public visibility settings." msgstr "RejectNonPublic drops posts with non-public visibility settings." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_simple" msgid "Simple ingress policies" msgstr "Simple ingress policies" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_steal_emoji" msgid "Steals emojis from selected instances when it sees them." msgstr "Steals emojis from selected instances when it sees them." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_subchain" -msgid "This policy processes messages through an alternate pipeline when a given message matches certain criteria. All criteria are configured as a map of regular expressions to lists of policy modules." +msgid "" +"This policy processes messages through an alternate pipeline when a given " +"message matches certain criteria. All criteria are configured as a map of " +"regular expressions to lists of policy modules." msgstr "" "This policy processes messages through an alternate pipeline when a given " "message matches certain criteria. All criteria are configured as a map of " "regular expressions to lists of policy modules." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_vocabulary" msgid "Filter messages which belong to certain activity vocabularies" msgstr "Filter messages which belong to certain activity vocabularies" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:oauth2" msgid "Configure OAuth 2 provider capabilities" msgstr "Configure OAuth 2 provider capabilities" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:pools" msgid "Advanced settings for `Gun` workers pools" msgstr "Advanced settings for `Gun` workers pools" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:populate_hashtags_table" msgid "`populate_hashtags_table` background migration settings" msgstr "`populate_hashtags_table` background migration settings" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:rate_limit" -msgid "Rate limit settings. This is an advanced feature enabled only for :authentication by default." +msgid "" +"Rate limit settings. This is an advanced feature enabled only for :" +"authentication by default." msgstr "" "Rate limit settings. This is an advanced feature enabled only for :" "authentication by default." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:restrict_unauthenticated" -msgid "Disallow viewing timelines, user profiles and statuses for unauthenticated users." +msgid "" +"Disallow viewing timelines, user profiles and statuses for unauthenticated " +"users." msgstr "" "Disallow viewing timelines, user profiles and statuses for unauthenticated " "users." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:rich_media" -msgid "If enabled the instance will parse metadata from attached links to generate link previews" +msgid "" +"If enabled the instance will parse metadata from attached links to generate " +"link previews" msgstr "" "If enabled the instance will parse metadata from attached links to generate " "link previews" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:shout" msgid "Pleroma shout settings" msgstr "Pleroma shout settings" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:static_fe" -msgid "Render profiles and posts using server-generated HTML that is viewable without using JavaScript" +msgid "" +"Render profiles and posts using server-generated HTML that is viewable " +"without using JavaScript" msgstr "" "Render profiles and posts using server-generated HTML that is viewable " "without using JavaScript" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:streamer" msgid "Settings for notifications streamer" msgstr "Settings for notifications streamer" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:uri_schemes" msgid "URI schemes related settings" msgstr "URI schemes related settings" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:web_cache_ttl" -msgid "The expiration time for the web responses cache. Values should be in milliseconds or `nil` to disable expiration." +msgid "" +"The expiration time for the web responses cache. Values should be in " +"milliseconds or `nil` to disable expiration." msgstr "" "The expiration time for the web responses cache. Values should be in " "milliseconds or `nil` to disable expiration." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:welcome" msgid "Welcome messages settings" msgstr "Welcome messages settings" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:workers" msgid "Includes custom worker options not interpretable directly by `Oban`" msgstr "Includes custom worker options not interpretable directly by `Oban`" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-ConcurrentLimiter" msgid "Limits configuration for background tasks." msgstr "Limits configuration for background tasks." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Oban" -msgid "[Oban](https://github.com/sorentwo/oban) asynchronous job processor configuration." +msgid "" +"[Oban](https://github.com/sorentwo/oban) asynchronous job processor " +"configuration." msgstr "" "[Oban](https://github.com/sorentwo/oban) asynchronous job processor " "configuration." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Captcha" msgid "Captcha-related settings" msgstr "Captcha-related settings" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Captcha.Kocaptcha" -msgid "Kocaptcha is a very simple captcha service with a single API endpoint, the source code is here: https://github.com/koto-bank/kocaptcha. The default endpoint (https://captcha.kotobank.ch) is hosted by the developer." +msgid "" +"Kocaptcha is a very simple captcha service with a single API endpoint, the " +"source code is here: https://github.com/koto-bank/kocaptcha. The default " +"endpoint (https://captcha.kotobank.ch) is hosted by the developer." msgstr "" "Kocaptcha is a very simple captcha service with a single API endpoint, the " "source code is here: https://github.com/koto-bank/kocaptcha. The default " "endpoint (https://captcha.kotobank.ch) is hosted by the developer." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Emails.Mailer" msgid "Mailer-related settings" msgstr "Mailer-related settings" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Emails.NewUsersDigestEmail" msgid "New users admin email digest" msgstr "New users admin email digest" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Emails.UserEmail" msgid "Email template settings" msgstr "Email template settings" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Formatter" -msgid "Configuration for Pleroma's link formatter which parses mentions, hashtags, and URLs." +msgid "" +"Configuration for Pleroma's link formatter which parses mentions, hashtags, " +"and URLs." msgstr "" "Configuration for Pleroma's link formatter which parses mentions, hashtags, " "and URLs." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.ScheduledActivity" msgid "Scheduled activities settings" msgstr "Scheduled activities settings" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Upload" msgid "Upload general settings" msgstr "Upload general settings" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-Pleroma.Upload.Filter.AnonymizeFilename" +#, fuzzy +msgctxt "" +"config description at :pleroma-Pleroma.Upload.Filter.AnonymizeFilename" msgid "Filter replaces the filename of the upload" msgstr "Filter replaces the filename of the upload" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Upload.Filter.Mogrify" msgid "Uploads mogrify filter settings" msgstr "Uploads mogrify filter settings" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Uploaders.Local" msgid "Local uploader-related settings" msgstr "Local uploader-related settings" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Uploaders.S3" msgid "S3 uploader-related settings" msgstr "S3 uploader-related settings" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.User.Backup" msgid "Account Backup" msgstr "Account Backup" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-Pleroma.Web.MediaProxy.Invalidation.Http" +#, fuzzy +msgctxt "" +"config description at :pleroma-Pleroma.Web.MediaProxy.Invalidation.Http" msgid "HTTP invalidate settings" msgstr "HTTP invalidate settings" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-Pleroma.Web.MediaProxy.Invalidation.Script" +#, fuzzy +msgctxt "" +"config description at :pleroma-Pleroma.Web.MediaProxy.Invalidation.Script" msgid "Invalidation script settings" msgstr "Invalidation script settings" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Web.Metadata" msgid "Metadata-related settings" msgstr "Metadata-related settings" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Web.Plugs.RemoteIp" -msgid "`Pleroma.Web.Plugs.RemoteIp` is a shim to call [`RemoteIp`](https://git.pleroma.social/pleroma/remote_ip) but with runtime configuration.\n**If your instance is not behind at least one reverse proxy, you should not enable this plug.**\n" +msgid "" +"`Pleroma.Web.Plugs.RemoteIp` is a shim to call [`RemoteIp`](https://git." +"pleroma.social/pleroma/remote_ip) but with runtime configuration.\n" +"**If your instance is not behind at least one reverse proxy, you should not " +"enable this plug.**\n" msgstr "" "`Pleroma.Web.Plugs.RemoteIp` is a shim to call [`RemoteIp`](https://git." "pleroma.social/pleroma/remote_ip) but with runtime configuration.\n" @@ -569,676 +625,697 @@ msgstr "" "enable this plug.**\n" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Web.Preload" msgid "Preload-related settings" msgstr "Preload-related settings" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Workers.PurgeExpiredActivity" msgid "Expired activities settings" msgstr "Expired activities settings" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :prometheus-Pleroma.Web.Endpoint.MetricsExporter" +#, fuzzy +msgctxt "" +"config description at :prometheus-Pleroma.Web.Endpoint.MetricsExporter" msgid "Prometheus app metrics endpoint configuration" msgstr "Prometheus app metrics endpoint configuration" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :web_push_encryption-:vapid_details" -msgid "Web Push Notifications configuration. You can use the mix task mix web_push.gen.keypair to generate it." +msgid "" +"Web Push Notifications configuration. You can use the mix task mix web_push." +"gen.keypair to generate it." msgstr "" -"Web Push Notifications configuration. You can use the mix task mix " -"web_push.gen.keypair to generate it." +"Web Push Notifications configuration. You can use the mix task mix web_push." +"gen.keypair to generate it." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :ex_aws-:s3" msgid "S3" msgstr "S3" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :logger-:console" msgid "Console Logger" msgstr "Console Logger" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :logger-:ex_syslogger" msgid "ExSyslogger" msgstr "ExSyslogger" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:activitypub" msgid "ActivityPub" msgstr "ActivityPub" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:assets" msgid "Assets" msgstr "Assets" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:auth" msgid "Auth" msgstr "Auth" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:connections_pool" msgid "Connections pool" msgstr "Connections pool" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:email_notifications" msgid "Email notifications" msgstr "Email notifications" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:emoji" msgid "Emoji" msgstr "Emoji" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:features" msgid "Features" msgstr "Features" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:feed" msgid "Feed" msgstr "Feed" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:frontend_configurations" msgid "Frontend configurations" msgstr "Frontend configurations" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:frontends" msgid "Frontends" msgstr "Frontends" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:gopher" msgid "Gopher" msgstr "Gopher" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:hackney_pools" msgid "Hackney pools" msgstr "Hackney pools" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:http" msgid "HTTP" msgstr "HTTP" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:http_security" msgid "HTTP security" msgstr "HTTP security" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance" msgid "Instance" msgstr "Instance" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instances_favicons" msgid "Instances favicons" msgstr "Instances favicons" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:ldap" msgid "LDAP" msgstr "LDAP" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:majic_pool" msgid "Majic pool" msgstr "Majic pool" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:manifest" msgid "Manifest" msgstr "Manifest" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:markup" msgid "Markup Settings" msgstr "Markup Settings" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:media_preview_proxy" msgid "Media preview proxy" msgstr "Media preview proxy" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:media_proxy" msgid "Media proxy" msgstr "Media proxy" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:modules" msgid "Modules" msgstr "Modules" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf" msgid "MRF" msgstr "MRF" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_activity_expiration" msgid "MRF Activity Expiration Policy" msgstr "MRF Activity Expiration Policy" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_follow_bot" msgid "MRF FollowBot Policy" msgstr "MRF FollowBot Policy" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_hashtag" msgid "MRF Hashtag" msgstr "MRF Hashtag" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_hellthread" msgid "MRF Hellthread" msgstr "MRF Hellthread" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_keyword" msgid "MRF Keyword" msgstr "MRF Keyword" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_mention" msgid "MRF Mention" msgstr "MRF Mention" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_normalize_markup" msgid "MRF Normalize Markup" msgstr "MRF Normalize Markup" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_object_age" msgid "MRF Object Age" msgstr "MRF Object Age" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_rejectnonpublic" msgid "MRF Reject Non Public" msgstr "MRF Reject Non Public" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_simple" msgid "MRF Simple" msgstr "MRF Simple" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_steal_emoji" msgid "MRF Emojis" msgstr "MRF Emojis" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_subchain" msgid "MRF Subchain" msgstr "MRF Subchain" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_vocabulary" msgid "MRF Vocabulary" msgstr "MRF Vocabulary" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:oauth2" msgid "OAuth2" msgstr "OAuth2" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:pools" msgid "Pools" msgstr "Pools" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:populate_hashtags_table" msgid "Populate hashtags table" msgstr "Populate hashtags table" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:rate_limit" msgid "Rate limit" msgstr "Rate limit" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:restrict_unauthenticated" msgid "Restrict Unauthenticated" msgstr "Restrict Unauthenticated" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:rich_media" msgid "Rich media" msgstr "Rich media" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:shout" msgid "Shout" msgstr "Shout" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:static_fe" msgid "Static FE" msgstr "Static FE" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:streamer" msgid "Streamer" msgstr "Streamer" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:uri_schemes" msgid "URI Schemes" msgstr "URI Schemes" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:user" msgid "User" msgstr "User" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:web_cache_ttl" msgid "Web cache TTL" msgstr "Web cache TTL" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:welcome" msgid "Welcome" msgstr "Welcome" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:workers" msgid "Workers" msgstr "Workers" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-ConcurrentLimiter" msgid "ConcurrentLimiter" msgstr "ConcurrentLimiter" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Oban" msgid "Oban" msgstr "Oban" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Captcha" msgid "Pleroma.Captcha" msgstr "Pleroma.Captcha" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Captcha.Kocaptcha" msgid "Pleroma.Captcha.Kocaptcha" msgstr "Pleroma.Captcha.Kocaptcha" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Emails.Mailer" msgid "Pleroma.Emails.Mailer" msgstr "Pleroma.Emails.Mailer" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Emails.NewUsersDigestEmail" msgid "Pleroma.Emails.NewUsersDigestEmail" msgstr "Pleroma.Emails.NewUsersDigestEmail" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Emails.UserEmail" msgid "Pleroma.Emails.UserEmail" msgstr "Pleroma.Emails.UserEmail" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Formatter" msgid "Linkify" msgstr "Linkify" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.ScheduledActivity" msgid "Pleroma.ScheduledActivity" msgstr "Pleroma.ScheduledActivity" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Upload" msgid "Pleroma.Upload" msgstr "Pleroma.Upload" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Upload.Filter.AnonymizeFilename" msgid "Pleroma.Upload.Filter.AnonymizeFilename" msgstr "Pleroma.Upload.Filter.AnonymizeFilename" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Upload.Filter.Mogrify" msgid "Pleroma.Upload.Filter.Mogrify" msgstr "Pleroma.Upload.Filter.Mogrify" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Uploaders.Local" msgid "Pleroma.Uploaders.Local" msgstr "Pleroma.Uploaders.Local" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Uploaders.S3" msgid "Pleroma.Uploaders.S3" msgstr "Pleroma.Uploaders.S3" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.User" msgid "Pleroma.User" msgstr "Pleroma.User" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.User.Backup" msgid "Pleroma.User.Backup" msgstr "Pleroma.User.Backup" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Web.ApiSpec.CastAndValidate" msgid "Pleroma.Web.ApiSpec.CastAndValidate" msgstr "Pleroma.Web.ApiSpec.CastAndValidate" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Web.MediaProxy.Invalidation.Http" msgid "Pleroma.Web.MediaProxy.Invalidation.Http" msgstr "Pleroma.Web.MediaProxy.Invalidation.Http" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Web.MediaProxy.Invalidation.Script" msgid "Pleroma.Web.MediaProxy.Invalidation.Script" msgstr "Pleroma.Web.MediaProxy.Invalidation.Script" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Web.Metadata" msgid "Pleroma.Web.Metadata" msgstr "Pleroma.Web.Metadata" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Web.Plugs.RemoteIp" msgid "Pleroma.Web.Plugs.RemoteIp" msgstr "Pleroma.Web.Plugs.RemoteIp" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Web.Preload" msgid "Pleroma.Web.Preload" msgstr "Pleroma.Web.Preload" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Workers.PurgeExpiredActivity" msgid "Pleroma.Workers.PurgeExpiredActivity" msgstr "Pleroma.Workers.PurgeExpiredActivity" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :prometheus-Pleroma.Web.Endpoint.MetricsExporter" msgid "Pleroma.Web.Endpoint.MetricsExporter" msgstr "Pleroma.Web.Endpoint.MetricsExporter" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :web_push_encryption-:vapid_details" msgid "Vapid Details" msgstr "Vapid Details" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :esshd > :enabled" msgid "Enables SSH" msgstr "Enables SSH" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :esshd > :handler" msgid "Handler module" msgstr "Handler module" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :esshd > :password_authenticator" msgid "Authenticator module" msgstr "Authenticator module" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :esshd > :port" msgid "Port to connect" msgstr "Port to connect" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :esshd > :priv_dir" msgid "Dir with SSH keys" msgstr "Dir with SSH keys" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :ex_aws-:s3 > :access_key_id" msgid "S3 access key ID" msgstr "S3 access key ID" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :ex_aws-:s3 > :host" msgid "S3 host" msgstr "S3 host" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :ex_aws-:s3 > :region" msgid "S3 region (for AWS)" msgstr "S3 region (for AWS)" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :ex_aws-:s3 > :secret_access_key" msgid "Secret access key" msgstr "Secret access key" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :logger > :backends" -msgid "Where logs will be sent, :console - send logs to stdout, { ExSyslogger, :ex_syslogger } - to syslog, Quack.Logger - to Slack." +msgid "" +"Where logs will be sent, :console - send logs to stdout, { ExSyslogger, :" +"ex_syslogger } - to syslog, Quack.Logger - to Slack." msgstr "" "Where logs will be sent, :console - send logs to stdout, { ExSyslogger, :" "ex_syslogger } - to syslog, Quack.Logger - to Slack." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :logger-:console > :format" msgid "Default: \"$date $time [$level] $levelpad$node $metadata $message\"" msgstr "Default: \"$date $time [$level] $levelpad$node $metadata $message\"" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :logger-:console > :level" msgid "Log level" msgstr "Log level" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :logger-:ex_syslogger > :format" msgid "Default: \"$date $time [$level] $levelpad$node $metadata $message\"" msgstr "Default: \"$date $time [$level] $levelpad$node $metadata $message\"" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :logger-:ex_syslogger > :ident" -msgid "A string that's prepended to every message, and is typically set to the app name" +msgid "" +"A string that's prepended to every message, and is typically set to the app " +"name" msgstr "" "A string that's prepended to every message, and is typically set to the app " "name" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :logger-:ex_syslogger > :level" msgid "Log level" msgstr "Log level" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma > :admin_token" msgid "Admin token" msgstr "Admin token" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:activitypub > :blockers_visible" msgid "Whether a user can see someone who has blocked them" msgstr "Whether a user can see someone who has blocked them" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:activitypub > :follow_handshake_timeout" +#, fuzzy +msgctxt "" +"config description at :pleroma-:activitypub > :follow_handshake_timeout" msgid "Following handshake timeout" msgstr "Following handshake timeout" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:activitypub > :note_replies_output_limit" -msgid "The number of Note replies' URIs to be included with outgoing federation (`5` to match Mastodon hardcoded value, `0` to disable the output)" +#, fuzzy +msgctxt "" +"config description at :pleroma-:activitypub > :note_replies_output_limit" +msgid "" +"The number of Note replies' URIs to be included with outgoing federation " +"(`5` to match Mastodon hardcoded value, `0` to disable the output)" msgstr "" -"The number of Note replies' URIs to be included with outgoing federation (`5`" -" to match Mastodon hardcoded value, `0` to disable the output)" +"The number of Note replies' URIs to be included with outgoing federation " +"(`5` to match Mastodon hardcoded value, `0` to disable the output)" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:activitypub > :outgoing_blocks" msgid "Whether to federate blocks to other instances" msgstr "Whether to federate blocks to other instances" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:activitypub > :sign_object_fetches" msgid "Sign object fetches with HTTP signatures" msgstr "Sign object fetches with HTTP signatures" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:activitypub > :unfollow_blocked" msgid "Whether blocks result in people getting unfollowed" msgstr "Whether blocks result in people getting unfollowed" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:assets > :default_mascot" -msgid "This will be used as the default mascot on MastoFE. Default: `:pleroma_fox_tan`" +msgid "" +"This will be used as the default mascot on MastoFE. Default: `:" +"pleroma_fox_tan`" msgstr "" -"This will be used as the default mascot on MastoFE. Default: " -"`:pleroma_fox_tan`" +"This will be used as the default mascot on MastoFE. Default: `:" +"pleroma_fox_tan`" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:assets > :default_user_avatar" msgid "URL of the default user avatar" msgstr "URL of the default user avatar" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:assets > :mascots" -msgid "Keyword of mascots, each element must contain both an URL and a mime_type key" +msgid "" +"Keyword of mascots, each element must contain both an URL and a mime_type key" msgstr "" "Keyword of mascots, each element must contain both an URL and a mime_type key" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:auth > :auth_template" -msgid "Authentication form template. By default it's `show.html` which corresponds to `lib/pleroma/web/templates/o_auth/o_auth/show.html.ee`." +msgid "" +"Authentication form template. By default it's `show.html` which corresponds " +"to `lib/pleroma/web/templates/o_auth/o_auth/show.html.ee`." msgstr "" "Authentication form template. By default it's `show.html` which corresponds " "to `lib/pleroma/web/templates/o_auth/o_auth/show.html.ee`." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:auth > :enforce_oauth_admin_scope_usage" -msgid "OAuth admin scope requirement toggle. If enabled, admin actions explicitly demand admin OAuth scope(s) presence in OAuth token (client app must support admin scopes). If disabled and token doesn't have admin scope(s), `is_admin` user flag grants access to admin-specific actions." +#, fuzzy +msgctxt "" +"config description at :pleroma-:auth > :enforce_oauth_admin_scope_usage" +msgid "" +"OAuth admin scope requirement toggle. If enabled, admin actions explicitly " +"demand admin OAuth scope(s) presence in OAuth token (client app must support " +"admin scopes). If disabled and token doesn't have admin scope(s), `is_admin` " +"user flag grants access to admin-specific actions." msgstr "" "OAuth admin scope requirement toggle. If enabled, admin actions explicitly " "demand admin OAuth scope(s) presence in OAuth token (client app must support " @@ -1246,57 +1323,78 @@ msgstr "" "user flag grants access to admin-specific actions." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:auth > :oauth_consumer_strategies" -msgid "The list of enabled OAuth consumer strategies. By default it's set by OAUTH_CONSUMER_STRATEGIES environment variable. Each entry in this space-delimited string should be of format \"strategy\" or \"strategy:dependency\" (e.g. twitter or keycloak:ueberauth_keycloak_strategy in case dependency is named differently than ueberauth_)." +msgid "" +"The list of enabled OAuth consumer strategies. By default it's set by " +"OAUTH_CONSUMER_STRATEGIES environment variable. Each entry in this space-" +"delimited string should be of format \"strategy\" or \"strategy:dependency" +"\" (e.g. twitter or keycloak:ueberauth_keycloak_strategy in case dependency " +"is named differently than ueberauth_)." msgstr "" "The list of enabled OAuth consumer strategies. By default it's set by " "OAUTH_CONSUMER_STRATEGIES environment variable. Each entry in this space-" -"delimited string should be of format \"strategy\" or \"strategy:dependency\" " -"(e.g. twitter or keycloak:ueberauth_keycloak_strategy in case dependency is " -"named differently than ueberauth_)." +"delimited string should be of format \"strategy\" or \"strategy:dependency" +"\" (e.g. twitter or keycloak:ueberauth_keycloak_strategy in case dependency " +"is named differently than ueberauth_)." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:auth > :oauth_consumer_template" -msgid "OAuth consumer mode authentication form template. By default it's `consumer.html` which corresponds to `lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex`." +msgid "" +"OAuth consumer mode authentication form template. By default it's `consumer." +"html` which corresponds to `lib/pleroma/web/templates/o_auth/o_auth/consumer." +"html.eex`." msgstr "" "OAuth consumer mode authentication form template. By default it's `consumer." "html` which corresponds to `lib/pleroma/web/templates/o_auth/o_auth/consumer." "html.eex`." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:connections_pool > :connect_timeout" msgid "Timeout while `gun` will wait until connection is up. Default: 5000ms." msgstr "Timeout while `gun` will wait until connection is up. Default: 5000ms." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:connections_pool > :connection_acquisition_retries" -msgid "Number of attempts to acquire the connection from the pool if it is overloaded. Default: 5" +#, fuzzy +msgctxt "" +"config description at :pleroma-:connections_pool > :" +"connection_acquisition_retries" +msgid "" +"Number of attempts to acquire the connection from the pool if it is " +"overloaded. Default: 5" msgstr "" "Number of attempts to acquire the connection from the pool if it is " "overloaded. Default: 5" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:connections_pool > :connection_acquisition_wait" -msgid "Timeout to acquire a connection from pool. The total max time is this value multiplied by the number of retries. Default: 250ms." +#, fuzzy +msgctxt "" +"config description at :pleroma-:connections_pool > :" +"connection_acquisition_wait" +msgid "" +"Timeout to acquire a connection from pool. The total max time is this value " +"multiplied by the number of retries. Default: 250ms." msgstr "" "Timeout to acquire a connection from pool. The total max time is this value " "multiplied by the number of retries. Default: 250ms." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:connections_pool > :max_connections" msgid "Maximum number of connections in the pool. Default: 250 connections." msgstr "Maximum number of connections in the pool. Default: 250 connections." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:connections_pool > :reclaim_multiplier" -msgid "Multiplier for the number of idle connection to be reclaimed if the pool is full. For example if the pool maxes out at 250 connections and this setting is set to 0.3, the pool will reclaim at most 75 idle connections if it's overloaded. Default: 0.1" +#, fuzzy +msgctxt "" +"config description at :pleroma-:connections_pool > :reclaim_multiplier" +msgid "" +"Multiplier for the number of idle connection to be reclaimed if the pool is " +"full. For example if the pool maxes out at 250 connections and this setting " +"is set to 0.3, the pool will reclaim at most 75 idle connections if it's " +"overloaded. Default: 0.1" msgstr "" "Multiplier for the number of idle connection to be reclaimed if the pool is " "full. For example if the pool maxes out at 250 connections and this setting " @@ -1304,249 +1402,333 @@ msgstr "" "overloaded. Default: 0.1" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:email_notifications > :digest" -msgid "emails of \"what you've missed\" for users who have been inactive for a while" +msgid "" +"emails of \"what you've missed\" for users who have been inactive for a while" msgstr "" "emails of \"what you've missed\" for users who have been inactive for a while" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:email_notifications > :digest > :active" +#, fuzzy +msgctxt "" +"config description at :pleroma-:email_notifications > :digest > :active" msgid "Globally enable or disable digest emails" msgstr "Globally enable or disable digest emails" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:email_notifications > :digest > :inactivity_threshold" +#, fuzzy +msgctxt "" +"config description at :pleroma-:email_notifications > :digest > :" +"inactivity_threshold" msgid "Minimum user inactivity threshold" msgstr "Minimum user inactivity threshold" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:email_notifications > :digest > :interval" +#, fuzzy +msgctxt "" +"config description at :pleroma-:email_notifications > :digest > :interval" msgid "Minimum interval between digest emails to one user" msgstr "Minimum interval between digest emails to one user" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:email_notifications > :digest > :schedule" -msgid "When to send digest email, in crontab format. \"0 0 0\" is the default, meaning \"once a week at midnight on Sunday morning\"." +#, fuzzy +msgctxt "" +"config description at :pleroma-:email_notifications > :digest > :schedule" +msgid "" +"When to send digest email, in crontab format. \"0 0 0\" is the default, " +"meaning \"once a week at midnight on Sunday morning\"." msgstr "" "When to send digest email, in crontab format. \"0 0 0\" is the default, " "meaning \"once a week at midnight on Sunday morning\"." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:emoji > :default_manifest" -msgid "Location of the JSON-manifest. This manifest contains information about the emoji-packs you can download. Currently only one manifest can be added (no arrays)." +msgid "" +"Location of the JSON-manifest. This manifest contains information about the " +"emoji-packs you can download. Currently only one manifest can be added (no " +"arrays)." msgstr "" "Location of the JSON-manifest. This manifest contains information about the " "emoji-packs you can download. Currently only one manifest can be added (no " "arrays)." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:emoji > :groups" -msgid "Emojis are ordered in groups (tags). This is an array of key-value pairs where the key is the group name and the value is the location or array of locations. * can be used as a wildcard." +msgid "" +"Emojis are ordered in groups (tags). This is an array of key-value pairs " +"where the key is the group name and the value is the location or array of " +"locations. * can be used as a wildcard." msgstr "" "Emojis are ordered in groups (tags). This is an array of key-value pairs " "where the key is the group name and the value is the location or array of " "locations. * can be used as a wildcard." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:emoji > :pack_extensions" -msgid "A list of file extensions for emojis, when no emoji.txt for a pack is present" +msgid "" +"A list of file extensions for emojis, when no emoji.txt for a pack is present" msgstr "" "A list of file extensions for emojis, when no emoji.txt for a pack is present" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:emoji > :shortcode_globs" msgid "Location of custom emoji files. * can be used as a wildcard." msgstr "Location of custom emoji files. * can be used as a wildcard." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:features > :improved_hashtag_timeline" -msgid "Setting to force toggle / force disable improved hashtags timeline. `:enabled` forces hashtags to be fetched from `hashtags` table for hashtags timeline. `:disabled` forces object-embedded hashtags to be used (slower). Keep it `:auto` for automatic behaviour (it is auto-set to `:enabled` [unless overridden] when HashtagsTableMigrator completes)." -msgstr "" -"Setting to force toggle / force disable improved hashtags timeline. " -"`:enabled` forces hashtags to be fetched from `hashtags` table for hashtags " +msgid "" +"Setting to force toggle / force disable improved hashtags timeline. `:" +"enabled` forces hashtags to be fetched from `hashtags` table for hashtags " "timeline. `:disabled` forces object-embedded hashtags to be used (slower). " -"Keep it `:auto` for automatic behaviour (it is auto-set to `:enabled` [" -"unless overridden] when HashtagsTableMigrator completes)." +"Keep it `:auto` for automatic behaviour (it is auto-set to `:enabled` " +"[unless overridden] when HashtagsTableMigrator completes)." +msgstr "" +"Setting to force toggle / force disable improved hashtags timeline. `:" +"enabled` forces hashtags to be fetched from `hashtags` table for hashtags " +"timeline. `:disabled` forces object-embedded hashtags to be used (slower). " +"Keep it `:auto` for automatic behaviour (it is auto-set to `:enabled` " +"[unless overridden] when HashtagsTableMigrator completes)." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:feed > :post_title" msgid "Configure title rendering" msgstr "Configure title rendering" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:feed > :post_title > :max_length" msgid "Maximum number of characters before truncating title" msgstr "Maximum number of characters before truncating title" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:feed > :post_title > :omission" msgid "Replacement which will be used after truncating string" msgstr "Replacement which will be used after truncating string" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:frontend_configurations > :pleroma_fe" msgid "Settings for Pleroma FE" msgstr "Settings for Pleroma FE" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:frontend_configurations > :pleroma_fe > :alwaysShowSubjectInput" +#, fuzzy +msgctxt "" +"config description at :pleroma-:frontend_configurations > :pleroma_fe > :" +"alwaysShowSubjectInput" msgid "When disabled, auto-hide the subject field if it's empty" msgstr "When disabled, auto-hide the subject field if it's empty" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:frontend_configurations > :pleroma_fe > :background" -msgid "URL of the background, unless viewing a user profile with a background that is set" +#, fuzzy +msgctxt "" +"config description at :pleroma-:frontend_configurations > :pleroma_fe > :" +"background" +msgid "" +"URL of the background, unless viewing a user profile with a background that " +"is set" msgstr "" "URL of the background, unless viewing a user profile with a background that " "is set" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:frontend_configurations > :pleroma_fe > :collapseMessageWithSubject" -msgid "When a message has a subject (aka Content Warning), collapse it by default" +#, fuzzy +msgctxt "" +"config description at :pleroma-:frontend_configurations > :pleroma_fe > :" +"collapseMessageWithSubject" +msgid "" +"When a message has a subject (aka Content Warning), collapse it by default" msgstr "" "When a message has a subject (aka Content Warning), collapse it by default" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:frontend_configurations > :pleroma_fe > :greentext" +#, fuzzy +msgctxt "" +"config description at :pleroma-:frontend_configurations > :pleroma_fe > :" +"greentext" msgid "Enables green text on lines prefixed with the > character" msgstr "Enables green text on lines prefixed with the > character" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:frontend_configurations > :pleroma_fe > :hideFilteredStatuses" +#, fuzzy +msgctxt "" +"config description at :pleroma-:frontend_configurations > :pleroma_fe > :" +"hideFilteredStatuses" msgid "Hides filtered statuses from timelines" msgstr "Hides filtered statuses from timelines" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:frontend_configurations > :pleroma_fe > :hideMutedPosts" +#, fuzzy +msgctxt "" +"config description at :pleroma-:frontend_configurations > :pleroma_fe > :" +"hideMutedPosts" msgid "Hides muted statuses from timelines" msgstr "Hides muted statuses from timelines" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:frontend_configurations > :pleroma_fe > :hidePostStats" +#, fuzzy +msgctxt "" +"config description at :pleroma-:frontend_configurations > :pleroma_fe > :" +"hidePostStats" msgid "Hide notices statistics (repeats, favorites, ...)" msgstr "Hide notices statistics (repeats, favorites, ...)" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:frontend_configurations > :pleroma_fe > :hideSitename" +#, fuzzy +msgctxt "" +"config description at :pleroma-:frontend_configurations > :pleroma_fe > :" +"hideSitename" msgid "Hides instance name from PleromaFE banner" msgstr "Hides instance name from PleromaFE banner" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:frontend_configurations > :pleroma_fe > :hideUserStats" -msgid "Hide profile statistics (posts, posts per day, followers, followings, ...)" +#, fuzzy +msgctxt "" +"config description at :pleroma-:frontend_configurations > :pleroma_fe > :" +"hideUserStats" +msgid "" +"Hide profile statistics (posts, posts per day, followers, followings, ...)" msgstr "" "Hide profile statistics (posts, posts per day, followers, followings, ...)" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:frontend_configurations > :pleroma_fe > :logo" +#, fuzzy +msgctxt "" +"config description at :pleroma-:frontend_configurations > :pleroma_fe > :logo" msgid "URL of the logo, defaults to Pleroma's logo" msgstr "URL of the logo, defaults to Pleroma's logo" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:frontend_configurations > :pleroma_fe > :logoMargin" -msgid "Allows you to adjust vertical margins between logo boundary and navbar borders. The idea is that to have logo's image without any extra margins and instead adjust them to your need in layout." +#, fuzzy +msgctxt "" +"config description at :pleroma-:frontend_configurations > :pleroma_fe > :" +"logoMargin" +msgid "" +"Allows you to adjust vertical margins between logo boundary and navbar " +"borders. The idea is that to have logo's image without any extra margins and " +"instead adjust them to your need in layout." msgstr "" "Allows you to adjust vertical margins between logo boundary and navbar " "borders. The idea is that to have logo's image without any extra margins and " "instead adjust them to your need in layout." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:frontend_configurations > :pleroma_fe > :logoMask" -msgid "By default it assumes logo used will be monochrome with alpha channel to be compatible with both light and dark themes. If you want a colorful logo you must disable logoMask." +#, fuzzy +msgctxt "" +"config description at :pleroma-:frontend_configurations > :pleroma_fe > :" +"logoMask" +msgid "" +"By default it assumes logo used will be monochrome with alpha channel to be " +"compatible with both light and dark themes. If you want a colorful logo you " +"must disable logoMask." msgstr "" "By default it assumes logo used will be monochrome with alpha channel to be " "compatible with both light and dark themes. If you want a colorful logo you " "must disable logoMask." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:frontend_configurations > :pleroma_fe > :minimalScopesMode" -msgid "Limit scope selection to Direct, User default, and Scope of post replying to. Also prevents replying to a DM with a public post from PleromaFE." +#, fuzzy +msgctxt "" +"config description at :pleroma-:frontend_configurations > :pleroma_fe > :" +"minimalScopesMode" +msgid "" +"Limit scope selection to Direct, User default, and Scope of post replying " +"to. Also prevents replying to a DM with a public post from PleromaFE." msgstr "" "Limit scope selection to Direct, User default, and Scope of post replying " "to. Also prevents replying to a DM with a public post from PleromaFE." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:frontend_configurations > :pleroma_fe > :nsfwCensorImage" -msgid "URL of the image to use for hiding NSFW media attachments in the timeline" +#, fuzzy +msgctxt "" +"config description at :pleroma-:frontend_configurations > :pleroma_fe > :" +"nsfwCensorImage" +msgid "" +"URL of the image to use for hiding NSFW media attachments in the timeline" msgstr "" "URL of the image to use for hiding NSFW media attachments in the timeline" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:frontend_configurations > :pleroma_fe > :postContentType" +#, fuzzy +msgctxt "" +"config description at :pleroma-:frontend_configurations > :pleroma_fe > :" +"postContentType" msgid "Default post formatting option" msgstr "Default post formatting option" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:frontend_configurations > :pleroma_fe > :redirectRootLogin" +#, fuzzy +msgctxt "" +"config description at :pleroma-:frontend_configurations > :pleroma_fe > :" +"redirectRootLogin" msgid "Relative URL which indicates where to redirect when a user is logged in" -msgstr "Relative URL which indicates where to redirect when a user is logged in" +msgstr "" +"Relative URL which indicates where to redirect when a user is logged in" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:frontend_configurations > :pleroma_fe > :redirectRootNoLogin" -msgid "Relative URL which indicates where to redirect when a user isn't logged in" +#, fuzzy +msgctxt "" +"config description at :pleroma-:frontend_configurations > :pleroma_fe > :" +"redirectRootNoLogin" +msgid "" +"Relative URL which indicates where to redirect when a user isn't logged in" msgstr "" "Relative URL which indicates where to redirect when a user isn't logged in" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:frontend_configurations > :pleroma_fe > :scopeCopy" +#, fuzzy +msgctxt "" +"config description at :pleroma-:frontend_configurations > :pleroma_fe > :" +"scopeCopy" msgid "Copy the scope (private/unlisted/public) in replies to posts by default" -msgstr "Copy the scope (private/unlisted/public) in replies to posts by default" +msgstr "" +"Copy the scope (private/unlisted/public) in replies to posts by default" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:frontend_configurations > :pleroma_fe > :showFeaturesPanel" -msgid "Enables panel displaying functionality of the instance on the About page" +#, fuzzy +msgctxt "" +"config description at :pleroma-:frontend_configurations > :pleroma_fe > :" +"showFeaturesPanel" +msgid "" +"Enables panel displaying functionality of the instance on the About page" msgstr "" "Enables panel displaying functionality of the instance on the About page" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:frontend_configurations > :pleroma_fe > :showInstanceSpecificPanel" +#, fuzzy +msgctxt "" +"config description at :pleroma-:frontend_configurations > :pleroma_fe > :" +"showInstanceSpecificPanel" msgid "Whether to show the instance's custom panel" msgstr "Whether to show the instance's custom panel" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:frontend_configurations > :pleroma_fe > :sidebarRight" +#, fuzzy +msgctxt "" +"config description at :pleroma-:frontend_configurations > :pleroma_fe > :" +"sidebarRight" msgid "Change alignment of sidebar and panels to the right" msgstr "Change alignment of sidebar and panels to the right" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:frontend_configurations > :pleroma_fe > :subjectLineBehavior" -msgid "Allows changing the default behaviour of subject lines in replies.\n `email`: copy and preprend re:, as in email,\n `masto`: copy verbatim, as in Mastodon,\n `noop`: don't copy the subject." +#, fuzzy +msgctxt "" +"config description at :pleroma-:frontend_configurations > :pleroma_fe > :" +"subjectLineBehavior" +msgid "" +"Allows changing the default behaviour of subject lines in replies.\n" +" `email`: copy and preprend re:, as in email,\n" +" `masto`: copy verbatim, as in Mastodon,\n" +" `noop`: don't copy the subject." msgstr "" "Allows changing the default behaviour of subject lines in replies.\n" " `email`: copy and preprend re:, as in email,\n" @@ -1554,337 +1736,374 @@ msgstr "" " `noop`: don't copy the subject." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:frontend_configurations > :pleroma_fe > :theme" +#, fuzzy +msgctxt "" +"config description at :pleroma-:frontend_configurations > :pleroma_fe > :" +"theme" msgid "Which theme to use. Available themes are defined in styles.json" msgstr "Which theme to use. Available themes are defined in styles.json" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:frontends > :admin" msgid "Admin frontend" msgstr "Admin frontend" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:frontends > :admin > name" -msgid "Name of the installed frontend. Valid config must include both `Name` and `Reference` values." +msgid "" +"Name of the installed frontend. Valid config must include both `Name` and " +"`Reference` values." msgstr "" "Name of the installed frontend. Valid config must include both `Name` and " "`Reference` values." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:frontends > :admin > ref" -msgid "Reference of the installed frontend to be used. Valid config must include both `Name` and `Reference` values." +msgid "" +"Reference of the installed frontend to be used. Valid config must include " +"both `Name` and `Reference` values." msgstr "" "Reference of the installed frontend to be used. Valid config must include " "both `Name` and `Reference` values." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:frontends > :available" -msgid "A map containing available frontends and parameters for their installation." +msgid "" +"A map containing available frontends and parameters for their installation." msgstr "" "A map containing available frontends and parameters for their installation." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:frontends > :available > build_dir" msgid "The directory inside the zip file " msgstr "The directory inside the zip file " #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:frontends > :available > build_url" -msgid "Either an url to a zip file containing the frontend or a template to build it by inserting the `ref`. The string `${ref}` will be replaced by the configured `ref`." +msgid "" +"Either an url to a zip file containing the frontend or a template to build " +"it by inserting the `ref`. The string `${ref}` will be replaced by the " +"configured `ref`." msgstr "" "Either an url to a zip file containing the frontend or a template to build " "it by inserting the `ref`. The string `${ref}` will be replaced by the " "configured `ref`." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:frontends > :available > custom-http-headers" +#, fuzzy +msgctxt "" +"config description at :pleroma-:frontends > :available > custom-http-headers" msgid "The custom HTTP headers for the frontend" msgstr "The custom HTTP headers for the frontend" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:frontends > :available > git" msgid "URL of the git repository of the frontend" msgstr "URL of the git repository of the frontend" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:frontends > :available > name" msgid "Name of the frontend." msgstr "Name of the frontend." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:frontends > :available > ref" msgid "Reference of the frontend to be used." msgstr "Reference of the frontend to be used." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:frontends > :primary" msgid "Primary frontend, the one that is served for all pages by default" msgstr "Primary frontend, the one that is served for all pages by default" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:frontends > :primary > name" -msgid "Name of the installed frontend. Valid config must include both `Name` and `Reference` values." +msgid "" +"Name of the installed frontend. Valid config must include both `Name` and " +"`Reference` values." msgstr "" "Name of the installed frontend. Valid config must include both `Name` and " "`Reference` values." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:frontends > :primary > ref" -msgid "Reference of the installed frontend to be used. Valid config must include both `Name` and `Reference` values." +msgid "" +"Reference of the installed frontend to be used. Valid config must include " +"both `Name` and `Reference` values." msgstr "" "Reference of the installed frontend to be used. Valid config must include " "both `Name` and `Reference` values." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:gopher > :dstport" msgid "Port advertised in URLs (optional, defaults to port)" msgstr "Port advertised in URLs (optional, defaults to port)" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:gopher > :enabled" msgid "Enables the gopher interface" msgstr "Enables the gopher interface" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:gopher > :ip" msgid "IP address to bind to" msgstr "IP address to bind to" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:gopher > :port" msgid "Port to bind to" msgstr "Port to bind to" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:hackney_pools > :federation" msgid "Settings for federation pool." msgstr "Settings for federation pool." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:hackney_pools > :federation > :max_connections" +#, fuzzy +msgctxt "" +"config description at :pleroma-:hackney_pools > :federation > :" +"max_connections" msgid "Number workers in the pool." msgstr "Number workers in the pool." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:hackney_pools > :federation > :timeout" +#, fuzzy +msgctxt "" +"config description at :pleroma-:hackney_pools > :federation > :timeout" msgid "Timeout while `hackney` will wait for response." msgstr "Timeout while `hackney` will wait for response." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:hackney_pools > :media" msgid "Settings for media pool." msgstr "Settings for media pool." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:hackney_pools > :media > :max_connections" +#, fuzzy +msgctxt "" +"config description at :pleroma-:hackney_pools > :media > :max_connections" msgid "Number workers in the pool." msgstr "Number workers in the pool." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:hackney_pools > :media > :timeout" msgid "Timeout while `hackney` will wait for response." msgstr "Timeout while `hackney` will wait for response." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:hackney_pools > :upload" msgid "Settings for upload pool." msgstr "Settings for upload pool." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:hackney_pools > :upload > :max_connections" +#, fuzzy +msgctxt "" +"config description at :pleroma-:hackney_pools > :upload > :max_connections" msgid "Number workers in the pool." msgstr "Number workers in the pool." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:hackney_pools > :upload > :timeout" msgid "Timeout while `hackney` will wait for response." msgstr "Timeout while `hackney` will wait for response." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:http > :adapter" msgid "Adapter specific options" msgstr "Adapter specific options" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:http > :adapter > :ssl_options" msgid "SSL options for HTTP adapter" msgstr "SSL options for HTTP adapter" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:http > :adapter > :ssl_options > :versions" +#, fuzzy +msgctxt "" +"config description at :pleroma-:http > :adapter > :ssl_options > :versions" msgid "List of TLS version to use" msgstr "List of TLS version to use" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:http > :proxy_url" msgid "Proxy URL" msgstr "Proxy URL" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:http > :user_agent" -msgid "What user agent to use. Must be a string or an atom `:default`. Default value is `:default`." +msgid "" +"What user agent to use. Must be a string or an atom `:default`. Default " +"value is `:default`." msgstr "" "What user agent to use. Must be a string or an atom `:default`. Default " "value is `:default`." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:http_security > :enabled" msgid "Whether the managed content security policy is enabled" msgstr "Whether the managed content security policy is enabled" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:http_security > :referrer_policy" msgid "The referrer policy to use, either \"same-origin\" or \"no-referrer\"" msgstr "The referrer policy to use, either \"same-origin\" or \"no-referrer\"" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:http_security > :report_uri" msgid "Adds the specified URL to report-uri and report-to group in CSP header" msgstr "Adds the specified URL to report-uri and report-to group in CSP header" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:http_security > :sts" msgid "Whether to additionally send a Strict-Transport-Security header" msgstr "Whether to additionally send a Strict-Transport-Security header" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:http_security > :sts_max_age" msgid "The maximum age for the Strict-Transport-Security header if sent" msgstr "The maximum age for the Strict-Transport-Security header if sent" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:instance > :account_activation_required" +#, fuzzy +msgctxt "" +"config description at :pleroma-:instance > :account_activation_required" msgid "Require users to confirm their emails before signing in" msgstr "Require users to confirm their emails before signing in" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :account_approval_required" msgid "Require users to be manually approved by an admin before signing in" msgstr "Require users to be manually approved by an admin before signing in" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :account_field_name_length" msgid "An account field name maximum length. Default: 512." msgstr "An account field name maximum length. Default: 512." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:instance > :account_field_value_length" +#, fuzzy +msgctxt "" +"config description at :pleroma-:instance > :account_field_value_length" msgid "An account field value maximum length. Default: 2048." msgstr "An account field value maximum length. Default: 2048." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :allow_relay" -msgid "Permits remote instances to subscribe to all public posts of your instance. (Important!) This may increase the visibility of your instance." +msgid "" +"Permits remote instances to subscribe to all public posts of your instance. " +"(Important!) This may increase the visibility of your instance." msgstr "" "Permits remote instances to subscribe to all public posts of your instance. " "(Important!) This may increase the visibility of your instance." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :allowed_post_formats" msgid "MIME-type list of formats allowed to be posted (transformed into HTML)" msgstr "MIME-type list of formats allowed to be posted (transformed into HTML)" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :attachment_links" msgid "Enable to automatically add attachment link text to statuses" msgstr "Enable to automatically add attachment link text to statuses" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :autofollowed_nicknames" -msgid "Set to nicknames of (local) users that every new user should automatically follow" +msgid "" +"Set to nicknames of (local) users that every new user should automatically " +"follow" msgstr "" "Set to nicknames of (local) users that every new user should automatically " "follow" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :autofollowing_nicknames" -msgid "Set to nicknames of (local) users that automatically follows every newly registered user" +msgid "" +"Set to nicknames of (local) users that automatically follows every newly " +"registered user" msgstr "" "Set to nicknames of (local) users that automatically follows every newly " "registered user" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :avatar_upload_limit" msgid "File size limit of user's profile avatars" msgstr "File size limit of user's profile avatars" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :background_upload_limit" msgid "File size limit of user's profile backgrounds" msgstr "File size limit of user's profile backgrounds" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :banner_upload_limit" msgid "File size limit of user's profile banners" msgstr "File size limit of user's profile banners" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :birthday_min_age" -msgid "Minimum required age for users to create account. Only used if birthday is required." +msgid "" +"Minimum required age for users to create account. Only used if birthday is " +"required." msgstr "" "Minimum required age for users to create account. Only used if birthday is " "required." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :birthday_required" msgid "Require users to enter their birthday." msgstr "Require users to enter their birthday." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :cleanup_attachments" -msgid "Enable to remove associated attachments when status is removed.\nThis will not affect duplicates and attachments without status.\nEnabling this will increase load to database when deleting statuses on larger instances.\n" +msgid "" +"Enable to remove associated attachments when status is removed.\n" +"This will not affect duplicates and attachments without status.\n" +"Enabling this will increase load to database when deleting statuses on " +"larger instances.\n" msgstr "" "Enable to remove associated attachments when status is removed.\n" "This will not affect duplicates and attachments without status.\n" @@ -1892,43 +2111,54 @@ msgstr "" "larger instances.\n" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :description" -msgid "The instance's description. It can be seen in nodeinfo and `/api/v1/instance`" +msgid "" +"The instance's description. It can be seen in nodeinfo and `/api/v1/instance`" msgstr "" "The instance's description. It can be seen in nodeinfo and `/api/v1/instance`" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :email" msgid "Email used to reach an Administrator/Moderator of the instance" msgstr "Email used to reach an Administrator/Moderator of the instance" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :extended_nickname_format" -msgid "Enable to use extended local nicknames format (allows underscores/dashes). This will break federation with older software for theses nicknames." +msgid "" +"Enable to use extended local nicknames format (allows underscores/dashes). " +"This will break federation with older software for theses nicknames." msgstr "" "Enable to use extended local nicknames format (allows underscores/dashes). " "This will break federation with older software for theses nicknames." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:instance > :external_user_synchronization" -msgid "Enabling following/followers counters synchronization for external users" +#, fuzzy +msgctxt "" +"config description at :pleroma-:instance > :external_user_synchronization" +msgid "" +"Enabling following/followers counters synchronization for external users" msgstr "" "Enabling following/followers counters synchronization for external users" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :federating" msgid "Enable federation with other instances" msgstr "Enable federation with other instances" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:instance > :federation_incoming_replies_max_depth" -msgid "Max. depth of reply-to and reply activities fetching on incoming federation, to prevent out-of-memory situations while fetching very long threads. If set to `nil`, threads of any depth will be fetched. Lower this value if you experience out-of-memory crashes." +#, fuzzy +msgctxt "" +"config description at :pleroma-:instance > :" +"federation_incoming_replies_max_depth" +msgid "" +"Max. depth of reply-to and reply activities fetching on incoming federation, " +"to prevent out-of-memory situations while fetching very long threads. If set " +"to `nil`, threads of any depth will be fetched. Lower this value if you " +"experience out-of-memory crashes." msgstr "" "Max. depth of reply-to and reply activities fetching on incoming federation, " "to prevent out-of-memory situations while fetching very long threads. If set " @@ -1936,196 +2166,239 @@ msgstr "" "experience out-of-memory crashes." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:instance > :federation_reachability_timeout_days" -msgid "Timeout (in days) of each external federation target being unreachable prior to pausing federating to it" +#, fuzzy +msgctxt "" +"config description at :pleroma-:instance > :" +"federation_reachability_timeout_days" +msgid "" +"Timeout (in days) of each external federation target being unreachable prior " +"to pausing federating to it" msgstr "" "Timeout (in days) of each external federation target being unreachable prior " "to pausing federating to it" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :healthcheck" msgid "If enabled, system data will be shown on `/api/pleroma/healthcheck`" msgstr "If enabled, system data will be shown on `/api/pleroma/healthcheck`" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :instance_thumbnail" -msgid "The instance thumbnail can be any image that represents your instance and is used by some apps or services when they display information about your instance." +msgid "" +"The instance thumbnail can be any image that represents your instance and is " +"used by some apps or services when they display information about your " +"instance." msgstr "" "The instance thumbnail can be any image that represents your instance and is " "used by some apps or services when they display information about your " "instance." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :invites_enabled" -msgid "Enable user invitations for admins (depends on `registrations_open` being disabled)" +msgid "" +"Enable user invitations for admins (depends on `registrations_open` being " +"disabled)" msgstr "" "Enable user invitations for admins (depends on `registrations_open` being " "disabled)" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :limit" msgid "Posts character limit (CW/Subject included in the counter)" msgstr "Posts character limit (CW/Subject included in the counter)" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :limit_to_local_content" -msgid "Limit unauthenticated users to search for local statutes and users only. Default: `:unauthenticated`." +msgid "" +"Limit unauthenticated users to search for local statutes and users only. " +"Default: `:unauthenticated`." msgstr "" "Limit unauthenticated users to search for local statutes and users only. " "Default: `:unauthenticated`." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :max_account_fields" msgid "The maximum number of custom fields in the user profile. Default: 10." msgstr "The maximum number of custom fields in the user profile. Default: 10." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :max_endorsed_users" msgid "The maximum number of recommended accounts. 0 will disable the feature." -msgstr "The maximum number of recommended accounts. 0 will disable the feature." +msgstr "" +"The maximum number of recommended accounts. 0 will disable the feature." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :max_media_attachments" msgid "Maximum number of post media attachments" msgstr "Maximum number of post media attachments" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :max_pinned_statuses" msgid "The maximum number of pinned statuses. 0 will disable the feature." msgstr "The maximum number of pinned statuses. 0 will disable the feature." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :max_remote_account_fields" -msgid "The maximum number of custom fields in the remote user profile. Default: 20." +msgid "" +"The maximum number of custom fields in the remote user profile. Default: 20." msgstr "" "The maximum number of custom fields in the remote user profile. Default: 20." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :max_report_comment_size" msgid "The maximum size of the report comment. Default: 1000." msgstr "The maximum size of the report comment. Default: 1000." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:instance > :multi_factor_authentication" +#, fuzzy +msgctxt "" +"config description at :pleroma-:instance > :multi_factor_authentication" msgid "Multi-factor authentication settings" msgstr "Multi-factor authentication settings" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:instance > :multi_factor_authentication > :backup_codes" +#, fuzzy +msgctxt "" +"config description at :pleroma-:instance > :multi_factor_authentication > :" +"backup_codes" msgid "MFA backup codes settings" msgstr "MFA backup codes settings" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:instance > :multi_factor_authentication > :backup_codes > :length" -msgid "Determines the length of backup one-time pass-codes, in characters. Defaults to 16 characters." +#, fuzzy +msgctxt "" +"config description at :pleroma-:instance > :multi_factor_authentication > :" +"backup_codes > :length" +msgid "" +"Determines the length of backup one-time pass-codes, in characters. Defaults " +"to 16 characters." msgstr "" "Determines the length of backup one-time pass-codes, in characters. Defaults " "to 16 characters." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:instance > :multi_factor_authentication > :backup_codes > :number" +#, fuzzy +msgctxt "" +"config description at :pleroma-:instance > :multi_factor_authentication > :" +"backup_codes > :number" msgid "Number of backup codes to generate." msgstr "Number of backup codes to generate." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:instance > :multi_factor_authentication > :totp" +#, fuzzy +msgctxt "" +"config description at :pleroma-:instance > :multi_factor_authentication > :" +"totp" msgid "TOTP settings" msgstr "TOTP settings" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:instance > :multi_factor_authentication > :totp > :digits" -msgid "Determines the length of a one-time pass-code, in characters. Defaults to 6 characters." +#, fuzzy +msgctxt "" +"config description at :pleroma-:instance > :multi_factor_authentication > :" +"totp > :digits" +msgid "" +"Determines the length of a one-time pass-code, in characters. Defaults to 6 " +"characters." msgstr "" "Determines the length of a one-time pass-code, in characters. Defaults to 6 " "characters." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:instance > :multi_factor_authentication > :totp > :period" -msgid "A period for which the TOTP code will be valid, in seconds. Defaults to 30 seconds." +#, fuzzy +msgctxt "" +"config description at :pleroma-:instance > :multi_factor_authentication > :" +"totp > :period" +msgid "" +"A period for which the TOTP code will be valid, in seconds. Defaults to 30 " +"seconds." msgstr "" "A period for which the TOTP code will be valid, in seconds. Defaults to 30 " "seconds." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :name" msgid "Name of the instance" msgstr "Name of the instance" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :notify_email" msgid "Envelope FROM address for mail sent via Pleroma" msgstr "Envelope FROM address for mail sent via Pleroma" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :poll_limits" msgid "A map with poll limits for local polls" msgstr "A map with poll limits for local polls" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:instance > :poll_limits > :max_expiration" +#, fuzzy +msgctxt "" +"config description at :pleroma-:instance > :poll_limits > :max_expiration" msgid "Maximum expiration time (in seconds)" msgstr "Maximum expiration time (in seconds)" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:instance > :poll_limits > :max_option_chars" +#, fuzzy +msgctxt "" +"config description at :pleroma-:instance > :poll_limits > :max_option_chars" msgid "Maximum number of characters per option" msgstr "Maximum number of characters per option" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:instance > :poll_limits > :max_options" +#, fuzzy +msgctxt "" +"config description at :pleroma-:instance > :poll_limits > :max_options" msgid "Maximum number of options" msgstr "Maximum number of options" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:instance > :poll_limits > :min_expiration" +#, fuzzy +msgctxt "" +"config description at :pleroma-:instance > :poll_limits > :min_expiration" msgid "Minimum expiration time (in seconds)" msgstr "Minimum expiration time (in seconds)" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :privileged_staff" -msgid "Let moderators access sensitive data (e.g. updating user credentials, get password reset token, delete users, index and read private statuses and chats)" +msgid "" +"Let moderators access sensitive data (e.g. updating user credentials, get " +"password reset token, delete users, index and read private statuses and " +"chats)" msgstr "" "Let moderators access sensitive data (e.g. updating user credentials, get " "password reset token, delete users, index and read private statuses and " "chats)" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :profile_directory" msgid "Enable profile directory." msgstr "Enable profile directory." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :public" -msgid "Makes the client API in authenticated mode-only except for user-profiles. Useful for disabling the Local Timeline and The Whole Known Network. Note: when setting to `false`, please also check `:restrict_unauthenticated` setting." +msgid "" +"Makes the client API in authenticated mode-only except for user-profiles. " +"Useful for disabling the Local Timeline and The Whole Known Network. Note: " +"when setting to `false`, please also check `:restrict_unauthenticated` " +"setting." msgstr "" "Makes the client API in authenticated mode-only except for user-profiles. " "Useful for disabling the Local Timeline and The Whole Known Network. Note: " @@ -2133,292 +2406,339 @@ msgstr "" "setting." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :quarantined_instances" -msgid "List of ActivityPub instances where private (DMs, followers-only) activities will not be sent and the reason for doing so" +msgid "" +"List of ActivityPub instances where private (DMs, followers-only) activities " +"will not be sent and the reason for doing so" msgstr "" "List of ActivityPub instances where private (DMs, followers-only) activities " "will not be sent and the reason for doing so" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:instance > :registration_reason_length" +#, fuzzy +msgctxt "" +"config description at :pleroma-:instance > :registration_reason_length" msgid "Maximum registration reason length. Default: 500." msgstr "Maximum registration reason length. Default: 500." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :registrations_open" -msgid "Enable registrations for anyone. Invitations require this setting to be disabled." +msgid "" +"Enable registrations for anyone. Invitations require this setting to be " +"disabled." msgstr "" "Enable registrations for anyone. Invitations require this setting to be " "disabled." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :remote_limit" msgid "Hard character limit beyond which remote posts will be dropped" msgstr "Hard character limit beyond which remote posts will be dropped" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:instance > :remote_post_retention_days" -msgid "The default amount of days to retain remote posts when pruning the database" +#, fuzzy +msgctxt "" +"config description at :pleroma-:instance > :remote_post_retention_days" +msgid "" +"The default amount of days to retain remote posts when pruning the database" msgstr "" "The default amount of days to retain remote posts when pruning the database" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :safe_dm_mentions" -msgid "If enabled, only mentions at the beginning of a post will be used to address people in direct messages. This is to prevent accidental mentioning of people when talking about them (e.g. \"@admin please keep an eye on @bad_actor\"). Default: disabled" +msgid "" +"If enabled, only mentions at the beginning of a post will be used to address " +"people in direct messages. This is to prevent accidental mentioning of " +"people when talking about them (e.g. \"@admin please keep an eye on " +"@bad_actor\"). Default: disabled" msgstr "" "If enabled, only mentions at the beginning of a post will be used to address " "people in direct messages. This is to prevent accidental mentioning of " -"people when talking about them (e.g. \"@admin please keep an eye on @" -"bad_actor\"). Default: disabled" +"people when talking about them (e.g. \"@admin please keep an eye on " +"@bad_actor\"). Default: disabled" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :show_reactions" msgid "Let favourites and emoji reactions be viewed through the API." msgstr "Let favourites and emoji reactions be viewed through the API." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :skip_thread_containment" msgid "Skip filtering out broken threads. Default: enabled." msgstr "Skip filtering out broken threads. Default: enabled." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :static_dir" msgid "Instance static directory" msgstr "Instance static directory" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :upload_limit" msgid "File size limit of uploads (except for avatar, background, banner)" msgstr "File size limit of uploads (except for avatar, background, banner)" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :user_bio_length" msgid "A user bio maximum length. Default: 5000." msgstr "A user bio maximum length. Default: 5000." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :user_name_length" msgid "A user name maximum length. Default: 100." msgstr "A user name maximum length. Default: 100." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instances_favicons > :enabled" msgid "Allow/disallow displaying and getting instances favicons" msgstr "Allow/disallow displaying and getting instances favicons" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:ldap > :base" msgid "LDAP base, e.g. \"dc=example,dc=com\"" msgstr "LDAP base, e.g. \"dc=example,dc=com\"" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:ldap > :enabled" msgid "Enables LDAP authentication" msgstr "Enables LDAP authentication" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:ldap > :host" msgid "LDAP server hostname" msgstr "LDAP server hostname" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:ldap > :port" msgid "LDAP port, e.g. 389 or 636" msgstr "LDAP port, e.g. 389 or 636" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:ldap > :ssl" msgid "Enable to use SSL, usually implies the port 636" msgstr "Enable to use SSL, usually implies the port 636" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:ldap > :sslopts" msgid "Additional SSL options" msgstr "Additional SSL options" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:ldap > :sslopts > :cacertfile" msgid "Path to file with PEM encoded cacerts" msgstr "Path to file with PEM encoded cacerts" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:ldap > :sslopts > :verify" msgid "Type of cert verification" msgstr "Type of cert verification" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:ldap > :tls" msgid "Enable to use STARTTLS, usually implies the port 389" msgstr "Enable to use STARTTLS, usually implies the port 389" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:ldap > :tlsopts" msgid "Additional TLS options" msgstr "Additional TLS options" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:ldap > :tlsopts > :cacertfile" msgid "Path to file with PEM encoded cacerts" msgstr "Path to file with PEM encoded cacerts" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:ldap > :tlsopts > :verify" msgid "Type of cert verification" msgstr "Type of cert verification" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:ldap > :uid" -msgid "LDAP attribute name to authenticate the user, e.g. when \"cn\", the filter will be \"cn=username,base\"" +msgid "" +"LDAP attribute name to authenticate the user, e.g. when \"cn\", the filter " +"will be \"cn=username,base\"" msgstr "" "LDAP attribute name to authenticate the user, e.g. when \"cn\", the filter " "will be \"cn=username,base\"" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:majic_pool > :size" msgid "Number of majic workers to start." msgstr "Number of majic workers to start." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:manifest > :background_color" msgid "Describe the background color of the app" msgstr "Describe the background color of the app" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:manifest > :icons" msgid "Describe the icons of the app" msgstr "Describe the icons of the app" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:manifest > :theme_color" msgid "Describe the theme color of the app" msgstr "Describe the theme color of the app" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:markup > :scrub_policy" -msgid "Module names are shortened (removed leading `Pleroma.HTML.` part), but on adding custom module you need to use full name." +msgid "" +"Module names are shortened (removed leading `Pleroma.HTML.` part), but on " +"adding custom module you need to use full name." msgstr "" "Module names are shortened (removed leading `Pleroma.HTML.` part), but on " "adding custom module you need to use full name." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:media_preview_proxy > :enabled" -msgid "Enables proxying of remote media preview to the instance's proxy. Requires enabled media proxy." +msgid "" +"Enables proxying of remote media preview to the instance's proxy. Requires " +"enabled media proxy." msgstr "" "Enables proxying of remote media preview to the instance's proxy. Requires " "enabled media proxy." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:media_preview_proxy > :image_quality" -msgid "Quality of the output. Ranges from 0 (min quality) to 100 (max quality)." +msgid "" +"Quality of the output. Ranges from 0 (min quality) to 100 (max quality)." msgstr "" "Quality of the output. Ranges from 0 (min quality) to 100 (max quality)." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:media_preview_proxy > :min_content_length" -msgid "Min content length (in bytes) to perform preview. Media smaller in size will be served without thumbnailing." +#, fuzzy +msgctxt "" +"config description at :pleroma-:media_preview_proxy > :min_content_length" +msgid "" +"Min content length (in bytes) to perform preview. Media smaller in size will " +"be served without thumbnailing." msgstr "" "Min content length (in bytes) to perform preview. Media smaller in size will " "be served without thumbnailing." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:media_preview_proxy > :thumbnail_max_height" -msgid "Max height of preview thumbnail for images (video preview always has original dimensions)." +#, fuzzy +msgctxt "" +"config description at :pleroma-:media_preview_proxy > :thumbnail_max_height" +msgid "" +"Max height of preview thumbnail for images (video preview always has " +"original dimensions)." msgstr "" "Max height of preview thumbnail for images (video preview always has " "original dimensions)." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:media_preview_proxy > :thumbnail_max_width" -msgid "Max width of preview thumbnail for images (video preview always has original dimensions)." +#, fuzzy +msgctxt "" +"config description at :pleroma-:media_preview_proxy > :thumbnail_max_width" +msgid "" +"Max width of preview thumbnail for images (video preview always has original " +"dimensions)." msgstr "" "Max width of preview thumbnail for images (video preview always has original " "dimensions)." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:media_proxy > :base_url" -msgid "The base URL to access a user-uploaded file. Useful when you want to proxy the media files via another host/CDN fronts." +msgid "" +"The base URL to access a user-uploaded file. Useful when you want to proxy " +"the media files via another host/CDN fronts." msgstr "" "The base URL to access a user-uploaded file. Useful when you want to proxy " "the media files via another host/CDN fronts." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:media_proxy > :enabled" msgid "Enables proxying of remote media via the instance's proxy" msgstr "Enables proxying of remote media via the instance's proxy" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:media_proxy > :invalidation > :enabled" +#, fuzzy +msgctxt "" +"config description at :pleroma-:media_proxy > :invalidation > :enabled" msgid "Enables media cache object invalidation." msgstr "Enables media cache object invalidation." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:media_proxy > :invalidation > :provider" +#, fuzzy +msgctxt "" +"config description at :pleroma-:media_proxy > :invalidation > :provider" msgid "Module which will be used to purge objects from the cache." msgstr "Module which will be used to purge objects from the cache." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:media_proxy > :proxy_opts" msgid "Internal Pleroma.ReverseProxy settings" msgstr "Internal Pleroma.ReverseProxy settings" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:media_proxy > :proxy_opts > :max_body_length" -msgid "Maximum file size (in bytes) allowed through the Pleroma MediaProxy cache." +#, fuzzy +msgctxt "" +"config description at :pleroma-:media_proxy > :proxy_opts > :max_body_length" +msgid "" +"Maximum file size (in bytes) allowed through the Pleroma MediaProxy cache." msgstr "" "Maximum file size (in bytes) allowed through the Pleroma MediaProxy cache." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:media_proxy > :proxy_opts > :max_read_duration" +#, fuzzy +msgctxt "" +"config description at :pleroma-:media_proxy > :proxy_opts > :" +"max_read_duration" msgid "Timeout (in milliseconds) of GET request to the remote URI." msgstr "Timeout (in milliseconds) of GET request to the remote URI." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:media_proxy > :proxy_opts > :redirect_on_failure" -msgid "Redirects the client to the origin server upon encountering HTTP errors.\n\nNote that files larger than Max Body Length will trigger an error. (e.g., Peertube videos)\n\n\n**WARNING:** This setting will allow larger files to be accessed, but exposes the\n\nIP addresses of your users to the other servers, bypassing the MediaProxy.\n" +#, fuzzy +msgctxt "" +"config description at :pleroma-:media_proxy > :proxy_opts > :" +"redirect_on_failure" +msgid "" +"Redirects the client to the origin server upon encountering HTTP errors.\n" +"\n" +"Note that files larger than Max Body Length will trigger an error. (e.g., " +"Peertube videos)\n" +"\n" +"\n" +"**WARNING:** This setting will allow larger files to be accessed, but " +"exposes the\n" +"\n" +"IP addresses of your users to the other servers, bypassing the MediaProxy.\n" msgstr "" "Redirects the client to the origin server upon encountering HTTP errors.\n" "\n" @@ -2432,38 +2752,47 @@ msgstr "" "IP addresses of your users to the other servers, bypassing the MediaProxy.\n" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:media_proxy > :whitelist" msgid "List of hosts with scheme to bypass the MediaProxy" msgstr "List of hosts with scheme to bypass the MediaProxy" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:modules > :runtime_dir" msgid "A path to custom Elixir modules (such as MRF policies)." msgstr "A path to custom Elixir modules (such as MRF policies)." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf > :policies" -msgid "A list of MRF policies enabled. Module names are shortened (removed leading `Pleroma.Web.ActivityPub.MRF.` part), but on adding custom module you need to use full name." +msgid "" +"A list of MRF policies enabled. Module names are shortened (removed leading " +"`Pleroma.Web.ActivityPub.MRF.` part), but on adding custom module you need " +"to use full name." msgstr "" "A list of MRF policies enabled. Module names are shortened (removed leading " "`Pleroma.Web.ActivityPub.MRF.` part), but on adding custom module you need " "to use full name." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf > :transparency" -msgid "Make the content of your Message Rewrite Facility settings public (via nodeinfo)" +msgid "" +"Make the content of your Message Rewrite Facility settings public (via " +"nodeinfo)" msgstr "" "Make the content of your Message Rewrite Facility settings public (via " "nodeinfo)" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf > :transparency_exclusions" -msgid "Exclude specific instance names from MRF transparency. The use of the exclusions feature will be disclosed in nodeinfo as a boolean value. You can also provide a reason for excluding these instance names. The instances and reasons won't be publicly disclosed." +msgid "" +"Exclude specific instance names from MRF transparency. The use of the " +"exclusions feature will be disclosed in nodeinfo as a boolean value. You can " +"also provide a reason for excluding these instance names. The instances and " +"reasons won't be publicly disclosed." msgstr "" "Exclude specific instance names from MRF transparency. The use of the " "exclusions feature will be disclosed in nodeinfo as a boolean value. You can " @@ -2471,60 +2800,76 @@ msgstr "" "reasons won't be publicly disclosed." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_activity_expiration > :days" msgid "Default global expiration time for all local activities (in days)" msgstr "Default global expiration time for all local activities (in days)" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_follow_bot > :follower_nickname" -msgid "The name of the bot account to use for following newly discovered users." +msgid "" +"The name of the bot account to use for following newly discovered users." msgstr "" "The name of the bot account to use for following newly discovered users." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:mrf_hashtag > :federated_timeline_removal" -msgid "A list of hashtags which result in message being removed from federated timelines (a.k.a unlisted)." +#, fuzzy +msgctxt "" +"config description at :pleroma-:mrf_hashtag > :federated_timeline_removal" +msgid "" +"A list of hashtags which result in message being removed from federated " +"timelines (a.k.a unlisted)." msgstr "" "A list of hashtags which result in message being removed from federated " "timelines (a.k.a unlisted)." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_hashtag > :reject" msgid "A list of hashtags which result in message being rejected." msgstr "A list of hashtags which result in message being rejected." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_hashtag > :sensitive" -msgid "A list of hashtags which result in message being set as sensitive (a.k.a NSFW/R-18)" +msgid "" +"A list of hashtags which result in message being set as sensitive (a.k.a " +"NSFW/R-18)" msgstr "" "A list of hashtags which result in message being set as sensitive (a.k.a " "NSFW/R-18)" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_hellthread > :delist_threshold" -msgid "Number of mentioned users after which the message gets removed from timelines anddisables notifications. Set to 0 to disable." +msgid "" +"Number of mentioned users after which the message gets removed from " +"timelines anddisables notifications. Set to 0 to disable." msgstr "" "Number of mentioned users after which the message gets removed from " "timelines anddisables notifications. Set to 0 to disable." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_hellthread > :reject_threshold" -msgid "Number of mentioned users after which the messaged gets rejected. Set to 0 to disable." +msgid "" +"Number of mentioned users after which the messaged gets rejected. Set to 0 " +"to disable." msgstr "" "Number of mentioned users after which the messaged gets rejected. Set to 0 " "to disable." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:mrf_keyword > :federated_timeline_removal" -msgid " A list of patterns which result in message being removed from federated timelines (a.k.a unlisted).\n\n Each pattern can be a string or [Regex](https://hexdocs.pm/elixir/Regex.html) in the format of `~r/PATTERN/`.\n" +#, fuzzy +msgctxt "" +"config description at :pleroma-:mrf_keyword > :federated_timeline_removal" +msgid "" +" A list of patterns which result in message being removed from federated " +"timelines (a.k.a unlisted).\n" +"\n" +" Each pattern can be a string or [Regex](https://hexdocs.pm/elixir/Regex." +"html) in the format of `~r/PATTERN/`.\n" msgstr "" " A list of patterns which result in message being removed from federated " "timelines (a.k.a unlisted).\n" @@ -2533,9 +2878,13 @@ msgstr "" "html) in the format of `~r/PATTERN/`.\n" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_keyword > :reject" -msgid " A list of patterns which result in message being rejected.\n\n Each pattern can be a string or [Regex](https://hexdocs.pm/elixir/Regex.html) in the format of `~r/PATTERN/`.\n" +msgid "" +" A list of patterns which result in message being rejected.\n" +"\n" +" Each pattern can be a string or [Regex](https://hexdocs.pm/elixir/Regex." +"html) in the format of `~r/PATTERN/`.\n" msgstr "" " A list of patterns which result in message being rejected.\n" "\n" @@ -2543,9 +2892,13 @@ msgstr "" "html) in the format of `~r/PATTERN/`.\n" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_keyword > :replace" -msgid " **Pattern**: a string or [Regex](https://hexdocs.pm/elixir/Regex.html) in the format of `~r/PATTERN/`.\n\n **Replacement**: a string. Leaving the field empty is permitted.\n" +msgid "" +" **Pattern**: a string or [Regex](https://hexdocs.pm/elixir/Regex.html) in " +"the format of `~r/PATTERN/`.\n" +"\n" +" **Replacement**: a string. Leaving the field empty is permitted.\n" msgstr "" " **Pattern**: a string or [Regex](https://hexdocs.pm/elixir/Regex.html) in " "the format of `~r/PATTERN/`.\n" @@ -2553,15 +2906,19 @@ msgstr "" " **Replacement**: a string. Leaving the field empty is permitted.\n" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_mention > :actors" msgid "A list of actors for which any post mentioning them will be dropped" msgstr "A list of actors for which any post mentioning them will be dropped" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_object_age > :actions" -msgid "A list of actions to apply to the post. `:delist` removes the post from public timelines; `:strip_followers` removes followers from the ActivityPub recipient list ensuring they won't be delivered to home timelines; `:reject` rejects the message entirely" +msgid "" +"A list of actions to apply to the post. `:delist` removes the post from " +"public timelines; `:strip_followers` removes followers from the ActivityPub " +"recipient list ensuring they won't be delivered to home timelines; `:reject` " +"rejects the message entirely" msgstr "" "A list of actions to apply to the post. `:delist` removes the post from " "public timelines; `:strip_followers` removes followers from the ActivityPub " @@ -2569,104 +2926,122 @@ msgstr "" "rejects the message entirely" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_object_age > :threshold" msgid "Required age (in seconds) of a post before actions are taken." msgstr "Required age (in seconds) of a post before actions are taken." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_rejectnonpublic > :allow_direct" msgid "Whether to allow direct messages" msgstr "Whether to allow direct messages" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:mrf_rejectnonpublic > :allow_followersonly" +#, fuzzy +msgctxt "" +"config description at :pleroma-:mrf_rejectnonpublic > :allow_followersonly" msgid "Whether to allow followers-only posts" msgstr "Whether to allow followers-only posts" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_simple > :accept" -msgid "List of instances to only accept activities from (except deletes) and the reason for doing so" +msgid "" +"List of instances to only accept activities from (except deletes) and the " +"reason for doing so" msgstr "" "List of instances to only accept activities from (except deletes) and the " "reason for doing so" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_simple > :avatar_removal" msgid "List of instances to strip avatars from and the reason for doing so" msgstr "List of instances to strip avatars from and the reason for doing so" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_simple > :banner_removal" msgid "List of instances to strip banners from and the reason for doing so" msgstr "List of instances to strip banners from and the reason for doing so" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:mrf_simple > :federated_timeline_removal" -msgid "List of instances to remove from the Federated (aka The Whole Known Network) Timeline and the reason for doing so" +#, fuzzy +msgctxt "" +"config description at :pleroma-:mrf_simple > :federated_timeline_removal" +msgid "" +"List of instances to remove from the Federated (aka The Whole Known Network) " +"Timeline and the reason for doing so" msgstr "" "List of instances to remove from the Federated (aka The Whole Known Network) " "Timeline and the reason for doing so" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_simple > :followers_only" -msgid "Force posts from the given instances to be visible by followers only and the reason for doing so" +msgid "" +"Force posts from the given instances to be visible by followers only and the " +"reason for doing so" msgstr "" "Force posts from the given instances to be visible by followers only and the " "reason for doing so" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_simple > :media_nsfw" -msgid "List of instances to tag all media as NSFW (sensitive) from and the reason for doing so" +msgid "" +"List of instances to tag all media as NSFW (sensitive) from and the reason " +"for doing so" msgstr "" "List of instances to tag all media as NSFW (sensitive) from and the reason " "for doing so" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_simple > :media_removal" -msgid "List of instances to strip media attachments from and the reason for doing so" +msgid "" +"List of instances to strip media attachments from and the reason for doing so" msgstr "" "List of instances to strip media attachments from and the reason for doing so" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_simple > :reject" -msgid "List of instances to reject activities from (except deletes) and the reason for doing so" +msgid "" +"List of instances to reject activities from (except deletes) and the reason " +"for doing so" msgstr "" "List of instances to reject activities from (except deletes) and the reason " "for doing so" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_simple > :reject_deletes" msgid "List of instances to reject deletions from and the reason for doing so" msgstr "List of instances to reject deletions from and the reason for doing so" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_simple > :report_removal" msgid "List of instances to reject reports from and the reason for doing so" msgstr "List of instances to reject reports from and the reason for doing so" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_steal_emoji > :hosts" msgid "List of hosts to steal emojis from" msgstr "List of hosts to steal emojis from" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:mrf_steal_emoji > :rejected_shortcodes" -msgid " A list of patterns or matches to reject shortcodes with.\n\n Each pattern can be a string or [Regex](https://hexdocs.pm/elixir/Regex.html) in the format of `~r/PATTERN/`.\n" +#, fuzzy +msgctxt "" +"config description at :pleroma-:mrf_steal_emoji > :rejected_shortcodes" +msgid "" +" A list of patterns or matches to reject shortcodes with.\n" +"\n" +" Each pattern can be a string or [Regex](https://hexdocs.pm/elixir/Regex." +"html) in the format of `~r/PATTERN/`.\n" msgstr "" " A list of patterns or matches to reject shortcodes with.\n" "\n" @@ -2674,3711 +3049,4054 @@ msgstr "" "html) in the format of `~r/PATTERN/`.\n" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_steal_emoji > :size_limit" -msgid "File size limit (in bytes), checked before an emoji is saved to the disk" +msgid "" +"File size limit (in bytes), checked before an emoji is saved to the disk" msgstr "" "File size limit (in bytes), checked before an emoji is saved to the disk" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_subchain > :match_actor" msgid "Matches a series of regular expressions against the actor field" msgstr "Matches a series of regular expressions against the actor field" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_vocabulary > :accept" -msgid "A list of ActivityStreams terms to accept. If empty, all supported messages are accepted." +msgid "" +"A list of ActivityStreams terms to accept. If empty, all supported messages " +"are accepted." msgstr "" "A list of ActivityStreams terms to accept. If empty, all supported messages " "are accepted." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_vocabulary > :reject" -msgid "A list of ActivityStreams terms to reject. If empty, no messages are rejected." +msgid "" +"A list of ActivityStreams terms to reject. If empty, no messages are " +"rejected." msgstr "" "A list of ActivityStreams terms to reject. If empty, no messages are " "rejected." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:oauth2 > :clean_expired_tokens" -msgid "Enable a background job to clean expired OAuth tokens. Default: disabled." +msgid "" +"Enable a background job to clean expired OAuth tokens. Default: disabled." msgstr "" "Enable a background job to clean expired OAuth tokens. Default: disabled." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:oauth2 > :issue_new_refresh_token" -msgid "Keeps old refresh token or generate new refresh token when to obtain an access token" +msgid "" +"Keeps old refresh token or generate new refresh token when to obtain an " +"access token" msgstr "" "Keeps old refresh token or generate new refresh token when to obtain an " "access token" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:oauth2 > :token_expires_in" msgid "The lifetime in seconds of the access token" msgstr "The lifetime in seconds of the access token" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:pools > :default" msgid "Settings for default pool." msgstr "Settings for default pool." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:pools > :default > :max_waiting" -msgid "Maximum number of requests waiting for other requests to finish. After this number is reached, the pool will start returning errrors when a new request is made" +msgid "" +"Maximum number of requests waiting for other requests to finish. After this " +"number is reached, the pool will start returning errrors when a new request " +"is made" msgstr "" "Maximum number of requests waiting for other requests to finish. After this " "number is reached, the pool will start returning errrors when a new request " "is made" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:pools > :default > :recv_timeout" msgid "Timeout for the pool while gun will wait for response" msgstr "Timeout for the pool while gun will wait for response" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:pools > :default > :size" msgid "Maximum number of concurrent requests in the pool." msgstr "Maximum number of concurrent requests in the pool." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:pools > :federation" msgid "Settings for federation pool." msgstr "Settings for federation pool." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:pools > :federation > :max_waiting" -msgid "Maximum number of requests waiting for other requests to finish. After this number is reached, the pool will start returning errrors when a new request is made" +msgid "" +"Maximum number of requests waiting for other requests to finish. After this " +"number is reached, the pool will start returning errrors when a new request " +"is made" msgstr "" "Maximum number of requests waiting for other requests to finish. After this " "number is reached, the pool will start returning errrors when a new request " "is made" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:pools > :federation > :recv_timeout" msgid "Timeout for the pool while gun will wait for response" msgstr "Timeout for the pool while gun will wait for response" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:pools > :federation > :size" msgid "Maximum number of concurrent requests in the pool." msgstr "Maximum number of concurrent requests in the pool." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:pools > :media" msgid "Settings for media pool." msgstr "Settings for media pool." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:pools > :media > :max_waiting" -msgid "Maximum number of requests waiting for other requests to finish. After this number is reached, the pool will start returning errrors when a new request is made" +msgid "" +"Maximum number of requests waiting for other requests to finish. After this " +"number is reached, the pool will start returning errrors when a new request " +"is made" msgstr "" "Maximum number of requests waiting for other requests to finish. After this " "number is reached, the pool will start returning errrors when a new request " "is made" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:pools > :media > :recv_timeout" msgid "Timeout for the pool while gun will wait for response" msgstr "Timeout for the pool while gun will wait for response" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:pools > :media > :size" msgid "Maximum number of concurrent requests in the pool." msgstr "Maximum number of concurrent requests in the pool." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:pools > :upload" msgid "Settings for upload pool." msgstr "Settings for upload pool." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:pools > :upload > :max_waiting" -msgid "Maximum number of requests waiting for other requests to finish. After this number is reached, the pool will start returning errrors when a new request is made" +msgid "" +"Maximum number of requests waiting for other requests to finish. After this " +"number is reached, the pool will start returning errrors when a new request " +"is made" msgstr "" "Maximum number of requests waiting for other requests to finish. After this " "number is reached, the pool will start returning errrors when a new request " "is made" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:pools > :upload > :recv_timeout" msgid "Timeout for the pool while gun will wait for response" msgstr "Timeout for the pool while gun will wait for response" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:pools > :upload > :size" msgid "Maximum number of concurrent requests in the pool." msgstr "Maximum number of concurrent requests in the pool." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:populate_hashtags_table > :fault_rate_allowance" -msgid "Max accepted rate of objects that failed in the migration. Any value from 0.0 which tolerates no errors to 1.0 which will enable the feature even if hashtags transfer failed for all records." +#, fuzzy +msgctxt "" +"config description at :pleroma-:populate_hashtags_table > :" +"fault_rate_allowance" +msgid "" +"Max accepted rate of objects that failed in the migration. Any value from " +"0.0 which tolerates no errors to 1.0 which will enable the feature even if " +"hashtags transfer failed for all records." msgstr "" "Max accepted rate of objects that failed in the migration. Any value from " "0.0 which tolerates no errors to 1.0 which will enable the feature even if " "hashtags transfer failed for all records." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:populate_hashtags_table > :sleep_interval_ms" -msgid "Sleep interval between each chunk of processed records in order to decrease the load on the system (defaults to 0 and should be keep default on most instances)." +#, fuzzy +msgctxt "" +"config description at :pleroma-:populate_hashtags_table > :sleep_interval_ms" +msgid "" +"Sleep interval between each chunk of processed records in order to decrease " +"the load on the system (defaults to 0 and should be keep default on most " +"instances)." msgstr "" "Sleep interval between each chunk of processed records in order to decrease " "the load on the system (defaults to 0 and should be keep default on most " "instances)." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:rate_limit > :app_account_creation" msgid "For registering user accounts from the same IP address" msgstr "For registering user accounts from the same IP address" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:rate_limit > :authentication" -msgid "For authentication create / password check / user existence check requests" +msgid "" +"For authentication create / password check / user existence check requests" msgstr "" "For authentication create / password check / user existence check requests" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:rate_limit > :relation_id_action" msgid "For actions on relation with a specific user (follow, unfollow)" msgstr "For actions on relation with a specific user (follow, unfollow)" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:rate_limit > :relations_actions" msgid "For actions on relationships with all users (follow, unfollow)" msgstr "For actions on relationships with all users (follow, unfollow)" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:rate_limit > :search" msgid "For the search requests (account & status search etc.)" msgstr "For the search requests (account & status search etc.)" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:rate_limit > :status_id_action" -msgid "For fav / unfav or reblog / unreblog actions on the same status by the same user" +msgid "" +"For fav / unfav or reblog / unreblog actions on the same status by the same " +"user" msgstr "" "For fav / unfav or reblog / unreblog actions on the same status by the same " "user" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:rate_limit > :statuses_actions" -msgid "For create / delete / fav / unfav / reblog / unreblog actions on any statuses" +msgid "" +"For create / delete / fav / unfav / reblog / unreblog actions on any statuses" msgstr "" "For create / delete / fav / unfav / reblog / unreblog actions on any statuses" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:rate_limit > :timeline" msgid "For requests to timelines (each timeline has it's own limiter)" msgstr "For requests to timelines (each timeline has it's own limiter)" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:restrict_unauthenticated > :activities" +#, fuzzy +msgctxt "" +"config description at :pleroma-:restrict_unauthenticated > :activities" msgid "Settings for statuses." msgstr "Settings for statuses." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:restrict_unauthenticated > :activities > :local" +#, fuzzy +msgctxt "" +"config description at :pleroma-:restrict_unauthenticated > :activities > :" +"local" msgid "Disallow view local statuses." msgstr "Disallow view local statuses." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:restrict_unauthenticated > :activities > :remote" +#, fuzzy +msgctxt "" +"config description at :pleroma-:restrict_unauthenticated > :activities > :" +"remote" msgid "Disallow view remote statuses." msgstr "Disallow view remote statuses." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:restrict_unauthenticated > :profiles" msgid "Settings for user profiles." msgstr "Settings for user profiles." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:restrict_unauthenticated > :profiles > :local" +#, fuzzy +msgctxt "" +"config description at :pleroma-:restrict_unauthenticated > :profiles > :local" msgid "Disallow view local user profiles." msgstr "Disallow view local user profiles." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:restrict_unauthenticated > :profiles > :remote" +#, fuzzy +msgctxt "" +"config description at :pleroma-:restrict_unauthenticated > :profiles > :" +"remote" msgid "Disallow view remote user profiles." msgstr "Disallow view remote user profiles." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:restrict_unauthenticated > :timelines" msgid "Settings for public and federated timelines." msgstr "Settings for public and federated timelines." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:restrict_unauthenticated > :timelines > :federated" +#, fuzzy +msgctxt "" +"config description at :pleroma-:restrict_unauthenticated > :timelines > :" +"federated" msgid "Disallow view federated timeline." msgstr "Disallow view federated timeline." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:restrict_unauthenticated > :timelines > :local" +#, fuzzy +msgctxt "" +"config description at :pleroma-:restrict_unauthenticated > :timelines > :" +"local" msgid "Disallow view public timeline." msgstr "Disallow view public timeline." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:rich_media > :enabled" msgid "Enables RichMedia parsing of URLs" msgstr "Enables RichMedia parsing of URLs" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:rich_media > :failure_backoff" -msgid "Amount of milliseconds after request failure, during which the request will not be retried." +msgid "" +"Amount of milliseconds after request failure, during which the request will " +"not be retried." msgstr "" "Amount of milliseconds after request failure, during which the request will " "not be retried." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:rich_media > :ignore_hosts" msgid "List of hosts which will be ignored by the metadata parser" msgstr "List of hosts which will be ignored by the metadata parser" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:rich_media > :ignore_tld" msgid "List TLDs (top-level domains) which will ignore for parse metadata" msgstr "List TLDs (top-level domains) which will ignore for parse metadata" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:rich_media > :parsers" -msgid "List of Rich Media parsers. Module names are shortened (removed leading `Pleroma.Web.RichMedia.Parsers.` part), but on adding custom module you need to use full name." +msgid "" +"List of Rich Media parsers. Module names are shortened (removed leading " +"`Pleroma.Web.RichMedia.Parsers.` part), but on adding custom module you need " +"to use full name." msgstr "" "List of Rich Media parsers. Module names are shortened (removed leading " "`Pleroma.Web.RichMedia.Parsers.` part), but on adding custom module you need " "to use full name." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:rich_media > :ttl_setters" -msgid "List of rich media TTL setters. Module names are shortened (removed leading `Pleroma.Web.RichMedia.Parser.` part), but on adding custom module you need to use full name." +msgid "" +"List of rich media TTL setters. Module names are shortened (removed leading " +"`Pleroma.Web.RichMedia.Parser.` part), but on adding custom module you need " +"to use full name." msgstr "" "List of rich media TTL setters. Module names are shortened (removed leading " "`Pleroma.Web.RichMedia.Parser.` part), but on adding custom module you need " "to use full name." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:shout > :enabled" msgid "Enables the backend Shoutbox chat feature." msgstr "Enables the backend Shoutbox chat feature." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:shout > :limit" msgid "Shout message character limit." msgstr "Shout message character limit." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:static_fe > :enabled" msgid "Enables the rendering of static HTML. Default: disabled." msgstr "Enables the rendering of static HTML. Default: disabled." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:streamer > :overflow_workers" msgid "Maximum number of workers created if pool is empty" msgstr "Maximum number of workers created if pool is empty" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:streamer > :workers" msgid "Number of workers to send notifications" msgstr "Number of workers to send notifications" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:uri_schemes > :valid_schemes" msgid "List of the scheme part that is considered valid to be an URL" msgstr "List of the scheme part that is considered valid to be an URL" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:web_cache_ttl > :activity_pub" -msgid "Activity pub routes (except question activities). Default: `nil` (no expiration)." +msgid "" +"Activity pub routes (except question activities). Default: `nil` (no " +"expiration)." msgstr "" "Activity pub routes (except question activities). Default: `nil` (no " "expiration)." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:web_cache_ttl > :activity_pub_question" -msgid "Activity pub routes (question activities). Default: `30_000` (30 seconds)." +#, fuzzy +msgctxt "" +"config description at :pleroma-:web_cache_ttl > :activity_pub_question" +msgid "" +"Activity pub routes (question activities). Default: `30_000` (30 seconds)." msgstr "" "Activity pub routes (question activities). Default: `30_000` (30 seconds)." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:welcome > :chat_message > :enabled" msgid "Enables sending a chat message to newly registered users" msgstr "Enables sending a chat message to newly registered users" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:welcome > :chat_message > :message" msgid "A message that will be sent to newly registered users as a chat message" -msgstr "A message that will be sent to newly registered users as a chat message" +msgstr "" +"A message that will be sent to newly registered users as a chat message" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:welcome > :chat_message > :sender_nickname" +#, fuzzy +msgctxt "" +"config description at :pleroma-:welcome > :chat_message > :sender_nickname" msgid "The nickname of the local user that sends a welcome chat message" msgstr "The nickname of the local user that sends a welcome chat message" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:welcome > :direct_message > :enabled" msgid "Enables sending a direct message to newly registered users" msgstr "Enables sending a direct message to newly registered users" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:welcome > :direct_message > :message" msgid "A message that will be sent to newly registered users" msgstr "A message that will be sent to newly registered users" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:welcome > :direct_message > :sender_nickname" +#, fuzzy +msgctxt "" +"config description at :pleroma-:welcome > :direct_message > :sender_nickname" msgid "The nickname of the local user that sends a welcome message" msgstr "The nickname of the local user that sends a welcome message" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:welcome > :email > :enabled" msgid "Enables sending an email to newly registered users" msgstr "Enables sending an email to newly registered users" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:welcome > :email > :html" -msgid "HTML content of the welcome email. EEX template with user and instance_name variables can be used." +msgid "" +"HTML content of the welcome email. EEX template with user and instance_name " +"variables can be used." msgstr "" "HTML content of the welcome email. EEX template with user and instance_name " "variables can be used." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:welcome > :email > :sender" -msgid "Email address and/or nickname that will be used to send the welcome email." +msgid "" +"Email address and/or nickname that will be used to send the welcome email." msgstr "" "Email address and/or nickname that will be used to send the welcome email." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:welcome > :email > :subject" -msgid "Subject of the welcome email. EEX template with user and instance_name variables can be used." +msgid "" +"Subject of the welcome email. EEX template with user and instance_name " +"variables can be used." msgstr "" "Subject of the welcome email. EEX template with user and instance_name " "variables can be used." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:welcome > :email > :text" -msgid "Text content of the welcome email. EEX template with user and instance_name variables can be used." +msgid "" +"Text content of the welcome email. EEX template with user and instance_name " +"variables can be used." msgstr "" "Text content of the welcome email. EEX template with user and instance_name " "variables can be used." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:workers > :retries" msgid "Max retry attempts for failed jobs, per `Oban` queue" msgstr "Max retry attempts for failed jobs, per `Oban` queue" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-ConcurrentLimiter > Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy" +#, fuzzy +msgctxt "" +"config description at :pleroma-ConcurrentLimiter > Pleroma.Web.ActivityPub." +"MRF.MediaProxyWarmingPolicy" msgid "Concurrent limits configuration for MediaProxyWarmingPolicy." msgstr "Concurrent limits configuration for MediaProxyWarmingPolicy." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-ConcurrentLimiter > Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy > :max_running" +#, fuzzy +msgctxt "" +"config description at :pleroma-ConcurrentLimiter > Pleroma.Web.ActivityPub." +"MRF.MediaProxyWarmingPolicy > :max_running" msgid "Max running concurrently jobs." msgstr "Max running concurrently jobs." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-ConcurrentLimiter > Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy > :max_waiting" +#, fuzzy +msgctxt "" +"config description at :pleroma-ConcurrentLimiter > Pleroma.Web.ActivityPub." +"MRF.MediaProxyWarmingPolicy > :max_waiting" msgid "Max waiting jobs." msgstr "Max waiting jobs." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-ConcurrentLimiter > Pleroma.Web.RichMedia.Helpers" +#, fuzzy +msgctxt "" +"config description at :pleroma-ConcurrentLimiter > Pleroma.Web.RichMedia." +"Helpers" msgid "Concurrent limits configuration for getting RichMedia for activities." msgstr "Concurrent limits configuration for getting RichMedia for activities." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-ConcurrentLimiter > Pleroma.Web.RichMedia.Helpers > :max_running" +#, fuzzy +msgctxt "" +"config description at :pleroma-ConcurrentLimiter > Pleroma.Web.RichMedia." +"Helpers > :max_running" msgid "Max running concurrently jobs." msgstr "Max running concurrently jobs." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-ConcurrentLimiter > Pleroma.Web.RichMedia.Helpers > :max_waiting" +#, fuzzy +msgctxt "" +"config description at :pleroma-ConcurrentLimiter > Pleroma.Web.RichMedia." +"Helpers > :max_waiting" msgid "Max waiting jobs." msgstr "Max waiting jobs." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Oban > :crontab" msgid "Settings for cron background jobs" msgstr "Settings for cron background jobs" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Oban > :log" msgid "Logs verbose mode" msgstr "Logs verbose mode" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Oban > :queues" -msgid "Background jobs queues (keys: queues, values: max numbers of concurrent jobs)" +msgid "" +"Background jobs queues (keys: queues, values: max numbers of concurrent jobs)" msgstr "" "Background jobs queues (keys: queues, values: max numbers of concurrent jobs)" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Oban > :queues > :activity_expiration" msgid "Activity expiration queue" msgstr "Activity expiration queue" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Oban > :queues > :attachments_cleanup" msgid "Attachment deletion queue" msgstr "Attachment deletion queue" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Oban > :queues > :background" msgid "Background queue" msgstr "Background queue" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Oban > :queues > :backup" msgid "Backup queue" msgstr "Backup queue" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Oban > :queues > :federator_incoming" msgid "Incoming federation queue" msgstr "Incoming federation queue" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Oban > :queues > :federator_outgoing" msgid "Outgoing federation queue" msgstr "Outgoing federation queue" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Oban > :queues > :mailer" msgid "Email sender queue, see Pleroma.Emails.Mailer" msgstr "Email sender queue, see Pleroma.Emails.Mailer" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Oban > :queues > :scheduled_activities" msgid "Scheduled activities queue, see Pleroma.ScheduledActivities" msgstr "Scheduled activities queue, see Pleroma.ScheduledActivities" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Oban > :queues > :transmogrifier" msgid "Transmogrifier queue" msgstr "Transmogrifier queue" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Oban > :queues > :web_push" msgid "Web push notifications queue" msgstr "Web push notifications queue" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Captcha > :enabled" msgid "Whether the captcha should be shown on registration" msgstr "Whether the captcha should be shown on registration" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Captcha > :method" msgid "The method/service to use for captcha" msgstr "The method/service to use for captcha" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Captcha > :seconds_valid" msgid "The time in seconds for which the captcha is valid" msgstr "The time in seconds for which the captcha is valid" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Captcha.Kocaptcha > :endpoint" msgid "The kocaptcha endpoint to use" msgstr "The kocaptcha endpoint to use" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Emails.Mailer > :adapter" -msgid "One of the mail adapters listed in [Swoosh documentation](https://hexdocs.pm/swoosh/Swoosh.html#module-adapters)" +msgid "" +"One of the mail adapters listed in [Swoosh documentation](https://hexdocs.pm/" +"swoosh/Swoosh.html#module-adapters)" msgstr "" "One of the mail adapters listed in [Swoosh documentation](https://hexdocs.pm/" "swoosh/Swoosh.html#module-adapters)" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SMTP-:auth" +#, fuzzy +msgctxt "" +"config description at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SMTP-:" +"auth" msgid "SMTP AUTH enforcement mode" msgstr "SMTP AUTH enforcement mode" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SMTP-:password" +#, fuzzy +msgctxt "" +"config description at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SMTP-:" +"password" msgid "SMTP AUTH password" msgstr "SMTP AUTH password" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SMTP-:port" +#, fuzzy +msgctxt "" +"config description at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SMTP-:" +"port" msgid "SMTP port" msgstr "SMTP port" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SMTP-:relay" +#, fuzzy +msgctxt "" +"config description at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SMTP-:" +"relay" msgid "Hostname or IP address" msgstr "Hostname or IP address" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SMTP-:retries" +#, fuzzy +msgctxt "" +"config description at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SMTP-:" +"retries" msgid "SMTP temporary (4xx) error retries" msgstr "SMTP temporary (4xx) error retries" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SMTP-:ssl" +#, fuzzy +msgctxt "" +"config description at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SMTP-:" +"ssl" msgid "Use Implicit SSL/TLS. e.g. port 465" msgstr "Use Implicit SSL/TLS. e.g. port 465" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SMTP-:tls" +#, fuzzy +msgctxt "" +"config description at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SMTP-:" +"tls" msgid "Explicit TLS (STARTTLS) enforcement mode" msgstr "Explicit TLS (STARTTLS) enforcement mode" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SMTP-:username" +#, fuzzy +msgctxt "" +"config description at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SMTP-:" +"username" msgid "SMTP AUTH username" msgstr "SMTP AUTH username" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-Pleroma.Emails.NewUsersDigestEmail > :enabled" +#, fuzzy +msgctxt "" +"config description at :pleroma-Pleroma.Emails.NewUsersDigestEmail > :enabled" msgid "Enables new users admin digest email when `true`" msgstr "Enables new users admin digest email when `true`" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Emails.UserEmail > :logo" -msgid "A path to a custom logo. Set it to `nil` to use the default Pleroma logo." +msgid "" +"A path to a custom logo. Set it to `nil` to use the default Pleroma logo." msgstr "" "A path to a custom logo. Set it to `nil` to use the default Pleroma logo." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Emails.UserEmail > :styling" msgid "A map with color settings for email templates." msgstr "A map with color settings for email templates." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Formatter > :class" msgid "Specify the class to be added to the generated link. Disable to clear." msgstr "Specify the class to be added to the generated link. Disable to clear." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Formatter > :extra" msgid "Link URLs with rarely used schemes (magnet, ipfs, irc, etc.)" msgstr "Link URLs with rarely used schemes (magnet, ipfs, irc, etc.)" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Formatter > :new_window" msgid "Link URLs will open in a new window/tab." msgstr "Link URLs will open in a new window/tab." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Formatter > :rel" msgid "Override the rel attribute. Disable to clear." msgstr "Override the rel attribute. Disable to clear." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Formatter > :strip_prefix" msgid "Strip the scheme prefix." msgstr "Strip the scheme prefix." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Formatter > :truncate" -msgid "Set to a number to truncate URLs longer than the number. Truncated URLs will end in `...`" +msgid "" +"Set to a number to truncate URLs longer than the number. Truncated URLs will " +"end in `...`" msgstr "" "Set to a number to truncate URLs longer than the number. Truncated URLs will " "end in `...`" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Formatter > :validate_tld" -msgid "Set to false to disable TLD validation for URLs/emails. Can be set to :no_scheme to validate TLDs only for URLs without a scheme (e.g `example.com` will be validated, but `http://example.loki` won't)" +msgid "" +"Set to false to disable TLD validation for URLs/emails. Can be set to :" +"no_scheme to validate TLDs only for URLs without a scheme (e.g `example.com` " +"will be validated, but `http://example.loki` won't)" msgstr "" "Set to false to disable TLD validation for URLs/emails. Can be set to :" "no_scheme to validate TLDs only for URLs without a scheme (e.g `example.com` " "will be validated, but `http://example.loki` won't)" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-Pleroma.ScheduledActivity > :daily_user_limit" -msgid "The number of scheduled activities a user is allowed to create in a single day. Default: 25." +#, fuzzy +msgctxt "" +"config description at :pleroma-Pleroma.ScheduledActivity > :daily_user_limit" +msgid "" +"The number of scheduled activities a user is allowed to create in a single " +"day. Default: 25." msgstr "" "The number of scheduled activities a user is allowed to create in a single " "day. Default: 25." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.ScheduledActivity > :enabled" msgid "Whether scheduled activities are sent to the job queue to be executed" msgstr "Whether scheduled activities are sent to the job queue to be executed" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-Pleroma.ScheduledActivity > :total_user_limit" -msgid "The number of scheduled activities a user is allowed to create in total. Default: 300." +#, fuzzy +msgctxt "" +"config description at :pleroma-Pleroma.ScheduledActivity > :total_user_limit" +msgid "" +"The number of scheduled activities a user is allowed to create in total. " +"Default: 300." msgstr "" "The number of scheduled activities a user is allowed to create in total. " "Default: 300." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Upload > :base_url" -msgid "Base URL for the uploads. Required if you use a CDN or host attachments under a different domain." +msgid "" +"Base URL for the uploads. Required if you use a CDN or host attachments " +"under a different domain." msgstr "" "Base URL for the uploads. Required if you use a CDN or host attachments " "under a different domain." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-Pleroma.Upload > :filename_display_max_length" +#, fuzzy +msgctxt "" +"config description at :pleroma-Pleroma.Upload > :filename_display_max_length" msgid "Set max length of a filename to display. 0 = no limit. Default: 30" msgstr "Set max length of a filename to display. 0 = no limit. Default: 30" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Upload > :filters" -msgid "List of filter modules for uploads. Module names are shortened (removed leading `Pleroma.Upload.Filter.` part), but on adding custom module you need to use full name." +msgid "" +"List of filter modules for uploads. Module names are shortened (removed " +"leading `Pleroma.Upload.Filter.` part), but on adding custom module you need " +"to use full name." msgstr "" "List of filter modules for uploads. Module names are shortened (removed " "leading `Pleroma.Upload.Filter.` part), but on adding custom module you need " "to use full name." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Upload > :link_name" -msgid "If enabled, a name parameter will be added to the URL of the upload. For example `https://instance.tld/media/imagehash.png?name=realname.png`." +msgid "" +"If enabled, a name parameter will be added to the URL of the upload. For " +"example `https://instance.tld/media/imagehash.png?name=realname.png`." msgstr "" "If enabled, a name parameter will be added to the URL of the upload. For " "example `https://instance.tld/media/imagehash.png?name=realname.png`." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Upload > :proxy_remote" -msgid "Proxy requests to the remote uploader.\n\nUseful if media upload endpoint is not internet accessible.\n" +msgid "" +"Proxy requests to the remote uploader.\n" +"\n" +"Useful if media upload endpoint is not internet accessible.\n" msgstr "" "Proxy requests to the remote uploader.\n" "\n" "Useful if media upload endpoint is not internet accessible.\n" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Upload > :uploader" msgid "Module which will be used for uploads" msgstr "Module which will be used for uploads" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-Pleroma.Upload.Filter.AnonymizeFilename > :text" -msgid "Text to replace filenames in links. If no setting, {random}.extension will be used. You can get the original filename extension by using {extension}, for example custom-file-name.{extension}." +#, fuzzy +msgctxt "" +"config description at :pleroma-Pleroma.Upload.Filter.AnonymizeFilename > :" +"text" +msgid "" +"Text to replace filenames in links. If no setting, {random}.extension will " +"be used. You can get the original filename extension by using {extension}, " +"for example custom-file-name.{extension}." msgstr "" "Text to replace filenames in links. If no setting, {random}.extension will " "be used. You can get the original filename extension by using {extension}, " "for example custom-file-name.{extension}." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Upload.Filter.Mogrify > :args" -msgid "List of actions for the mogrify command. It's possible to add self-written settings as string. For example `auto-orient, strip, {\"resize\", \"3840x1080>\"}` value will be parsed into valid list of the settings." +msgid "" +"List of actions for the mogrify command. It's possible to add self-written " +"settings as string. For example `auto-orient, strip, {\"resize\", " +"\"3840x1080>\"}` value will be parsed into valid list of the settings." msgstr "" "List of actions for the mogrify command. It's possible to add self-written " -"settings as string. For example `auto-orient, strip, {\"resize\", \"3840x1080" -">\"}` value will be parsed into valid list of the settings." +"settings as string. For example `auto-orient, strip, {\"resize\", " +"\"3840x1080>\"}` value will be parsed into valid list of the settings." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Uploaders.Local > :uploads" msgid "Path where user's uploads will be saved" msgstr "Path where user's uploads will be saved" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Uploaders.S3 > :bucket" msgid "S3 bucket" msgstr "S3 bucket" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-Pleroma.Uploaders.S3 > :bucket_namespace" +#, fuzzy +msgctxt "" +"config description at :pleroma-Pleroma.Uploaders.S3 > :bucket_namespace" msgid "S3 bucket namespace" msgstr "S3 bucket namespace" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-Pleroma.Uploaders.S3 > :streaming_enabled" -msgid "Enable streaming uploads, when enabled the file will be sent to the server in chunks as it's being read. This may be unsupported by some providers, try disabling this if you have upload problems." +#, fuzzy +msgctxt "" +"config description at :pleroma-Pleroma.Uploaders.S3 > :streaming_enabled" +msgid "" +"Enable streaming uploads, when enabled the file will be sent to the server " +"in chunks as it's being read. This may be unsupported by some providers, try " +"disabling this if you have upload problems." msgstr "" "Enable streaming uploads, when enabled the file will be sent to the server " "in chunks as it's being read. This may be unsupported by some providers, try " "disabling this if you have upload problems." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-Pleroma.Uploaders.S3 > :truncated_namespace" -msgid "If you use S3 compatible service such as Digital Ocean Spaces or CDN, set folder name or \"\" etc. For example, when using CDN to S3 virtual host format, set \"\". At this time, write CNAME to CDN in Upload base_url." +#, fuzzy +msgctxt "" +"config description at :pleroma-Pleroma.Uploaders.S3 > :truncated_namespace" +msgid "" +"If you use S3 compatible service such as Digital Ocean Spaces or CDN, set " +"folder name or \"\" etc. For example, when using CDN to S3 virtual host " +"format, set \"\". At this time, write CNAME to CDN in Upload base_url." msgstr "" "If you use S3 compatible service such as Digital Ocean Spaces or CDN, set " "folder name or \"\" etc. For example, when using CDN to S3 virtual host " "format, set \"\". At this time, write CNAME to CDN in Upload base_url." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.User > :email_blacklist" msgid "List of email domains users may not register with." msgstr "List of email domains users may not register with." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.User > :restricted_nicknames" msgid "List of nicknames users may not register with." msgstr "List of nicknames users may not register with." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.User.Backup > :limit_days" msgid "Limit user to export not more often than once per N days" msgstr "Limit user to export not more often than once per N days" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-Pleroma.User.Backup > :purge_after_days" +#, fuzzy +msgctxt "" +"config description at :pleroma-Pleroma.User.Backup > :purge_after_days" msgid "Remove backup achives after N days" msgstr "Remove backup achives after N days" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-Pleroma.Web.ApiSpec.CastAndValidate > :strict" -msgid "Enables strict input validation (useful in development, not recommended in production)" +#, fuzzy +msgctxt "" +"config description at :pleroma-Pleroma.Web.ApiSpec.CastAndValidate > :strict" +msgid "" +"Enables strict input validation (useful in development, not recommended in " +"production)" msgstr "" "Enables strict input validation (useful in development, not recommended in " "production)" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-Pleroma.Web.MediaProxy.Invalidation.Http > :headers" +#, fuzzy +msgctxt "" +"config description at :pleroma-Pleroma.Web.MediaProxy.Invalidation.Http > :" +"headers" msgid "HTTP headers of request" msgstr "HTTP headers of request" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-Pleroma.Web.MediaProxy.Invalidation.Http > :method" +#, fuzzy +msgctxt "" +"config description at :pleroma-Pleroma.Web.MediaProxy.Invalidation.Http > :" +"method" msgid "HTTP method of request. Default: :purge" msgstr "HTTP method of request. Default: :purge" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-Pleroma.Web.MediaProxy.Invalidation.Http > :options" +#, fuzzy +msgctxt "" +"config description at :pleroma-Pleroma.Web.MediaProxy.Invalidation.Http > :" +"options" msgid "Request options" msgstr "Request options" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-Pleroma.Web.MediaProxy.Invalidation.Script > :script_path" +#, fuzzy +msgctxt "" +"config description at :pleroma-Pleroma.Web.MediaProxy.Invalidation.Script > :" +"script_path" msgid "Path to executable script which will purge cached items." msgstr "Path to executable script which will purge cached items." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-Pleroma.Web.MediaProxy.Invalidation.Script > :url_format" -msgid "Optional URL format preprocessing. Only required for Apache's htcacheclean." +#, fuzzy +msgctxt "" +"config description at :pleroma-Pleroma.Web.MediaProxy.Invalidation.Script > :" +"url_format" +msgid "" +"Optional URL format preprocessing. Only required for Apache's htcacheclean." msgstr "" "Optional URL format preprocessing. Only required for Apache's htcacheclean." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Web.Metadata > :providers" msgid "List of metadata providers to enable" msgstr "List of metadata providers to enable" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Web.Metadata > :unfurl_nsfw" msgid "When enabled NSFW attachments will be shown in previews" msgstr "When enabled NSFW attachments will be shown in previews" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Web.Plugs.RemoteIp > :enabled" msgid "Enable/disable the plug. Default: disabled." msgstr "Enable/disable the plug. Default: disabled." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Web.Plugs.RemoteIp > :headers" -msgid " A list of strings naming the HTTP headers to use when deriving the true client IP. Default: `[\"x-forwarded-for\"]`.\n" +msgid "" +" A list of strings naming the HTTP headers to use when deriving the true " +"client IP. Default: `[\"x-forwarded-for\"]`.\n" msgstr "" " A list of strings naming the HTTP headers to use when deriving the true " "client IP. Default: `[\"x-forwarded-for\"]`.\n" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Web.Plugs.RemoteIp > :proxies" -msgid "A list of upstream proxy IP subnets in CIDR notation from which we will parse the content of `headers`. Defaults to `[]`. IPv4 entries without a bitmask will be assumed to be /32 and IPv6 /128." +msgid "" +"A list of upstream proxy IP subnets in CIDR notation from which we will " +"parse the content of `headers`. Defaults to `[]`. IPv4 entries without a " +"bitmask will be assumed to be /32 and IPv6 /128." msgstr "" "A list of upstream proxy IP subnets in CIDR notation from which we will " "parse the content of `headers`. Defaults to `[]`. IPv4 entries without a " "bitmask will be assumed to be /32 and IPv6 /128." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Web.Plugs.RemoteIp > :reserved" -msgid " A list of reserved IP subnets in CIDR notation which should be ignored if found in `headers`. Defaults to `[\"127.0.0.0/8\", \"::1/128\", \"fc00::/7\", \"10.0.0.0/8\", \"172.16.0.0/12\", \"192.168.0.0/16\"]`\n" +msgid "" +" A list of reserved IP subnets in CIDR notation which should be ignored if " +"found in `headers`. Defaults to `[\"127.0.0.0/8\", \"::1/128\", " +"\"fc00::/7\", \"10.0.0.0/8\", \"172.16.0.0/12\", \"192.168.0.0/16\"]`\n" msgstr "" " A list of reserved IP subnets in CIDR notation which should be ignored if " -"found in `headers`. Defaults to `[\"127.0.0.0/8\", \"::1/128\", \"fc00::/7\"" -", \"10.0.0.0/8\", \"172.16.0.0/12\", \"192.168.0.0/16\"]`\n" +"found in `headers`. Defaults to `[\"127.0.0.0/8\", \"::1/128\", " +"\"fc00::/7\", \"10.0.0.0/8\", \"172.16.0.0/12\", \"192.168.0.0/16\"]`\n" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Web.Preload > :providers" msgid "List of preload providers to enable" msgstr "List of preload providers to enable" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-Pleroma.Workers.PurgeExpiredActivity > :enabled" +#, fuzzy +msgctxt "" +"config description at :pleroma-Pleroma.Workers.PurgeExpiredActivity > :" +"enabled" msgid "Enables expired activities addition & deletion" msgstr "Enables expired activities addition & deletion" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-Pleroma.Workers.PurgeExpiredActivity > :min_lifetime" +#, fuzzy +msgctxt "" +"config description at :pleroma-Pleroma.Workers.PurgeExpiredActivity > :" +"min_lifetime" msgid "Minimum lifetime for ephemeral activity (in seconds)" msgstr "Minimum lifetime for ephemeral activity (in seconds)" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :prometheus-Pleroma.Web.Endpoint.MetricsExporter > :auth" +#, fuzzy +msgctxt "" +"config description at :prometheus-Pleroma.Web.Endpoint.MetricsExporter > :" +"auth" msgid "Enables HTTP Basic Auth for app metrics endpoint." msgstr "Enables HTTP Basic Auth for app metrics endpoint." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :prometheus-Pleroma.Web.Endpoint.MetricsExporter > :enabled" +#, fuzzy +msgctxt "" +"config description at :prometheus-Pleroma.Web.Endpoint.MetricsExporter > :" +"enabled" msgid "[Pleroma extension] Enables app metrics endpoint." msgstr "[Pleroma extension] Enables app metrics endpoint." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :prometheus-Pleroma.Web.Endpoint.MetricsExporter > :format" +#, fuzzy +msgctxt "" +"config description at :prometheus-Pleroma.Web.Endpoint.MetricsExporter > :" +"format" msgid "App metrics endpoint output format." msgstr "App metrics endpoint output format." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :prometheus-Pleroma.Web.Endpoint.MetricsExporter > :ip_whitelist" +#, fuzzy +msgctxt "" +"config description at :prometheus-Pleroma.Web.Endpoint.MetricsExporter > :" +"ip_whitelist" msgid "Restrict access of app metrics endpoint to the specified IP addresses." msgstr "Restrict access of app metrics endpoint to the specified IP addresses." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :prometheus-Pleroma.Web.Endpoint.MetricsExporter > :path" +#, fuzzy +msgctxt "" +"config description at :prometheus-Pleroma.Web.Endpoint.MetricsExporter > :" +"path" msgid "App metrics endpoint URI path." msgstr "App metrics endpoint URI path." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :quack > :level" msgid "Log level" msgstr "Log level" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :quack > :meta" msgid "Configure which metadata you want to report on" msgstr "Configure which metadata you want to report on" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :quack > :webhook_url" msgid "Configure the Slack incoming webhook" msgstr "Configure the Slack incoming webhook" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :web_push_encryption-:vapid_details > :private_key" +#, fuzzy +msgctxt "" +"config description at :web_push_encryption-:vapid_details > :private_key" msgid "VAPID private key" msgstr "VAPID private key" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :web_push_encryption-:vapid_details > :public_key" +#, fuzzy +msgctxt "" +"config description at :web_push_encryption-:vapid_details > :public_key" msgid "VAPID public key" msgstr "VAPID public key" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :web_push_encryption-:vapid_details > :subject" -msgid "A mailto link for the administrative contact. It's best if this email is not a personal email address, but rather a group email to the instance moderation team." +msgid "" +"A mailto link for the administrative contact. It's best if this email is not " +"a personal email address, but rather a group email to the instance " +"moderation team." msgstr "" "A mailto link for the administrative contact. It's best if this email is not " "a personal email address, but rather a group email to the instance " "moderation team." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :cors_plug > :credentials" msgid "Credentials" msgstr "Credentials" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :cors_plug > :expose" msgid "Expose" msgstr "Expose" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :cors_plug > :headers" msgid "Headers" msgstr "Headers" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :cors_plug > :max_age" msgid "Max age" msgstr "Max age" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :cors_plug > :methods" msgid "Methods" msgstr "Methods" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :esshd > :enabled" msgid "Enabled" msgstr "Enabled" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :esshd > :handler" msgid "Handler" msgstr "Handler" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :esshd > :password_authenticator" msgid "Password authenticator" msgstr "Password authenticator" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :esshd > :port" msgid "Port" msgstr "Port" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :esshd > :priv_dir" msgid "Priv dir" msgstr "Priv dir" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :ex_aws-:s3 > :access_key_id" msgid "Access key" msgstr "Access key" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :ex_aws-:s3 > :host" msgid "Host" msgstr "Host" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :ex_aws-:s3 > :region" msgid "Region" msgstr "Region" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :ex_aws-:s3 > :secret_access_key" msgid "Secret access key" msgstr "Secret access key" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :logger > :backends" msgid "Backends" msgstr "Backends" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :logger-:console > :format" msgid "Format" msgstr "Format" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :logger-:console > :level" msgid "Level" msgstr "Level" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :logger-:console > :metadata" msgid "Metadata" msgstr "Metadata" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :logger-:ex_syslogger > :format" msgid "Format" msgstr "Format" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :logger-:ex_syslogger > :ident" msgid "Ident" msgstr "Ident" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :logger-:ex_syslogger > :level" msgid "Level" msgstr "Level" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :logger-:ex_syslogger > :metadata" msgid "Metadata" msgstr "Metadata" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :mime > :types" msgid "Types" msgstr "Types" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :mime > :types > application/activity+json" msgid "\"application/activity+json\"" msgstr "\"application/activity+json\"" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :mime > :types > application/jrd+json" msgid "\"application/jrd+json\"" msgstr "\"application/jrd+json\"" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :mime > :types > application/ld+json" msgid "\"application/ld+json\"" msgstr "\"application/ld+json\"" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :mime > :types > application/xml" msgid "\"application/xml\"" msgstr "\"application/xml\"" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :mime > :types > application/xrd+xml" msgid "\"application/xrd+xml\"" msgstr "\"application/xrd+xml\"" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma > :admin_token" msgid "Admin token" msgstr "Admin token" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma > Pleroma.Web.Auth.Authenticator" msgid "Pleroma.Web.Auth.Authenticator" msgstr "Pleroma.Web.Auth.Authenticator" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:activitypub > :blockers_visible" msgid "Blockers visible" msgstr "Blockers visible" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:activitypub > :follow_handshake_timeout" msgid "Follow handshake timeout" msgstr "Follow handshake timeout" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:activitypub > :note_replies_output_limit" msgid "Note replies output limit" msgstr "Note replies output limit" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:activitypub > :outgoing_blocks" msgid "Outgoing blocks" msgstr "Outgoing blocks" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:activitypub > :sign_object_fetches" msgid "Sign object fetches" msgstr "Sign object fetches" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:activitypub > :unfollow_blocked" msgid "Unfollow blocked" msgstr "Unfollow blocked" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:assets > :default_mascot" msgid "Default mascot" msgstr "Default mascot" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:assets > :default_user_avatar" msgid "Default user avatar" msgstr "Default user avatar" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:assets > :mascots" msgid "Mascots" msgstr "Mascots" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:auth > :auth_template" msgid "Auth template" msgstr "Auth template" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:auth > :enforce_oauth_admin_scope_usage" msgid "Enforce OAuth admin scope usage" msgstr "Enforce OAuth admin scope usage" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:auth > :oauth_consumer_strategies" msgid "OAuth consumer strategies" msgstr "OAuth consumer strategies" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:auth > :oauth_consumer_template" msgid "OAuth consumer template" msgstr "OAuth consumer template" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:connections_pool > :connect_timeout" msgid "Connect timeout" msgstr "Connect timeout" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:connections_pool > :connection_acquisition_retries" +#, fuzzy +msgctxt "" +"config label at :pleroma-:connections_pool > :connection_acquisition_retries" msgid "Connection acquisition retries" msgstr "Connection acquisition retries" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:connections_pool > :connection_acquisition_wait" +#, fuzzy +msgctxt "" +"config label at :pleroma-:connections_pool > :connection_acquisition_wait" msgid "Connection acquisition wait" msgstr "Connection acquisition wait" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:connections_pool > :max_connections" msgid "Max connections" msgstr "Max connections" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:connections_pool > :reclaim_multiplier" msgid "Reclaim multiplier" msgstr "Reclaim multiplier" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:email_notifications > :digest" msgid "Digest" msgstr "Digest" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:email_notifications > :digest > :active" msgid "Enabled" msgstr "Enabled" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:email_notifications > :digest > :inactivity_threshold" +#, fuzzy +msgctxt "" +"config label at :pleroma-:email_notifications > :digest > :" +"inactivity_threshold" msgid "Inactivity threshold" msgstr "Inactivity threshold" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:email_notifications > :digest > :interval" msgid "Interval" msgstr "Interval" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:email_notifications > :digest > :schedule" msgid "Schedule" msgstr "Schedule" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:emoji > :default_manifest" msgid "Default manifest" msgstr "Default manifest" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:emoji > :groups" msgid "Groups" msgstr "Groups" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:emoji > :pack_extensions" msgid "Pack extensions" msgstr "Pack extensions" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:emoji > :shared_pack_cache_seconds_per_file" msgid "Shared pack cache s/file" msgstr "Shared pack cache s/file" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:emoji > :shortcode_globs" msgid "Shortcode globs" msgstr "Shortcode globs" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:features > :improved_hashtag_timeline" msgid "Improved hashtag timeline" msgstr "Improved hashtag timeline" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:feed > :post_title" msgid "Post title" msgstr "Post title" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:feed > :post_title > :max_length" msgid "Max length" msgstr "Max length" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:feed > :post_title > :omission" msgid "Omission" msgstr "Omission" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:frontend_configurations > :pleroma_fe" msgid "Pleroma FE" msgstr "Pleroma FE" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:frontend_configurations > :pleroma_fe > :alwaysShowSubjectInput" +#, fuzzy +msgctxt "" +"config label at :pleroma-:frontend_configurations > :pleroma_fe > :" +"alwaysShowSubjectInput" msgid "Always show subject input" msgstr "Always show subject input" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:frontend_configurations > :pleroma_fe > :background" +#, fuzzy +msgctxt "" +"config label at :pleroma-:frontend_configurations > :pleroma_fe > :background" msgid "Background" msgstr "Background" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:frontend_configurations > :pleroma_fe > :collapseMessageWithSubject" +#, fuzzy +msgctxt "" +"config label at :pleroma-:frontend_configurations > :pleroma_fe > :" +"collapseMessageWithSubject" msgid "Collapse message with subject" msgstr "Collapse message with subject" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:frontend_configurations > :pleroma_fe > :greentext" +#, fuzzy +msgctxt "" +"config label at :pleroma-:frontend_configurations > :pleroma_fe > :greentext" msgid "Greentext" msgstr "Greentext" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:frontend_configurations > :pleroma_fe > :hideFilteredStatuses" +#, fuzzy +msgctxt "" +"config label at :pleroma-:frontend_configurations > :pleroma_fe > :" +"hideFilteredStatuses" msgid "Hide Filtered Statuses" msgstr "Hide Filtered Statuses" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:frontend_configurations > :pleroma_fe > :hideMutedPosts" +#, fuzzy +msgctxt "" +"config label at :pleroma-:frontend_configurations > :pleroma_fe > :" +"hideMutedPosts" msgid "Hide Muted Posts" msgstr "Hide Muted Posts" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:frontend_configurations > :pleroma_fe > :hidePostStats" +#, fuzzy +msgctxt "" +"config label at :pleroma-:frontend_configurations > :pleroma_fe > :" +"hidePostStats" msgid "Hide post stats" msgstr "Hide post stats" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:frontend_configurations > :pleroma_fe > :hideSitename" +#, fuzzy +msgctxt "" +"config label at :pleroma-:frontend_configurations > :pleroma_fe > :" +"hideSitename" msgid "Hide Sitename" msgstr "Hide Sitename" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:frontend_configurations > :pleroma_fe > :hideUserStats" +#, fuzzy +msgctxt "" +"config label at :pleroma-:frontend_configurations > :pleroma_fe > :" +"hideUserStats" msgid "Hide user stats" msgstr "Hide user stats" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:frontend_configurations > :pleroma_fe > :logo" +#, fuzzy +msgctxt "" +"config label at :pleroma-:frontend_configurations > :pleroma_fe > :logo" msgid "Logo" msgstr "Logo" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:frontend_configurations > :pleroma_fe > :logoMargin" +#, fuzzy +msgctxt "" +"config label at :pleroma-:frontend_configurations > :pleroma_fe > :logoMargin" msgid "Logo margin" msgstr "Logo margin" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:frontend_configurations > :pleroma_fe > :logoMask" +#, fuzzy +msgctxt "" +"config label at :pleroma-:frontend_configurations > :pleroma_fe > :logoMask" msgid "Logo mask" msgstr "Logo mask" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:frontend_configurations > :pleroma_fe > :minimalScopesMode" +#, fuzzy +msgctxt "" +"config label at :pleroma-:frontend_configurations > :pleroma_fe > :" +"minimalScopesMode" msgid "Minimal scopes mode" msgstr "Minimal scopes mode" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:frontend_configurations > :pleroma_fe > :nsfwCensorImage" +#, fuzzy +msgctxt "" +"config label at :pleroma-:frontend_configurations > :pleroma_fe > :" +"nsfwCensorImage" msgid "NSFW Censor Image" msgstr "NSFW Censor Image" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:frontend_configurations > :pleroma_fe > :postContentType" +#, fuzzy +msgctxt "" +"config label at :pleroma-:frontend_configurations > :pleroma_fe > :" +"postContentType" msgid "Post Content Type" msgstr "Post Content Type" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:frontend_configurations > :pleroma_fe > :redirectRootLogin" +#, fuzzy +msgctxt "" +"config label at :pleroma-:frontend_configurations > :pleroma_fe > :" +"redirectRootLogin" msgid "Redirect root login" msgstr "Redirect root login" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:frontend_configurations > :pleroma_fe > :redirectRootNoLogin" +#, fuzzy +msgctxt "" +"config label at :pleroma-:frontend_configurations > :pleroma_fe > :" +"redirectRootNoLogin" msgid "Redirect root no login" msgstr "Redirect root no login" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:frontend_configurations > :pleroma_fe > :scopeCopy" +#, fuzzy +msgctxt "" +"config label at :pleroma-:frontend_configurations > :pleroma_fe > :scopeCopy" msgid "Scope copy" msgstr "Scope copy" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:frontend_configurations > :pleroma_fe > :showFeaturesPanel" +#, fuzzy +msgctxt "" +"config label at :pleroma-:frontend_configurations > :pleroma_fe > :" +"showFeaturesPanel" msgid "Show instance features panel" msgstr "Show instance features panel" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:frontend_configurations > :pleroma_fe > :showInstanceSpecificPanel" +#, fuzzy +msgctxt "" +"config label at :pleroma-:frontend_configurations > :pleroma_fe > :" +"showInstanceSpecificPanel" msgid "Show instance specific panel" msgstr "Show instance specific panel" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:frontend_configurations > :pleroma_fe > :sidebarRight" +#, fuzzy +msgctxt "" +"config label at :pleroma-:frontend_configurations > :pleroma_fe > :" +"sidebarRight" msgid "Sidebar on Right" msgstr "Sidebar on Right" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:frontend_configurations > :pleroma_fe > :subjectLineBehavior" +#, fuzzy +msgctxt "" +"config label at :pleroma-:frontend_configurations > :pleroma_fe > :" +"subjectLineBehavior" msgid "Subject line behavior" msgstr "Subject line behavior" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:frontend_configurations > :pleroma_fe > :theme" +#, fuzzy +msgctxt "" +"config label at :pleroma-:frontend_configurations > :pleroma_fe > :theme" msgid "Theme" msgstr "Theme" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:frontends > :admin" msgid "Admin" msgstr "Admin" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:frontends > :admin > name" msgid "Name" msgstr "Name" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:frontends > :admin > ref" msgid "Reference" msgstr "Reference" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:frontends > :available" msgid "Available" msgstr "Available" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:frontends > :available > build_dir" msgid "Build directory" msgstr "Build directory" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:frontends > :available > build_url" msgid "Build URL" msgstr "Build URL" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:frontends > :available > custom-http-headers" +#, fuzzy +msgctxt "" +"config label at :pleroma-:frontends > :available > custom-http-headers" msgid "Custom HTTP headers" msgstr "Custom HTTP headers" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:frontends > :available > git" msgid "Git Repository URL" msgstr "Git Repository URL" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:frontends > :available > name" msgid "Name" msgstr "Name" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:frontends > :available > ref" msgid "Reference" msgstr "Reference" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:frontends > :primary" msgid "Primary" msgstr "Primary" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:frontends > :primary > name" msgid "Name" msgstr "Name" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:frontends > :primary > ref" msgid "Reference" msgstr "Reference" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:gopher > :dstport" msgid "Dstport" msgstr "Dstport" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:gopher > :enabled" msgid "Enabled" msgstr "Enabled" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:gopher > :ip" msgid "IP" msgstr "IP" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:gopher > :port" msgid "Port" msgstr "Port" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:hackney_pools > :federation" msgid "Federation" msgstr "Federation" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:hackney_pools > :federation > :max_connections" +#, fuzzy +msgctxt "" +"config label at :pleroma-:hackney_pools > :federation > :max_connections" msgid "Max connections" msgstr "Max connections" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:hackney_pools > :federation > :timeout" msgid "Timeout" msgstr "Timeout" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:hackney_pools > :media" msgid "Media" msgstr "Media" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:hackney_pools > :media > :max_connections" msgid "Max connections" msgstr "Max connections" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:hackney_pools > :media > :timeout" msgid "Timeout" msgstr "Timeout" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:hackney_pools > :upload" msgid "Upload" msgstr "Upload" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:hackney_pools > :upload > :max_connections" msgid "Max connections" msgstr "Max connections" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:hackney_pools > :upload > :timeout" msgid "Timeout" msgstr "Timeout" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:http > :adapter" msgid "Adapter" msgstr "Adapter" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:http > :adapter > :ssl_options" msgid "SSL Options" msgstr "SSL Options" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:http > :adapter > :ssl_options > :versions" msgid "Versions" msgstr "Versions" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:http > :proxy_url" msgid "Proxy URL" msgstr "Proxy URL" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:http > :send_user_agent" msgid "Send user agent" msgstr "Send user agent" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:http > :user_agent" msgid "User agent" msgstr "User agent" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:http_security > :enabled" msgid "Enabled" msgstr "Enabled" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:http_security > :referrer_policy" msgid "Referrer policy" msgstr "Referrer policy" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:http_security > :report_uri" msgid "Report URI" msgstr "Report URI" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:http_security > :sts" msgid "STS" msgstr "STS" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:http_security > :sts_max_age" msgid "STS max age" msgstr "STS max age" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :account_activation_required" msgid "Account activation required" msgstr "Account activation required" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :account_approval_required" msgid "Account approval required" msgstr "Account approval required" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :account_field_name_length" msgid "Account field name length" msgstr "Account field name length" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :account_field_value_length" msgid "Account field value length" msgstr "Account field value length" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :allow_relay" msgid "Allow relay" msgstr "Allow relay" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :allowed_post_formats" msgid "Allowed post formats" msgstr "Allowed post formats" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :attachment_links" msgid "Attachment links" msgstr "Attachment links" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :autofollowed_nicknames" msgid "Autofollowed nicknames" msgstr "Autofollowed nicknames" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :autofollowing_nicknames" msgid "Autofollowing nicknames" msgstr "Autofollowing nicknames" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :avatar_upload_limit" msgid "Avatar upload limit" msgstr "Avatar upload limit" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :background_upload_limit" msgid "Background upload limit" msgstr "Background upload limit" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :banner_upload_limit" msgid "Banner upload limit" msgstr "Banner upload limit" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :birthday_min_age" msgid "Birthday min age" msgstr "Birthday min age" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :birthday_required" msgid "Birthday required" msgstr "Birthday required" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :cleanup_attachments" msgid "Cleanup attachments" msgstr "Cleanup attachments" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :description" msgid "Description" msgstr "Description" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :email" msgid "Admin Email Address" msgstr "Admin Email Address" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :extended_nickname_format" msgid "Extended nickname format" msgstr "Extended nickname format" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :external_user_synchronization" msgid "External user synchronization" msgstr "External user synchronization" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :federating" msgid "Federating" msgstr "Federating" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:instance > :federation_incoming_replies_max_depth" +#, fuzzy +msgctxt "" +"config label at :pleroma-:instance > :federation_incoming_replies_max_depth" msgid "Fed. incoming replies max depth" msgstr "Fed. incoming replies max depth" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:instance > :federation_reachability_timeout_days" +#, fuzzy +msgctxt "" +"config label at :pleroma-:instance > :federation_reachability_timeout_days" msgid "Fed. reachability timeout days" msgstr "Fed. reachability timeout days" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :healthcheck" msgid "Healthcheck" msgstr "Healthcheck" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :instance_thumbnail" msgid "Instance thumbnail" msgstr "Instance thumbnail" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :invites_enabled" msgid "Invites enabled" msgstr "Invites enabled" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :limit" msgid "Limit" msgstr "Limit" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :limit_to_local_content" msgid "Limit to local content" msgstr "Limit to local content" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :max_account_fields" msgid "Max account fields" msgstr "Max account fields" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :max_endorsed_users" msgid "Max endorsed users" msgstr "Max endorsed users" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :max_media_attachments" msgid "Max media attachments" msgstr "Max media attachments" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :max_pinned_statuses" msgid "Max pinned statuses" msgstr "Max pinned statuses" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :max_remote_account_fields" msgid "Max remote account fields" msgstr "Max remote account fields" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :max_report_comment_size" msgid "Max report comment size" msgstr "Max report comment size" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :multi_factor_authentication" msgid "Multi factor authentication" msgstr "Multi factor authentication" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:instance > :multi_factor_authentication > :backup_codes" +#, fuzzy +msgctxt "" +"config label at :pleroma-:instance > :multi_factor_authentication > :" +"backup_codes" msgid "Backup codes" msgstr "Backup codes" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:instance > :multi_factor_authentication > :backup_codes > :length" +#, fuzzy +msgctxt "" +"config label at :pleroma-:instance > :multi_factor_authentication > :" +"backup_codes > :length" msgid "Length" msgstr "Length" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:instance > :multi_factor_authentication > :backup_codes > :number" +#, fuzzy +msgctxt "" +"config label at :pleroma-:instance > :multi_factor_authentication > :" +"backup_codes > :number" msgid "Number" msgstr "Number" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:instance > :multi_factor_authentication > :totp" +#, fuzzy +msgctxt "" +"config label at :pleroma-:instance > :multi_factor_authentication > :totp" msgid "TOTP settings" msgstr "TOTP settings" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:instance > :multi_factor_authentication > :totp > :digits" +#, fuzzy +msgctxt "" +"config label at :pleroma-:instance > :multi_factor_authentication > :totp > :" +"digits" msgid "Digits" msgstr "Digits" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:instance > :multi_factor_authentication > :totp > :period" +#, fuzzy +msgctxt "" +"config label at :pleroma-:instance > :multi_factor_authentication > :totp > :" +"period" msgid "Period" msgstr "Period" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :name" msgid "Name" msgstr "Name" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :notify_email" msgid "Sender Email Address" msgstr "Sender Email Address" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :poll_limits" msgid "Poll limits" msgstr "Poll limits" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :poll_limits > :max_expiration" msgid "Max expiration" msgstr "Max expiration" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :poll_limits > :max_option_chars" msgid "Max option chars" msgstr "Max option chars" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :poll_limits > :max_options" msgid "Max options" msgstr "Max options" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :poll_limits > :min_expiration" msgid "Min expiration" msgstr "Min expiration" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :privileged_staff" msgid "Privileged staff" msgstr "Privileged staff" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :profile_directory" msgid "Profile directory" msgstr "Profile directory" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :public" msgid "Public" msgstr "Public" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :quarantined_instances" msgid "Quarantined instances" msgstr "Quarantined instances" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :registration_reason_length" msgid "Registration reason length" msgstr "Registration reason length" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :registrations_open" msgid "Registrations open" msgstr "Registrations open" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :remote_limit" msgid "Remote limit" msgstr "Remote limit" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :remote_post_retention_days" msgid "Remote post retention days" msgstr "Remote post retention days" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :safe_dm_mentions" msgid "Safe DM mentions" msgstr "Safe DM mentions" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :show_reactions" msgid "Show reactions" msgstr "Show reactions" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :skip_thread_containment" msgid "Skip thread containment" msgstr "Skip thread containment" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :static_dir" msgid "Static dir" msgstr "Static dir" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :upload_limit" msgid "Upload limit" msgstr "Upload limit" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :user_bio_length" msgid "User bio length" msgstr "User bio length" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :user_name_length" msgid "User name length" msgstr "User name length" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instances_favicons > :enabled" msgid "Enabled" msgstr "Enabled" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:ldap > :base" msgid "Base" msgstr "Base" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:ldap > :enabled" msgid "Enabled" msgstr "Enabled" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:ldap > :host" msgid "Host" msgstr "Host" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:ldap > :port" msgid "Port" msgstr "Port" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:ldap > :ssl" msgid "SSL" msgstr "SSL" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:ldap > :sslopts" msgid "SSL options" msgstr "SSL options" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:ldap > :sslopts > :cacertfile" msgid "Cacertfile" msgstr "Cacertfile" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:ldap > :sslopts > :verify" msgid "Verify" msgstr "Verify" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:ldap > :tls" msgid "TLS" msgstr "TLS" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:ldap > :tlsopts" msgid "TLS options" msgstr "TLS options" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:ldap > :tlsopts > :cacertfile" msgid "Cacertfile" msgstr "Cacertfile" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:ldap > :tlsopts > :verify" msgid "Verify" msgstr "Verify" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:ldap > :uid" msgid "UID" msgstr "UID" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:majic_pool > :size" msgid "Size" msgstr "Size" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:manifest > :background_color" msgid "Background color" msgstr "Background color" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:manifest > :icons" msgid "Icons" msgstr "Icons" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:manifest > :theme_color" msgid "Theme color" msgstr "Theme color" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:markup > :allow_fonts" msgid "Allow fonts" msgstr "Allow fonts" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:markup > :allow_headings" msgid "Allow headings" msgstr "Allow headings" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:markup > :allow_inline_images" msgid "Allow inline images" msgstr "Allow inline images" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:markup > :allow_tables" msgid "Allow tables" msgstr "Allow tables" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:markup > :scrub_policy" msgid "Scrub policy" msgstr "Scrub policy" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:media_preview_proxy > :enabled" msgid "Enabled" msgstr "Enabled" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:media_preview_proxy > :image_quality" msgid "Image quality" msgstr "Image quality" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:media_preview_proxy > :min_content_length" msgid "Min content length" msgstr "Min content length" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:media_preview_proxy > :thumbnail_max_height" msgid "Thumbnail max height" msgstr "Thumbnail max height" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:media_preview_proxy > :thumbnail_max_width" msgid "Thumbnail max width" msgstr "Thumbnail max width" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:media_proxy > :base_url" msgid "Base URL" msgstr "Base URL" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:media_proxy > :enabled" msgid "Enabled" msgstr "Enabled" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:media_proxy > :invalidation" msgid "Invalidation" msgstr "Invalidation" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:media_proxy > :invalidation > :enabled" msgid "Enabled" msgstr "Enabled" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:media_proxy > :invalidation > :provider" msgid "Provider" msgstr "Provider" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:media_proxy > :proxy_opts" msgid "Advanced MediaProxy Options" msgstr "Advanced MediaProxy Options" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:media_proxy > :proxy_opts > :max_body_length" +#, fuzzy +msgctxt "" +"config label at :pleroma-:media_proxy > :proxy_opts > :max_body_length" msgid "Max body length" msgstr "Max body length" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:media_proxy > :proxy_opts > :max_read_duration" +#, fuzzy +msgctxt "" +"config label at :pleroma-:media_proxy > :proxy_opts > :max_read_duration" msgid "Max read duration" msgstr "Max read duration" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:media_proxy > :proxy_opts > :redirect_on_failure" +#, fuzzy +msgctxt "" +"config label at :pleroma-:media_proxy > :proxy_opts > :redirect_on_failure" msgid "Redirect on failure" msgstr "Redirect on failure" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:media_proxy > :whitelist" msgid "Whitelist" msgstr "Whitelist" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:modules > :runtime_dir" msgid "Runtime dir" msgstr "Runtime dir" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf > :policies" msgid "Policies" msgstr "Policies" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf > :transparency" msgid "MRF transparency" msgstr "MRF transparency" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf > :transparency_exclusions" msgid "MRF transparency exclusions" msgstr "MRF transparency exclusions" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_activity_expiration > :days" msgid "Days" msgstr "Days" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_follow_bot > :follower_nickname" msgid "Follower nickname" msgstr "Follower nickname" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_hashtag > :federated_timeline_removal" msgid "Federated timeline removal" msgstr "Federated timeline removal" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_hashtag > :reject" msgid "Reject" msgstr "Reject" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_hashtag > :sensitive" msgid "Sensitive" msgstr "Sensitive" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_hellthread > :delist_threshold" msgid "Delist threshold" msgstr "Delist threshold" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_hellthread > :reject_threshold" msgid "Reject threshold" msgstr "Reject threshold" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_keyword > :federated_timeline_removal" msgid "Federated timeline removal" msgstr "Federated timeline removal" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_keyword > :reject" msgid "Reject" msgstr "Reject" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_keyword > :replace" msgid "Replace" msgstr "Replace" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_mention > :actors" msgid "Actors" msgstr "Actors" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_normalize_markup > :scrub_policy" msgid "Scrub policy" msgstr "Scrub policy" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_object_age > :actions" msgid "Actions" msgstr "Actions" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_object_age > :threshold" msgid "Threshold" msgstr "Threshold" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_rejectnonpublic > :allow_direct" msgid "Allow direct" msgstr "Allow direct" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_rejectnonpublic > :allow_followersonly" msgid "Allow followers-only" msgstr "Allow followers-only" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_simple > :accept" msgid "Accept" msgstr "Accept" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_simple > :avatar_removal" msgid "Avatar removal" msgstr "Avatar removal" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_simple > :banner_removal" msgid "Banner removal" msgstr "Banner removal" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_simple > :federated_timeline_removal" msgid "Federated timeline removal" msgstr "Federated timeline removal" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_simple > :followers_only" msgid "Followers only" msgstr "Followers only" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_simple > :media_nsfw" msgid "Media NSFW" msgstr "Media NSFW" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_simple > :media_removal" msgid "Media removal" msgstr "Media removal" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_simple > :reject" msgid "Reject" msgstr "Reject" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_simple > :reject_deletes" msgid "Reject deletes" msgstr "Reject deletes" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_simple > :report_removal" msgid "Report removal" msgstr "Report removal" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_steal_emoji > :hosts" msgid "Hosts" msgstr "Hosts" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_steal_emoji > :rejected_shortcodes" msgid "Rejected shortcodes" msgstr "Rejected shortcodes" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_steal_emoji > :size_limit" msgid "Size limit" msgstr "Size limit" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_subchain > :match_actor" msgid "Match actor" msgstr "Match actor" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_vocabulary > :accept" msgid "Accept" msgstr "Accept" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_vocabulary > :reject" msgid "Reject" msgstr "Reject" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:oauth2 > :clean_expired_tokens" msgid "Clean expired tokens" msgstr "Clean expired tokens" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:oauth2 > :issue_new_refresh_token" msgid "Issue new refresh token" msgstr "Issue new refresh token" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:oauth2 > :token_expires_in" msgid "Token expires in" msgstr "Token expires in" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:pools > :default" msgid "Default" msgstr "Default" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:pools > :default > :max_waiting" msgid "Max waiting" msgstr "Max waiting" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:pools > :default > :recv_timeout" msgid "Recv timeout" msgstr "Recv timeout" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:pools > :default > :size" msgid "Size" msgstr "Size" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:pools > :federation" msgid "Federation" msgstr "Federation" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:pools > :federation > :max_waiting" msgid "Max waiting" msgstr "Max waiting" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:pools > :federation > :recv_timeout" msgid "Recv timeout" msgstr "Recv timeout" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:pools > :federation > :size" msgid "Size" msgstr "Size" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:pools > :media" msgid "Media" msgstr "Media" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:pools > :media > :max_waiting" msgid "Max waiting" msgstr "Max waiting" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:pools > :media > :recv_timeout" msgid "Recv timeout" msgstr "Recv timeout" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:pools > :media > :size" msgid "Size" msgstr "Size" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:pools > :upload" msgid "Upload" msgstr "Upload" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:pools > :upload > :max_waiting" msgid "Max waiting" msgstr "Max waiting" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:pools > :upload > :recv_timeout" msgid "Recv timeout" msgstr "Recv timeout" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:pools > :upload > :size" msgid "Size" msgstr "Size" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:populate_hashtags_table > :fault_rate_allowance" +#, fuzzy +msgctxt "" +"config label at :pleroma-:populate_hashtags_table > :fault_rate_allowance" msgid "Fault rate allowance" msgstr "Fault rate allowance" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:populate_hashtags_table > :sleep_interval_ms" +#, fuzzy +msgctxt "" +"config label at :pleroma-:populate_hashtags_table > :sleep_interval_ms" msgid "Sleep interval ms" msgstr "Sleep interval ms" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:rate_limit > :app_account_creation" msgid "App account creation" msgstr "App account creation" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:rate_limit > :authentication" msgid "Authentication" msgstr "Authentication" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:rate_limit > :relation_id_action" msgid "Relation ID action" msgstr "Relation ID action" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:rate_limit > :relations_actions" msgid "Relations actions" msgstr "Relations actions" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:rate_limit > :search" msgid "Search" msgstr "Search" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:rate_limit > :status_id_action" msgid "Status ID action" msgstr "Status ID action" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:rate_limit > :statuses_actions" msgid "Statuses actions" msgstr "Statuses actions" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:rate_limit > :timeline" msgid "Timeline" msgstr "Timeline" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:restrict_unauthenticated > :activities" msgid "Activities" msgstr "Activities" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:restrict_unauthenticated > :activities > :local" +#, fuzzy +msgctxt "" +"config label at :pleroma-:restrict_unauthenticated > :activities > :local" msgid "Local" msgstr "Local" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:restrict_unauthenticated > :activities > :remote" +#, fuzzy +msgctxt "" +"config label at :pleroma-:restrict_unauthenticated > :activities > :remote" msgid "Remote" msgstr "Remote" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:restrict_unauthenticated > :profiles" msgid "Profiles" msgstr "Profiles" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:restrict_unauthenticated > :profiles > :local" +#, fuzzy +msgctxt "" +"config label at :pleroma-:restrict_unauthenticated > :profiles > :local" msgid "Local" msgstr "Local" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:restrict_unauthenticated > :profiles > :remote" +#, fuzzy +msgctxt "" +"config label at :pleroma-:restrict_unauthenticated > :profiles > :remote" msgid "Remote" msgstr "Remote" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:restrict_unauthenticated > :timelines" msgid "Timelines" msgstr "Timelines" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:restrict_unauthenticated > :timelines > :federated" +#, fuzzy +msgctxt "" +"config label at :pleroma-:restrict_unauthenticated > :timelines > :federated" msgid "Federated" msgstr "Federated" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:restrict_unauthenticated > :timelines > :local" +#, fuzzy +msgctxt "" +"config label at :pleroma-:restrict_unauthenticated > :timelines > :local" msgid "Local" msgstr "Local" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:rich_media > :enabled" msgid "Enabled" msgstr "Enabled" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:rich_media > :failure_backoff" msgid "Failure backoff" msgstr "Failure backoff" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:rich_media > :ignore_hosts" msgid "Ignore hosts" msgstr "Ignore hosts" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:rich_media > :ignore_tld" msgid "Ignore TLD" msgstr "Ignore TLD" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:rich_media > :parsers" msgid "Parsers" msgstr "Parsers" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:rich_media > :ttl_setters" msgid "TTL setters" msgstr "TTL setters" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:shout > :enabled" msgid "Enabled" msgstr "Enabled" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:shout > :limit" msgid "Limit" msgstr "Limit" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:static_fe > :enabled" msgid "Enabled" msgstr "Enabled" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:streamer > :overflow_workers" msgid "Overflow workers" msgstr "Overflow workers" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:streamer > :workers" msgid "Workers" msgstr "Workers" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:uri_schemes > :valid_schemes" msgid "Valid schemes" msgstr "Valid schemes" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:user > :deny_follow_blocked" msgid "Deny follow blocked" msgstr "Deny follow blocked" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:web_cache_ttl > :activity_pub" msgid "Activity pub" msgstr "Activity pub" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:web_cache_ttl > :activity_pub_question" msgid "Activity pub question" msgstr "Activity pub question" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:welcome > :chat_message" msgid "Chat message" msgstr "Chat message" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:welcome > :chat_message > :enabled" msgid "Enabled" msgstr "Enabled" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:welcome > :chat_message > :message" msgid "Message" msgstr "Message" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:welcome > :chat_message > :sender_nickname" msgid "Sender nickname" msgstr "Sender nickname" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:welcome > :direct_message" msgid "Direct message" msgstr "Direct message" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:welcome > :direct_message > :enabled" msgid "Enabled" msgstr "Enabled" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:welcome > :direct_message > :message" msgid "Message" msgstr "Message" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:welcome > :direct_message > :sender_nickname" +#, fuzzy +msgctxt "" +"config label at :pleroma-:welcome > :direct_message > :sender_nickname" msgid "Sender nickname" msgstr "Sender nickname" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:welcome > :email" msgid "Email" msgstr "Email" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:welcome > :email > :enabled" msgid "Enabled" msgstr "Enabled" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:welcome > :email > :html" msgid "Html" msgstr "Html" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:welcome > :email > :sender" msgid "Sender" msgstr "Sender" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:welcome > :email > :subject" msgid "Subject" msgstr "Subject" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:welcome > :email > :text" msgid "Text" msgstr "Text" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:workers > :retries" msgid "Retries" msgstr "Retries" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-ConcurrentLimiter > Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy" +#, fuzzy +msgctxt "" +"config label at :pleroma-ConcurrentLimiter > Pleroma.Web.ActivityPub.MRF." +"MediaProxyWarmingPolicy" msgid "Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy" msgstr "Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-ConcurrentLimiter > Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy > :max_running" +#, fuzzy +msgctxt "" +"config label at :pleroma-ConcurrentLimiter > Pleroma.Web.ActivityPub.MRF." +"MediaProxyWarmingPolicy > :max_running" msgid "Max running" msgstr "Max running" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-ConcurrentLimiter > Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy > :max_waiting" +#, fuzzy +msgctxt "" +"config label at :pleroma-ConcurrentLimiter > Pleroma.Web.ActivityPub.MRF." +"MediaProxyWarmingPolicy > :max_waiting" msgid "Max waiting" msgstr "Max waiting" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-ConcurrentLimiter > Pleroma.Web.RichMedia.Helpers" +#, fuzzy +msgctxt "" +"config label at :pleroma-ConcurrentLimiter > Pleroma.Web.RichMedia.Helpers" msgid "Pleroma.Web.RichMedia.Helpers" msgstr "Pleroma.Web.RichMedia.Helpers" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-ConcurrentLimiter > Pleroma.Web.RichMedia.Helpers > :max_running" +#, fuzzy +msgctxt "" +"config label at :pleroma-ConcurrentLimiter > Pleroma.Web.RichMedia.Helpers " +"> :max_running" msgid "Max running" msgstr "Max running" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-ConcurrentLimiter > Pleroma.Web.RichMedia.Helpers > :max_waiting" +#, fuzzy +msgctxt "" +"config label at :pleroma-ConcurrentLimiter > Pleroma.Web.RichMedia.Helpers " +"> :max_waiting" msgid "Max waiting" msgstr "Max waiting" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Oban > :crontab" msgid "Crontab" msgstr "Crontab" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Oban > :log" msgid "Log" msgstr "Log" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Oban > :queues" msgid "Queues" msgstr "Queues" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Oban > :queues > :activity_expiration" msgid "Activity expiration" msgstr "Activity expiration" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Oban > :queues > :attachments_cleanup" msgid "Attachments cleanup" msgstr "Attachments cleanup" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Oban > :queues > :background" msgid "Background" msgstr "Background" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Oban > :queues > :backup" msgid "Backup" msgstr "Backup" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Oban > :queues > :federator_incoming" msgid "Federator incoming" msgstr "Federator incoming" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Oban > :queues > :federator_outgoing" msgid "Federator outgoing" msgstr "Federator outgoing" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Oban > :queues > :mailer" msgid "Mailer" msgstr "Mailer" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Oban > :queues > :scheduled_activities" msgid "Scheduled activities" msgstr "Scheduled activities" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Oban > :queues > :transmogrifier" msgid "Transmogrifier" msgstr "Transmogrifier" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Oban > :queues > :web_push" msgid "Web push" msgstr "Web push" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Captcha > :enabled" msgid "Enabled" msgstr "Enabled" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Captcha > :method" msgid "Method" msgstr "Method" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Captcha > :seconds_valid" msgid "Seconds valid" msgstr "Seconds valid" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Captcha.Kocaptcha > :endpoint" msgid "Endpoint" msgstr "Endpoint" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Emails.Mailer > :adapter" msgid "Adapter" msgstr "Adapter" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Emails.Mailer > :enabled" msgid "Mailer Enabled" msgstr "Mailer Enabled" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.AmazonSES-:access_key" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.AmazonSES-:" +"access_key" msgid "AWS Access Key" msgstr "AWS Access Key" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.AmazonSES-:region" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.AmazonSES-:" +"region" msgid "AWS Region" msgstr "AWS Region" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.AmazonSES-:secret" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.AmazonSES-:" +"secret" msgid "AWS Secret Key" msgstr "AWS Secret Key" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.Dyn-:api_key" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.Dyn-:api_key" msgid "Dyn API Key" msgstr "Dyn API Key" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.Gmail-:access_token" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.Gmail-:" +"access_token" msgid "GMail API Access Token" msgstr "GMail API Access Token" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.Mailgun-:api_key" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.Mailgun-:" +"api_key" msgid "Mailgun API Key" msgstr "Mailgun API Key" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.Mailgun-:domain" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.Mailgun-:" +"domain" msgid "Domain" msgstr "Domain" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.Mailjet-:api_key" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.Mailjet-:" +"api_key" msgid "MailJet Public API Key" msgstr "MailJet Public API Key" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.Mailjet-:secret" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.Mailjet-:" +"secret" msgid "MailJet Private API Key" msgstr "MailJet Private API Key" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.Mandrill-:api_key" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.Mandrill-:" +"api_key" msgid "Mandrill API Key" msgstr "Mandrill API Key" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.Postmark-:api_key" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.Postmark-:" +"api_key" msgid "Postmark API Key" msgstr "Postmark API Key" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SMTP-:auth" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SMTP-:auth" msgid "AUTH Mode" msgstr "AUTH Mode" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SMTP-:password" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SMTP-:" +"password" msgid "Password" msgstr "Password" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SMTP-:port" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SMTP-:port" msgid "Port" msgstr "Port" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SMTP-:relay" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SMTP-:relay" msgid "Relay" msgstr "Relay" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SMTP-:retries" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SMTP-:" +"retries" msgid "Retries" msgstr "Retries" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SMTP-:ssl" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SMTP-:ssl" msgid "Use SSL" msgstr "Use SSL" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SMTP-:tls" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SMTP-:tls" msgid "STARTTLS Mode" msgstr "STARTTLS Mode" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SMTP-:username" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SMTP-:" +"username" msgid "Username" msgstr "Username" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.Sendgrid-:api_key" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.Sendgrid-:" +"api_key" msgid "SendGrid API Key" msgstr "SendGrid API Key" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.Sendmail-:cmd_args" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.Sendmail-:" +"cmd_args" msgid "Cmd args" msgstr "Cmd args" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.Sendmail-:cmd_path" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.Sendmail-:" +"cmd_path" msgid "Cmd path" msgstr "Cmd path" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.Sendmail-:qmail" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.Sendmail-:" +"qmail" msgid "Qmail compat mode" msgstr "Qmail compat mode" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SocketLabs-:api_key" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SocketLabs-:" +"api_key" msgid "SocketLabs API Key" msgstr "SocketLabs API Key" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SocketLabs-:server_id" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SocketLabs-:" +"server_id" msgid "Server ID" msgstr "Server ID" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SparkPost-:api_key" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SparkPost-:" +"api_key" msgid "SparkPost API key" msgstr "SparkPost API key" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SparkPost-:endpoint" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SparkPost-:" +"endpoint" msgid "Endpoint" msgstr "Endpoint" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Emails.NewUsersDigestEmail > :enabled" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Emails.NewUsersDigestEmail > :enabled" msgid "Enabled" msgstr "Enabled" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Emails.UserEmail > :logo" msgid "Logo" msgstr "Logo" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Emails.UserEmail > :styling" msgid "Styling" msgstr "Styling" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Emails.UserEmail > :styling > :background_color" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Emails.UserEmail > :styling > :" +"background_color" msgid "Background color" msgstr "Background color" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Emails.UserEmail > :styling > :content_background_color" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Emails.UserEmail > :styling > :" +"content_background_color" msgid "Content background color" msgstr "Content background color" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Emails.UserEmail > :styling > :header_color" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Emails.UserEmail > :styling > :header_color" msgid "Header color" msgstr "Header color" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Emails.UserEmail > :styling > :link_color" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Emails.UserEmail > :styling > :link_color" msgid "Link color" msgstr "Link color" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Emails.UserEmail > :styling > :text_color" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Emails.UserEmail > :styling > :text_color" msgid "Text color" msgstr "Text color" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Emails.UserEmail > :styling > :text_muted_color" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Emails.UserEmail > :styling > :" +"text_muted_color" msgid "Text muted color" msgstr "Text muted color" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Formatter > :class" msgid "Class" msgstr "Class" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Formatter > :extra" msgid "Extra" msgstr "Extra" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Formatter > :new_window" msgid "New window" msgstr "New window" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Formatter > :rel" msgid "Rel" msgstr "Rel" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Formatter > :strip_prefix" msgid "Strip prefix" msgstr "Strip prefix" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Formatter > :truncate" msgid "Truncate" msgstr "Truncate" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Formatter > :validate_tld" msgid "Validate tld" msgstr "Validate tld" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.ScheduledActivity > :daily_user_limit" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.ScheduledActivity > :daily_user_limit" msgid "Daily user limit" msgstr "Daily user limit" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.ScheduledActivity > :enabled" msgid "Enabled" msgstr "Enabled" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.ScheduledActivity > :total_user_limit" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.ScheduledActivity > :total_user_limit" msgid "Total user limit" msgstr "Total user limit" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Upload > :base_url" msgid "Base URL" msgstr "Base URL" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Upload > :filename_display_max_length" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Upload > :filename_display_max_length" msgid "Filename display max length" msgstr "Filename display max length" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Upload > :filters" msgid "Filters" msgstr "Filters" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Upload > :link_name" msgid "Link name" msgstr "Link name" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Upload > :proxy_remote" msgid "Proxy remote" msgstr "Proxy remote" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Upload > :uploader" msgid "Uploader" msgstr "Uploader" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Upload.Filter.AnonymizeFilename > :text" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Upload.Filter.AnonymizeFilename > :text" msgid "Text" msgstr "Text" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Upload.Filter.Mogrify > :args" msgid "Args" msgstr "Args" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Uploaders.Local > :uploads" msgid "Uploads" msgstr "Uploads" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Uploaders.S3 > :bucket" msgid "Bucket" msgstr "Bucket" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Uploaders.S3 > :bucket_namespace" msgid "Bucket namespace" msgstr "Bucket namespace" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Uploaders.S3 > :streaming_enabled" msgid "Streaming enabled" msgstr "Streaming enabled" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Uploaders.S3 > :truncated_namespace" msgid "Truncated namespace" msgstr "Truncated namespace" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.User > :email_blacklist" msgid "Email blacklist" msgstr "Email blacklist" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.User > :restricted_nicknames" msgid "Restricted nicknames" msgstr "Restricted nicknames" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.User.Backup > :limit_days" msgid "Limit days" msgstr "Limit days" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.User.Backup > :purge_after_days" msgid "Purge after days" msgstr "Purge after days" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Web.ApiSpec.CastAndValidate > :strict" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Web.ApiSpec.CastAndValidate > :strict" msgid "Strict" msgstr "Strict" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Web.MediaProxy.Invalidation.Http > :headers" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Web.MediaProxy.Invalidation.Http > :headers" msgid "Headers" msgstr "Headers" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Web.MediaProxy.Invalidation.Http > :method" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Web.MediaProxy.Invalidation.Http > :method" msgid "Method" msgstr "Method" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Web.MediaProxy.Invalidation.Http > :options" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Web.MediaProxy.Invalidation.Http > :options" msgid "Options" msgstr "Options" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Web.MediaProxy.Invalidation.Http > :options > :params" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Web.MediaProxy.Invalidation.Http > :options " +"> :params" msgid "Params" msgstr "Params" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Web.MediaProxy.Invalidation.Script > :script_path" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Web.MediaProxy.Invalidation.Script > :" +"script_path" msgid "Script path" msgstr "Script path" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Web.MediaProxy.Invalidation.Script > :url_format" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Web.MediaProxy.Invalidation.Script > :" +"url_format" msgid "URL Format" msgstr "URL Format" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Web.Metadata > :providers" msgid "Providers" msgstr "Providers" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Web.Metadata > :unfurl_nsfw" msgid "Unfurl NSFW" msgstr "Unfurl NSFW" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Web.Plugs.RemoteIp > :enabled" msgid "Enabled" msgstr "Enabled" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Web.Plugs.RemoteIp > :headers" msgid "Headers" msgstr "Headers" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Web.Plugs.RemoteIp > :proxies" msgid "Proxies" msgstr "Proxies" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Web.Plugs.RemoteIp > :reserved" msgid "Reserved" msgstr "Reserved" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Web.Preload > :providers" msgid "Providers" msgstr "Providers" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Workers.PurgeExpiredActivity > :enabled" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Workers.PurgeExpiredActivity > :enabled" msgid "Enabled" msgstr "Enabled" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Workers.PurgeExpiredActivity > :min_lifetime" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Workers.PurgeExpiredActivity > :min_lifetime" msgid "Min lifetime" msgstr "Min lifetime" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :prometheus-Pleroma.Web.Endpoint.MetricsExporter > :auth" +#, fuzzy +msgctxt "" +"config label at :prometheus-Pleroma.Web.Endpoint.MetricsExporter > :auth" msgid "Auth" msgstr "Auth" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :prometheus-Pleroma.Web.Endpoint.MetricsExporter > :enabled" +#, fuzzy +msgctxt "" +"config label at :prometheus-Pleroma.Web.Endpoint.MetricsExporter > :enabled" msgid "Enabled" msgstr "Enabled" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :prometheus-Pleroma.Web.Endpoint.MetricsExporter > :format" +#, fuzzy +msgctxt "" +"config label at :prometheus-Pleroma.Web.Endpoint.MetricsExporter > :format" msgid "Format" msgstr "Format" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :prometheus-Pleroma.Web.Endpoint.MetricsExporter > :ip_whitelist" +#, fuzzy +msgctxt "" +"config label at :prometheus-Pleroma.Web.Endpoint.MetricsExporter > :" +"ip_whitelist" msgid "IP Whitelist" msgstr "IP Whitelist" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :prometheus-Pleroma.Web.Endpoint.MetricsExporter > :path" +#, fuzzy +msgctxt "" +"config label at :prometheus-Pleroma.Web.Endpoint.MetricsExporter > :path" msgid "Path" msgstr "Path" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :quack > :level" msgid "Level" msgstr "Level" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :quack > :meta" msgid "Meta" msgstr "Meta" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :quack > :webhook_url" msgid "Webhook URL" msgstr "Webhook URL" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :web_push_encryption-:vapid_details > :private_key" msgid "Private key" msgstr "Private key" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :web_push_encryption-:vapid_details > :public_key" msgid "Public key" msgstr "Public key" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :web_push_encryption-:vapid_details > :subject" msgid "Subject" msgstr "Subject" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:activitypub > :authorized_fetch_mode" msgid "Require HTTP signatures for AP fetches" msgstr "Require HTTP signatures for AP fetches" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :short_description" -msgid "Shorter version of instance description. It can be seen on `/api/v1/instance`" +msgid "" +"Shorter version of instance description. It can be seen on `/api/v1/instance`" msgstr "" "Shorter version of instance description. It can be seen on `/api/v1/instance`" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:activitypub > :authorized_fetch_mode" msgid "Authorized fetch mode" msgstr "Authorized fetch mode" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :short_description" msgid "Short description" msgstr "Short description" diff --git a/priv/gettext/nl/LC_MESSAGES/config_descriptions.po b/priv/gettext/nl/LC_MESSAGES/config_descriptions.po index 8ce06bf38..1770b9bfa 100644 --- a/priv/gettext/nl/LC_MESSAGES/config_descriptions.po +++ b/priv/gettext/nl/LC_MESSAGES/config_descriptions.po @@ -5,8 +5,8 @@ msgstr "" "POT-Creation-Date: 2022-08-06 21:54+0000\n" "PO-Revision-Date: 2022-08-06 21:55+0000\n" "Last-Translator: Anonymous \n" -"Language-Team: Dutch \n" +"Language-Team: Dutch \n" "Language: nl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -14,40 +14,47 @@ msgstr "" "Plural-Forms: nplurals=2; plural=n != 1;\n" "X-Generator: Weblate 4.13.1\n" -## This file is a PO Template file. -## -## "msgid"s here are often extracted from source code. -## Add new translations manually only if they're dynamic -## translations that can't be statically extracted. -## -## Run "mix gettext.extract" to bring this file up to -## date. Leave "msgstr"s empty as changing them here has no -## effect: edit them in PO (.po) files instead. +# # This file is a PO Template file. +# # +# # "msgid"s here are often extracted from source code. +# # Add new translations manually only if they're dynamic +# # translations that can't be statically extracted. +# # +# # Run "mix gettext.extract" to bring this file up to +# # date. Leave "msgstr"s empty as changing them here has no +# # effect: edit them in PO (.po) files instead. #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :esshd" -msgid "Before enabling this you must add :esshd to mix.exs as one of the extra_applications and generate host keys in your priv dir with ssh-keygen -m PEM -N \"\" -b 2048 -t rsa -f ssh_host_rsa_key" +msgid "" +"Before enabling this you must add :esshd to mix.exs as one of the " +"extra_applications and generate host keys in your priv dir with ssh-keygen -" +"m PEM -N \"\" -b 2048 -t rsa -f ssh_host_rsa_key" msgstr "" "Before enabling this you must add :esshd to mix.exs as one of the " "extra_applications and generate host keys in your priv dir with ssh-keygen -" "m PEM -N \"\" -b 2048 -t rsa -f ssh_host_rsa_key" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :logger" msgid "Logger-related settings" msgstr "Logger-related settings" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :mime" msgid "Mime Types settings" msgstr "Mime Types settings" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma" -msgid "Allows setting a token that can be used to authenticate requests with admin privileges without a normal user account token. Append the `admin_token` parameter to requests to utilize it. (Please reconsider using HTTP Basic Auth or OAuth-based authentication if possible)" +msgid "" +"Allows setting a token that can be used to authenticate requests with admin " +"privileges without a normal user account token. Append the `admin_token` " +"parameter to requests to utilize it. (Please reconsider using HTTP Basic " +"Auth or OAuth-based authentication if possible)" msgstr "" "Allows setting a token that can be used to authenticate requests with admin " "privileges without a normal user account token. Append the `admin_token` " @@ -55,119 +62,125 @@ msgstr "" "Auth or OAuth-based authentication if possible)" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma" msgid "Authenticator" msgstr "Authenticator" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :quack" msgid "Quack-related settings" msgstr "Quack-related settings" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :cors_plug" msgid "CORS plug config" msgstr "CORS plug config" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :esshd" msgid "ESSHD" msgstr "ESSHD" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :logger" msgid "Logger" msgstr "Logger" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :mime" msgid "Mime Types" msgstr "Mime Types" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma" msgid "Pleroma Admin Token" msgstr "Pleroma Admin Token" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma" msgid "Pleroma Authenticator" msgstr "Pleroma Authenticator" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :quack" msgid "Quack Logger" msgstr "Quack Logger" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :logger-:console" msgid "Console logger settings" msgstr "Console logger settings" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :logger-:ex_syslogger" msgid "ExSyslogger-related settings" msgstr "ExSyslogger-related settings" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:activitypub" msgid "ActivityPub-related settings" msgstr "ActivityPub-related settings" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:assets" -msgid "This section configures assets to be used with various frontends. Currently the only option relates to mascots on the mastodon frontend" +msgid "" +"This section configures assets to be used with various frontends. Currently " +"the only option relates to mascots on the mastodon frontend" msgstr "" "This section configures assets to be used with various frontends. Currently " "the only option relates to mascots on the mastodon frontend" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:auth" msgid "Authentication / authorization settings" msgstr "Authentication / authorization settings" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:connections_pool" msgid "Advanced settings for `Gun` connections pool" msgstr "Advanced settings for `Gun` connections pool" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:email_notifications" msgid "Email notifications settings" msgstr "Email notifications settings" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:features" msgid "Customizable features" msgstr "Customizable features" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:feed" msgid "Configure feed rendering" msgstr "Configure feed rendering" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:frontend_configurations" -msgid "This form can be used to configure a keyword list that keeps the configuration data for any kind of frontend. By default, settings for pleroma_fe are configured. If you want to add your own configuration your settings all fields must be complete." +msgid "" +"This form can be used to configure a keyword list that keeps the " +"configuration data for any kind of frontend. By default, settings for " +"pleroma_fe are configured. If you want to add your own configuration your " +"settings all fields must be complete." msgstr "" "This form can be used to configure a keyword list that keeps the " "configuration data for any kind of frontend. By default, settings for " @@ -175,51 +188,56 @@ msgstr "" "settings all fields must be complete." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:frontends" msgid "Installed frontends management" msgstr "Installed frontends management" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:gopher" msgid "Gopher settings" msgstr "Gopher settings" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:hackney_pools" msgid "Advanced settings for `Hackney` connections pools" msgstr "Advanced settings for `Hackney` connections pools" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:http" msgid "HTTP settings" msgstr "HTTP settings" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:http_security" msgid "HTTP security settings" msgstr "HTTP security settings" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance" msgid "Instance-related settings" msgstr "Instance-related settings" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instances_favicons" msgid "Control favicons for instances" msgstr "Control favicons for instances" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:ldap" -msgid "Use LDAP for user authentication. When a user logs in to the Pleroma instance, the name and password will be verified by trying to authenticate (bind) to a LDAP server. If a user exists in the LDAP directory but there is no account with the same name yet on the Pleroma instance then a new Pleroma account will be created with the same name as the LDAP user name." +msgid "" +"Use LDAP for user authentication. When a user logs in to the Pleroma " +"instance, the name and password will be verified by trying to authenticate " +"(bind) to a LDAP server. If a user exists in the LDAP directory but there is " +"no account with the same name yet on the Pleroma instance then a new Pleroma " +"account will be created with the same name as the LDAP user name." msgstr "" "Use LDAP for user authentication. When a user logs in to the Pleroma " "instance, the name and password will be verified by trying to authenticate " @@ -228,340 +246,378 @@ msgstr "" "account will be created with the same name as the LDAP user name." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:majic_pool" msgid "Majic/libmagic configuration" msgstr "Majic/libmagic configuration" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:manifest" -msgid "This section describe PWA manifest instance-specific values. Currently this option relate only for MastoFE." +msgid "" +"This section describe PWA manifest instance-specific values. Currently this " +"option relate only for MastoFE." msgstr "" "This section describe PWA manifest instance-specific values. Currently this " "option relate only for MastoFE." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:media_preview_proxy" msgid "Media preview proxy" msgstr "Media preview proxy" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:media_proxy" msgid "Media proxy" msgstr "Media proxy" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:modules" msgid "Custom Runtime Modules" msgstr "Custom Runtime Modules" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf" msgid "General MRF settings" msgstr "General MRF settings" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_activity_expiration" msgid "Adds automatic expiration to all local activities" msgstr "Adds automatic expiration to all local activities" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_follow_bot" msgid "Automatically follows newly discovered accounts." msgstr "Automatically follows newly discovered accounts." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_hashtag" -msgid "Reject, TWKN-remove or Set-Sensitive messsages with specific hashtags (without the leading #)\n\nNote: This MRF Policy is always enabled, if you want to disable it you have to set empty lists.\n" +msgid "" +"Reject, TWKN-remove or Set-Sensitive messsages with specific hashtags " +"(without the leading #)\n" +"\n" +"Note: This MRF Policy is always enabled, if you want to disable it you have " +"to set empty lists.\n" msgstr "" -"Reject, TWKN-remove or Set-Sensitive messsages with specific hashtags (" -"without the leading #)\n" +"Reject, TWKN-remove or Set-Sensitive messsages with specific hashtags " +"(without the leading #)\n" "\n" "Note: This MRF Policy is always enabled, if you want to disable it you have " "to set empty lists.\n" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_hellthread" msgid "Block messages with excessive user mentions" msgstr "Block messages with excessive user mentions" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_keyword" -msgid "Reject or Word-Replace messages matching a keyword or [Regex](https://hexdocs.pm/elixir/Regex.html)." +msgid "" +"Reject or Word-Replace messages matching a keyword or [Regex](https://" +"hexdocs.pm/elixir/Regex.html)." msgstr "" -"Reject or Word-Replace messages matching a keyword or [Regex](https://hexdocs" -".pm/elixir/Regex.html)." +"Reject or Word-Replace messages matching a keyword or [Regex](https://" +"hexdocs.pm/elixir/Regex.html)." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_mention" msgid "Block messages which mention a specific user" msgstr "Block messages which mention a specific user" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_normalize_markup" msgid "MRF NormalizeMarkup settings. Scrub configured hypertext markup." msgstr "MRF NormalizeMarkup settings. Scrub configured hypertext markup." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_object_age" -msgid "Rejects or delists posts based on their timestamp deviance from your server's clock." +msgid "" +"Rejects or delists posts based on their timestamp deviance from your " +"server's clock." msgstr "" "Rejects or delists posts based on their timestamp deviance from your " "server's clock." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_rejectnonpublic" msgid "RejectNonPublic drops posts with non-public visibility settings." msgstr "RejectNonPublic drops posts with non-public visibility settings." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_simple" msgid "Simple ingress policies" msgstr "Simple ingress policies" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_steal_emoji" msgid "Steals emojis from selected instances when it sees them." msgstr "Steals emojis from selected instances when it sees them." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_subchain" -msgid "This policy processes messages through an alternate pipeline when a given message matches certain criteria. All criteria are configured as a map of regular expressions to lists of policy modules." +msgid "" +"This policy processes messages through an alternate pipeline when a given " +"message matches certain criteria. All criteria are configured as a map of " +"regular expressions to lists of policy modules." msgstr "" "This policy processes messages through an alternate pipeline when a given " "message matches certain criteria. All criteria are configured as a map of " "regular expressions to lists of policy modules." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_vocabulary" msgid "Filter messages which belong to certain activity vocabularies" msgstr "Filter messages which belong to certain activity vocabularies" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:oauth2" msgid "Configure OAuth 2 provider capabilities" msgstr "Configure OAuth 2 provider capabilities" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:pools" msgid "Advanced settings for `Gun` workers pools" msgstr "Advanced settings for `Gun` workers pools" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:populate_hashtags_table" msgid "`populate_hashtags_table` background migration settings" msgstr "`populate_hashtags_table` background migration settings" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:rate_limit" -msgid "Rate limit settings. This is an advanced feature enabled only for :authentication by default." +msgid "" +"Rate limit settings. This is an advanced feature enabled only for :" +"authentication by default." msgstr "" "Rate limit settings. This is an advanced feature enabled only for :" "authentication by default." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:restrict_unauthenticated" -msgid "Disallow viewing timelines, user profiles and statuses for unauthenticated users." +msgid "" +"Disallow viewing timelines, user profiles and statuses for unauthenticated " +"users." msgstr "" "Disallow viewing timelines, user profiles and statuses for unauthenticated " "users." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:rich_media" -msgid "If enabled the instance will parse metadata from attached links to generate link previews" +msgid "" +"If enabled the instance will parse metadata from attached links to generate " +"link previews" msgstr "" "If enabled the instance will parse metadata from attached links to generate " "link previews" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:shout" msgid "Pleroma shout settings" msgstr "Pleroma shout settings" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:static_fe" -msgid "Render profiles and posts using server-generated HTML that is viewable without using JavaScript" +msgid "" +"Render profiles and posts using server-generated HTML that is viewable " +"without using JavaScript" msgstr "" "Render profiles and posts using server-generated HTML that is viewable " "without using JavaScript" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:streamer" msgid "Settings for notifications streamer" msgstr "Settings for notifications streamer" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:uri_schemes" msgid "URI schemes related settings" msgstr "URI schemes related settings" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:web_cache_ttl" -msgid "The expiration time for the web responses cache. Values should be in milliseconds or `nil` to disable expiration." +msgid "" +"The expiration time for the web responses cache. Values should be in " +"milliseconds or `nil` to disable expiration." msgstr "" "The expiration time for the web responses cache. Values should be in " "milliseconds or `nil` to disable expiration." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:welcome" msgid "Welcome messages settings" msgstr "Welcome messages settings" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:workers" msgid "Includes custom worker options not interpretable directly by `Oban`" msgstr "Includes custom worker options not interpretable directly by `Oban`" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-ConcurrentLimiter" msgid "Limits configuration for background tasks." msgstr "Limits configuration for background tasks." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Oban" -msgid "[Oban](https://github.com/sorentwo/oban) asynchronous job processor configuration." +msgid "" +"[Oban](https://github.com/sorentwo/oban) asynchronous job processor " +"configuration." msgstr "" "[Oban](https://github.com/sorentwo/oban) asynchronous job processor " "configuration." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Captcha" msgid "Captcha-related settings" msgstr "Captcha-related settings" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Captcha.Kocaptcha" -msgid "Kocaptcha is a very simple captcha service with a single API endpoint, the source code is here: https://github.com/koto-bank/kocaptcha. The default endpoint (https://captcha.kotobank.ch) is hosted by the developer." +msgid "" +"Kocaptcha is a very simple captcha service with a single API endpoint, the " +"source code is here: https://github.com/koto-bank/kocaptcha. The default " +"endpoint (https://captcha.kotobank.ch) is hosted by the developer." msgstr "" "Kocaptcha is a very simple captcha service with a single API endpoint, the " "source code is here: https://github.com/koto-bank/kocaptcha. The default " "endpoint (https://captcha.kotobank.ch) is hosted by the developer." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Emails.Mailer" msgid "Mailer-related settings" msgstr "Mailer-related settings" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Emails.NewUsersDigestEmail" msgid "New users admin email digest" msgstr "New users admin email digest" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Emails.UserEmail" msgid "Email template settings" msgstr "Email template settings" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Formatter" -msgid "Configuration for Pleroma's link formatter which parses mentions, hashtags, and URLs." +msgid "" +"Configuration for Pleroma's link formatter which parses mentions, hashtags, " +"and URLs." msgstr "" "Configuration for Pleroma's link formatter which parses mentions, hashtags, " "and URLs." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.ScheduledActivity" msgid "Scheduled activities settings" msgstr "Scheduled activities settings" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Upload" msgid "Upload general settings" msgstr "Upload general settings" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-Pleroma.Upload.Filter.AnonymizeFilename" +#, fuzzy +msgctxt "" +"config description at :pleroma-Pleroma.Upload.Filter.AnonymizeFilename" msgid "Filter replaces the filename of the upload" msgstr "Filter replaces the filename of the upload" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Upload.Filter.Mogrify" msgid "Uploads mogrify filter settings" msgstr "Uploads mogrify filter settings" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Uploaders.Local" msgid "Local uploader-related settings" msgstr "Local uploader-related settings" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Uploaders.S3" msgid "S3 uploader-related settings" msgstr "S3 uploader-related settings" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.User.Backup" msgid "Account Backup" msgstr "Account Backup" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-Pleroma.Web.MediaProxy.Invalidation.Http" +#, fuzzy +msgctxt "" +"config description at :pleroma-Pleroma.Web.MediaProxy.Invalidation.Http" msgid "HTTP invalidate settings" msgstr "HTTP invalidate settings" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-Pleroma.Web.MediaProxy.Invalidation.Script" +#, fuzzy +msgctxt "" +"config description at :pleroma-Pleroma.Web.MediaProxy.Invalidation.Script" msgid "Invalidation script settings" msgstr "Invalidation script settings" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Web.Metadata" msgid "Metadata-related settings" msgstr "Metadata-related settings" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Web.Plugs.RemoteIp" -msgid "`Pleroma.Web.Plugs.RemoteIp` is a shim to call [`RemoteIp`](https://git.pleroma.social/pleroma/remote_ip) but with runtime configuration.\n**If your instance is not behind at least one reverse proxy, you should not enable this plug.**\n" +msgid "" +"`Pleroma.Web.Plugs.RemoteIp` is a shim to call [`RemoteIp`](https://git." +"pleroma.social/pleroma/remote_ip) but with runtime configuration.\n" +"**If your instance is not behind at least one reverse proxy, you should not " +"enable this plug.**\n" msgstr "" "`Pleroma.Web.Plugs.RemoteIp` is a shim to call [`RemoteIp`](https://git." "pleroma.social/pleroma/remote_ip) but with runtime configuration.\n" @@ -569,676 +625,697 @@ msgstr "" "enable this plug.**\n" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Web.Preload" msgid "Preload-related settings" msgstr "Preload-related settings" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Workers.PurgeExpiredActivity" msgid "Expired activities settings" msgstr "Expired activities settings" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :prometheus-Pleroma.Web.Endpoint.MetricsExporter" +#, fuzzy +msgctxt "" +"config description at :prometheus-Pleroma.Web.Endpoint.MetricsExporter" msgid "Prometheus app metrics endpoint configuration" msgstr "Prometheus app metrics endpoint configuration" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :web_push_encryption-:vapid_details" -msgid "Web Push Notifications configuration. You can use the mix task mix web_push.gen.keypair to generate it." +msgid "" +"Web Push Notifications configuration. You can use the mix task mix web_push." +"gen.keypair to generate it." msgstr "" -"Web Push Notifications configuration. You can use the mix task mix " -"web_push.gen.keypair to generate it." +"Web Push Notifications configuration. You can use the mix task mix web_push." +"gen.keypair to generate it." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :ex_aws-:s3" msgid "S3" msgstr "S3" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :logger-:console" msgid "Console Logger" msgstr "Console Logger" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :logger-:ex_syslogger" msgid "ExSyslogger" msgstr "ExSyslogger" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:activitypub" msgid "ActivityPub" msgstr "ActivityPub" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:assets" msgid "Assets" msgstr "Assets" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:auth" msgid "Auth" msgstr "Auth" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:connections_pool" msgid "Connections pool" msgstr "Connections pool" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:email_notifications" msgid "Email notifications" msgstr "Email notifications" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:emoji" msgid "Emoji" msgstr "Emoji" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:features" msgid "Features" msgstr "Features" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:feed" msgid "Feed" msgstr "Feed" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:frontend_configurations" msgid "Frontend configurations" msgstr "Frontend configurations" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:frontends" msgid "Frontends" msgstr "Frontends" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:gopher" msgid "Gopher" msgstr "Gopher" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:hackney_pools" msgid "Hackney pools" msgstr "Hackney pools" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:http" msgid "HTTP" msgstr "HTTP" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:http_security" msgid "HTTP security" msgstr "HTTP security" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance" msgid "Instance" msgstr "Instance" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instances_favicons" msgid "Instances favicons" msgstr "Instances favicons" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:ldap" msgid "LDAP" msgstr "LDAP" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:majic_pool" msgid "Majic pool" msgstr "Majic pool" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:manifest" msgid "Manifest" msgstr "Manifest" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:markup" msgid "Markup Settings" msgstr "Markup Settings" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:media_preview_proxy" msgid "Media preview proxy" msgstr "Media preview proxy" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:media_proxy" msgid "Media proxy" msgstr "Media proxy" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:modules" msgid "Modules" msgstr "Modules" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf" msgid "MRF" msgstr "MRF" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_activity_expiration" msgid "MRF Activity Expiration Policy" msgstr "MRF Activity Expiration Policy" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_follow_bot" msgid "MRF FollowBot Policy" msgstr "MRF FollowBot Policy" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_hashtag" msgid "MRF Hashtag" msgstr "MRF Hashtag" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_hellthread" msgid "MRF Hellthread" msgstr "MRF Hellthread" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_keyword" msgid "MRF Keyword" msgstr "MRF Keyword" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_mention" msgid "MRF Mention" msgstr "MRF Mention" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_normalize_markup" msgid "MRF Normalize Markup" msgstr "MRF Normalize Markup" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_object_age" msgid "MRF Object Age" msgstr "MRF Object Age" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_rejectnonpublic" msgid "MRF Reject Non Public" msgstr "MRF Reject Non Public" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_simple" msgid "MRF Simple" msgstr "MRF Simple" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_steal_emoji" msgid "MRF Emojis" msgstr "MRF Emojis" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_subchain" msgid "MRF Subchain" msgstr "MRF Subchain" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_vocabulary" msgid "MRF Vocabulary" msgstr "MRF Vocabulary" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:oauth2" msgid "OAuth2" msgstr "OAuth2" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:pools" msgid "Pools" msgstr "Pools" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:populate_hashtags_table" msgid "Populate hashtags table" msgstr "Populate hashtags table" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:rate_limit" msgid "Rate limit" msgstr "Rate limit" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:restrict_unauthenticated" msgid "Restrict Unauthenticated" msgstr "Restrict Unauthenticated" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:rich_media" msgid "Rich media" msgstr "Rich media" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:shout" msgid "Shout" msgstr "Shout" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:static_fe" msgid "Static FE" msgstr "Static FE" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:streamer" msgid "Streamer" msgstr "Streamer" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:uri_schemes" msgid "URI Schemes" msgstr "URI Schemes" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:user" msgid "User" msgstr "User" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:web_cache_ttl" msgid "Web cache TTL" msgstr "Web cache TTL" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:welcome" msgid "Welcome" msgstr "Welcome" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:workers" msgid "Workers" msgstr "Workers" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-ConcurrentLimiter" msgid "ConcurrentLimiter" msgstr "ConcurrentLimiter" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Oban" msgid "Oban" msgstr "Oban" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Captcha" msgid "Pleroma.Captcha" msgstr "Pleroma.Captcha" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Captcha.Kocaptcha" msgid "Pleroma.Captcha.Kocaptcha" msgstr "Pleroma.Captcha.Kocaptcha" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Emails.Mailer" msgid "Pleroma.Emails.Mailer" msgstr "Pleroma.Emails.Mailer" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Emails.NewUsersDigestEmail" msgid "Pleroma.Emails.NewUsersDigestEmail" msgstr "Pleroma.Emails.NewUsersDigestEmail" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Emails.UserEmail" msgid "Pleroma.Emails.UserEmail" msgstr "Pleroma.Emails.UserEmail" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Formatter" msgid "Linkify" msgstr "Linkify" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.ScheduledActivity" msgid "Pleroma.ScheduledActivity" msgstr "Pleroma.ScheduledActivity" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Upload" msgid "Pleroma.Upload" msgstr "Pleroma.Upload" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Upload.Filter.AnonymizeFilename" msgid "Pleroma.Upload.Filter.AnonymizeFilename" msgstr "Pleroma.Upload.Filter.AnonymizeFilename" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Upload.Filter.Mogrify" msgid "Pleroma.Upload.Filter.Mogrify" msgstr "Pleroma.Upload.Filter.Mogrify" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Uploaders.Local" msgid "Pleroma.Uploaders.Local" msgstr "Pleroma.Uploaders.Local" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Uploaders.S3" msgid "Pleroma.Uploaders.S3" msgstr "Pleroma.Uploaders.S3" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.User" msgid "Pleroma.User" msgstr "Pleroma.User" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.User.Backup" msgid "Pleroma.User.Backup" msgstr "Pleroma.User.Backup" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Web.ApiSpec.CastAndValidate" msgid "Pleroma.Web.ApiSpec.CastAndValidate" msgstr "Pleroma.Web.ApiSpec.CastAndValidate" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Web.MediaProxy.Invalidation.Http" msgid "Pleroma.Web.MediaProxy.Invalidation.Http" msgstr "Pleroma.Web.MediaProxy.Invalidation.Http" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Web.MediaProxy.Invalidation.Script" msgid "Pleroma.Web.MediaProxy.Invalidation.Script" msgstr "Pleroma.Web.MediaProxy.Invalidation.Script" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Web.Metadata" msgid "Pleroma.Web.Metadata" msgstr "Pleroma.Web.Metadata" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Web.Plugs.RemoteIp" msgid "Pleroma.Web.Plugs.RemoteIp" msgstr "Pleroma.Web.Plugs.RemoteIp" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Web.Preload" msgid "Pleroma.Web.Preload" msgstr "Pleroma.Web.Preload" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Workers.PurgeExpiredActivity" msgid "Pleroma.Workers.PurgeExpiredActivity" msgstr "Pleroma.Workers.PurgeExpiredActivity" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :prometheus-Pleroma.Web.Endpoint.MetricsExporter" msgid "Pleroma.Web.Endpoint.MetricsExporter" msgstr "Pleroma.Web.Endpoint.MetricsExporter" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :web_push_encryption-:vapid_details" msgid "Vapid Details" msgstr "Vapid Details" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :esshd > :enabled" msgid "Enables SSH" msgstr "Enables SSH" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :esshd > :handler" msgid "Handler module" msgstr "Handler module" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :esshd > :password_authenticator" msgid "Authenticator module" msgstr "Authenticator module" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :esshd > :port" msgid "Port to connect" msgstr "Port to connect" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :esshd > :priv_dir" msgid "Dir with SSH keys" msgstr "Dir with SSH keys" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :ex_aws-:s3 > :access_key_id" msgid "S3 access key ID" msgstr "S3 access key ID" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :ex_aws-:s3 > :host" msgid "S3 host" msgstr "S3 host" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :ex_aws-:s3 > :region" msgid "S3 region (for AWS)" msgstr "S3 region (for AWS)" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :ex_aws-:s3 > :secret_access_key" msgid "Secret access key" msgstr "Secret access key" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :logger > :backends" -msgid "Where logs will be sent, :console - send logs to stdout, { ExSyslogger, :ex_syslogger } - to syslog, Quack.Logger - to Slack." +msgid "" +"Where logs will be sent, :console - send logs to stdout, { ExSyslogger, :" +"ex_syslogger } - to syslog, Quack.Logger - to Slack." msgstr "" "Where logs will be sent, :console - send logs to stdout, { ExSyslogger, :" "ex_syslogger } - to syslog, Quack.Logger - to Slack." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :logger-:console > :format" msgid "Default: \"$date $time [$level] $levelpad$node $metadata $message\"" msgstr "Default: \"$date $time [$level] $levelpad$node $metadata $message\"" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :logger-:console > :level" msgid "Log level" msgstr "Log level" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :logger-:ex_syslogger > :format" msgid "Default: \"$date $time [$level] $levelpad$node $metadata $message\"" msgstr "Default: \"$date $time [$level] $levelpad$node $metadata $message\"" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :logger-:ex_syslogger > :ident" -msgid "A string that's prepended to every message, and is typically set to the app name" +msgid "" +"A string that's prepended to every message, and is typically set to the app " +"name" msgstr "" "A string that's prepended to every message, and is typically set to the app " "name" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :logger-:ex_syslogger > :level" msgid "Log level" msgstr "Log level" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma > :admin_token" msgid "Admin token" msgstr "Admin token" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:activitypub > :blockers_visible" msgid "Whether a user can see someone who has blocked them" msgstr "Whether a user can see someone who has blocked them" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:activitypub > :follow_handshake_timeout" +#, fuzzy +msgctxt "" +"config description at :pleroma-:activitypub > :follow_handshake_timeout" msgid "Following handshake timeout" msgstr "Following handshake timeout" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:activitypub > :note_replies_output_limit" -msgid "The number of Note replies' URIs to be included with outgoing federation (`5` to match Mastodon hardcoded value, `0` to disable the output)" +#, fuzzy +msgctxt "" +"config description at :pleroma-:activitypub > :note_replies_output_limit" +msgid "" +"The number of Note replies' URIs to be included with outgoing federation " +"(`5` to match Mastodon hardcoded value, `0` to disable the output)" msgstr "" -"The number of Note replies' URIs to be included with outgoing federation (`5`" -" to match Mastodon hardcoded value, `0` to disable the output)" +"The number of Note replies' URIs to be included with outgoing federation " +"(`5` to match Mastodon hardcoded value, `0` to disable the output)" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:activitypub > :outgoing_blocks" msgid "Whether to federate blocks to other instances" msgstr "Whether to federate blocks to other instances" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:activitypub > :sign_object_fetches" msgid "Sign object fetches with HTTP signatures" msgstr "Sign object fetches with HTTP signatures" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:activitypub > :unfollow_blocked" msgid "Whether blocks result in people getting unfollowed" msgstr "Whether blocks result in people getting unfollowed" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:assets > :default_mascot" -msgid "This will be used as the default mascot on MastoFE. Default: `:pleroma_fox_tan`" +msgid "" +"This will be used as the default mascot on MastoFE. Default: `:" +"pleroma_fox_tan`" msgstr "" -"This will be used as the default mascot on MastoFE. Default: " -"`:pleroma_fox_tan`" +"This will be used as the default mascot on MastoFE. Default: `:" +"pleroma_fox_tan`" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:assets > :default_user_avatar" msgid "URL of the default user avatar" msgstr "URL of the default user avatar" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:assets > :mascots" -msgid "Keyword of mascots, each element must contain both an URL and a mime_type key" +msgid "" +"Keyword of mascots, each element must contain both an URL and a mime_type key" msgstr "" "Keyword of mascots, each element must contain both an URL and a mime_type key" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:auth > :auth_template" -msgid "Authentication form template. By default it's `show.html` which corresponds to `lib/pleroma/web/templates/o_auth/o_auth/show.html.ee`." +msgid "" +"Authentication form template. By default it's `show.html` which corresponds " +"to `lib/pleroma/web/templates/o_auth/o_auth/show.html.ee`." msgstr "" "Authentication form template. By default it's `show.html` which corresponds " "to `lib/pleroma/web/templates/o_auth/o_auth/show.html.ee`." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:auth > :enforce_oauth_admin_scope_usage" -msgid "OAuth admin scope requirement toggle. If enabled, admin actions explicitly demand admin OAuth scope(s) presence in OAuth token (client app must support admin scopes). If disabled and token doesn't have admin scope(s), `is_admin` user flag grants access to admin-specific actions." +#, fuzzy +msgctxt "" +"config description at :pleroma-:auth > :enforce_oauth_admin_scope_usage" +msgid "" +"OAuth admin scope requirement toggle. If enabled, admin actions explicitly " +"demand admin OAuth scope(s) presence in OAuth token (client app must support " +"admin scopes). If disabled and token doesn't have admin scope(s), `is_admin` " +"user flag grants access to admin-specific actions." msgstr "" "OAuth admin scope requirement toggle. If enabled, admin actions explicitly " "demand admin OAuth scope(s) presence in OAuth token (client app must support " @@ -1246,57 +1323,78 @@ msgstr "" "user flag grants access to admin-specific actions." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:auth > :oauth_consumer_strategies" -msgid "The list of enabled OAuth consumer strategies. By default it's set by OAUTH_CONSUMER_STRATEGIES environment variable. Each entry in this space-delimited string should be of format \"strategy\" or \"strategy:dependency\" (e.g. twitter or keycloak:ueberauth_keycloak_strategy in case dependency is named differently than ueberauth_)." +msgid "" +"The list of enabled OAuth consumer strategies. By default it's set by " +"OAUTH_CONSUMER_STRATEGIES environment variable. Each entry in this space-" +"delimited string should be of format \"strategy\" or \"strategy:dependency" +"\" (e.g. twitter or keycloak:ueberauth_keycloak_strategy in case dependency " +"is named differently than ueberauth_)." msgstr "" "The list of enabled OAuth consumer strategies. By default it's set by " "OAUTH_CONSUMER_STRATEGIES environment variable. Each entry in this space-" -"delimited string should be of format \"strategy\" or \"strategy:dependency\" " -"(e.g. twitter or keycloak:ueberauth_keycloak_strategy in case dependency is " -"named differently than ueberauth_)." +"delimited string should be of format \"strategy\" or \"strategy:dependency" +"\" (e.g. twitter or keycloak:ueberauth_keycloak_strategy in case dependency " +"is named differently than ueberauth_)." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:auth > :oauth_consumer_template" -msgid "OAuth consumer mode authentication form template. By default it's `consumer.html` which corresponds to `lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex`." +msgid "" +"OAuth consumer mode authentication form template. By default it's `consumer." +"html` which corresponds to `lib/pleroma/web/templates/o_auth/o_auth/consumer." +"html.eex`." msgstr "" "OAuth consumer mode authentication form template. By default it's `consumer." "html` which corresponds to `lib/pleroma/web/templates/o_auth/o_auth/consumer." "html.eex`." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:connections_pool > :connect_timeout" msgid "Timeout while `gun` will wait until connection is up. Default: 5000ms." msgstr "Timeout while `gun` will wait until connection is up. Default: 5000ms." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:connections_pool > :connection_acquisition_retries" -msgid "Number of attempts to acquire the connection from the pool if it is overloaded. Default: 5" +#, fuzzy +msgctxt "" +"config description at :pleroma-:connections_pool > :" +"connection_acquisition_retries" +msgid "" +"Number of attempts to acquire the connection from the pool if it is " +"overloaded. Default: 5" msgstr "" "Number of attempts to acquire the connection from the pool if it is " "overloaded. Default: 5" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:connections_pool > :connection_acquisition_wait" -msgid "Timeout to acquire a connection from pool. The total max time is this value multiplied by the number of retries. Default: 250ms." +#, fuzzy +msgctxt "" +"config description at :pleroma-:connections_pool > :" +"connection_acquisition_wait" +msgid "" +"Timeout to acquire a connection from pool. The total max time is this value " +"multiplied by the number of retries. Default: 250ms." msgstr "" "Timeout to acquire a connection from pool. The total max time is this value " "multiplied by the number of retries. Default: 250ms." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:connections_pool > :max_connections" msgid "Maximum number of connections in the pool. Default: 250 connections." msgstr "Maximum number of connections in the pool. Default: 250 connections." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:connections_pool > :reclaim_multiplier" -msgid "Multiplier for the number of idle connection to be reclaimed if the pool is full. For example if the pool maxes out at 250 connections and this setting is set to 0.3, the pool will reclaim at most 75 idle connections if it's overloaded. Default: 0.1" +#, fuzzy +msgctxt "" +"config description at :pleroma-:connections_pool > :reclaim_multiplier" +msgid "" +"Multiplier for the number of idle connection to be reclaimed if the pool is " +"full. For example if the pool maxes out at 250 connections and this setting " +"is set to 0.3, the pool will reclaim at most 75 idle connections if it's " +"overloaded. Default: 0.1" msgstr "" "Multiplier for the number of idle connection to be reclaimed if the pool is " "full. For example if the pool maxes out at 250 connections and this setting " @@ -1304,249 +1402,333 @@ msgstr "" "overloaded. Default: 0.1" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:email_notifications > :digest" -msgid "emails of \"what you've missed\" for users who have been inactive for a while" +msgid "" +"emails of \"what you've missed\" for users who have been inactive for a while" msgstr "" "emails of \"what you've missed\" for users who have been inactive for a while" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:email_notifications > :digest > :active" +#, fuzzy +msgctxt "" +"config description at :pleroma-:email_notifications > :digest > :active" msgid "Globally enable or disable digest emails" msgstr "Globally enable or disable digest emails" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:email_notifications > :digest > :inactivity_threshold" +#, fuzzy +msgctxt "" +"config description at :pleroma-:email_notifications > :digest > :" +"inactivity_threshold" msgid "Minimum user inactivity threshold" msgstr "Minimum user inactivity threshold" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:email_notifications > :digest > :interval" +#, fuzzy +msgctxt "" +"config description at :pleroma-:email_notifications > :digest > :interval" msgid "Minimum interval between digest emails to one user" msgstr "Minimum interval between digest emails to one user" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:email_notifications > :digest > :schedule" -msgid "When to send digest email, in crontab format. \"0 0 0\" is the default, meaning \"once a week at midnight on Sunday morning\"." +#, fuzzy +msgctxt "" +"config description at :pleroma-:email_notifications > :digest > :schedule" +msgid "" +"When to send digest email, in crontab format. \"0 0 0\" is the default, " +"meaning \"once a week at midnight on Sunday morning\"." msgstr "" "When to send digest email, in crontab format. \"0 0 0\" is the default, " "meaning \"once a week at midnight on Sunday morning\"." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:emoji > :default_manifest" -msgid "Location of the JSON-manifest. This manifest contains information about the emoji-packs you can download. Currently only one manifest can be added (no arrays)." +msgid "" +"Location of the JSON-manifest. This manifest contains information about the " +"emoji-packs you can download. Currently only one manifest can be added (no " +"arrays)." msgstr "" "Location of the JSON-manifest. This manifest contains information about the " "emoji-packs you can download. Currently only one manifest can be added (no " "arrays)." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:emoji > :groups" -msgid "Emojis are ordered in groups (tags). This is an array of key-value pairs where the key is the group name and the value is the location or array of locations. * can be used as a wildcard." +msgid "" +"Emojis are ordered in groups (tags). This is an array of key-value pairs " +"where the key is the group name and the value is the location or array of " +"locations. * can be used as a wildcard." msgstr "" "Emojis are ordered in groups (tags). This is an array of key-value pairs " "where the key is the group name and the value is the location or array of " "locations. * can be used as a wildcard." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:emoji > :pack_extensions" -msgid "A list of file extensions for emojis, when no emoji.txt for a pack is present" +msgid "" +"A list of file extensions for emojis, when no emoji.txt for a pack is present" msgstr "" "A list of file extensions for emojis, when no emoji.txt for a pack is present" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:emoji > :shortcode_globs" msgid "Location of custom emoji files. * can be used as a wildcard." msgstr "Location of custom emoji files. * can be used as a wildcard." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:features > :improved_hashtag_timeline" -msgid "Setting to force toggle / force disable improved hashtags timeline. `:enabled` forces hashtags to be fetched from `hashtags` table for hashtags timeline. `:disabled` forces object-embedded hashtags to be used (slower). Keep it `:auto` for automatic behaviour (it is auto-set to `:enabled` [unless overridden] when HashtagsTableMigrator completes)." -msgstr "" -"Setting to force toggle / force disable improved hashtags timeline. " -"`:enabled` forces hashtags to be fetched from `hashtags` table for hashtags " +msgid "" +"Setting to force toggle / force disable improved hashtags timeline. `:" +"enabled` forces hashtags to be fetched from `hashtags` table for hashtags " "timeline. `:disabled` forces object-embedded hashtags to be used (slower). " -"Keep it `:auto` for automatic behaviour (it is auto-set to `:enabled` [" -"unless overridden] when HashtagsTableMigrator completes)." +"Keep it `:auto` for automatic behaviour (it is auto-set to `:enabled` " +"[unless overridden] when HashtagsTableMigrator completes)." +msgstr "" +"Setting to force toggle / force disable improved hashtags timeline. `:" +"enabled` forces hashtags to be fetched from `hashtags` table for hashtags " +"timeline. `:disabled` forces object-embedded hashtags to be used (slower). " +"Keep it `:auto` for automatic behaviour (it is auto-set to `:enabled` " +"[unless overridden] when HashtagsTableMigrator completes)." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:feed > :post_title" msgid "Configure title rendering" msgstr "Configure title rendering" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:feed > :post_title > :max_length" msgid "Maximum number of characters before truncating title" msgstr "Maximum number of characters before truncating title" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:feed > :post_title > :omission" msgid "Replacement which will be used after truncating string" msgstr "Replacement which will be used after truncating string" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:frontend_configurations > :pleroma_fe" msgid "Settings for Pleroma FE" msgstr "Settings for Pleroma FE" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:frontend_configurations > :pleroma_fe > :alwaysShowSubjectInput" +#, fuzzy +msgctxt "" +"config description at :pleroma-:frontend_configurations > :pleroma_fe > :" +"alwaysShowSubjectInput" msgid "When disabled, auto-hide the subject field if it's empty" msgstr "When disabled, auto-hide the subject field if it's empty" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:frontend_configurations > :pleroma_fe > :background" -msgid "URL of the background, unless viewing a user profile with a background that is set" +#, fuzzy +msgctxt "" +"config description at :pleroma-:frontend_configurations > :pleroma_fe > :" +"background" +msgid "" +"URL of the background, unless viewing a user profile with a background that " +"is set" msgstr "" "URL of the background, unless viewing a user profile with a background that " "is set" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:frontend_configurations > :pleroma_fe > :collapseMessageWithSubject" -msgid "When a message has a subject (aka Content Warning), collapse it by default" +#, fuzzy +msgctxt "" +"config description at :pleroma-:frontend_configurations > :pleroma_fe > :" +"collapseMessageWithSubject" +msgid "" +"When a message has a subject (aka Content Warning), collapse it by default" msgstr "" "When a message has a subject (aka Content Warning), collapse it by default" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:frontend_configurations > :pleroma_fe > :greentext" +#, fuzzy +msgctxt "" +"config description at :pleroma-:frontend_configurations > :pleroma_fe > :" +"greentext" msgid "Enables green text on lines prefixed with the > character" msgstr "Enables green text on lines prefixed with the > character" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:frontend_configurations > :pleroma_fe > :hideFilteredStatuses" +#, fuzzy +msgctxt "" +"config description at :pleroma-:frontend_configurations > :pleroma_fe > :" +"hideFilteredStatuses" msgid "Hides filtered statuses from timelines" msgstr "Hides filtered statuses from timelines" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:frontend_configurations > :pleroma_fe > :hideMutedPosts" +#, fuzzy +msgctxt "" +"config description at :pleroma-:frontend_configurations > :pleroma_fe > :" +"hideMutedPosts" msgid "Hides muted statuses from timelines" msgstr "Hides muted statuses from timelines" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:frontend_configurations > :pleroma_fe > :hidePostStats" +#, fuzzy +msgctxt "" +"config description at :pleroma-:frontend_configurations > :pleroma_fe > :" +"hidePostStats" msgid "Hide notices statistics (repeats, favorites, ...)" msgstr "Hide notices statistics (repeats, favorites, ...)" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:frontend_configurations > :pleroma_fe > :hideSitename" +#, fuzzy +msgctxt "" +"config description at :pleroma-:frontend_configurations > :pleroma_fe > :" +"hideSitename" msgid "Hides instance name from PleromaFE banner" msgstr "Hides instance name from PleromaFE banner" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:frontend_configurations > :pleroma_fe > :hideUserStats" -msgid "Hide profile statistics (posts, posts per day, followers, followings, ...)" +#, fuzzy +msgctxt "" +"config description at :pleroma-:frontend_configurations > :pleroma_fe > :" +"hideUserStats" +msgid "" +"Hide profile statistics (posts, posts per day, followers, followings, ...)" msgstr "" "Hide profile statistics (posts, posts per day, followers, followings, ...)" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:frontend_configurations > :pleroma_fe > :logo" +#, fuzzy +msgctxt "" +"config description at :pleroma-:frontend_configurations > :pleroma_fe > :logo" msgid "URL of the logo, defaults to Pleroma's logo" msgstr "URL of the logo, defaults to Pleroma's logo" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:frontend_configurations > :pleroma_fe > :logoMargin" -msgid "Allows you to adjust vertical margins between logo boundary and navbar borders. The idea is that to have logo's image without any extra margins and instead adjust them to your need in layout." +#, fuzzy +msgctxt "" +"config description at :pleroma-:frontend_configurations > :pleroma_fe > :" +"logoMargin" +msgid "" +"Allows you to adjust vertical margins between logo boundary and navbar " +"borders. The idea is that to have logo's image without any extra margins and " +"instead adjust them to your need in layout." msgstr "" "Allows you to adjust vertical margins between logo boundary and navbar " "borders. The idea is that to have logo's image without any extra margins and " "instead adjust them to your need in layout." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:frontend_configurations > :pleroma_fe > :logoMask" -msgid "By default it assumes logo used will be monochrome with alpha channel to be compatible with both light and dark themes. If you want a colorful logo you must disable logoMask." +#, fuzzy +msgctxt "" +"config description at :pleroma-:frontend_configurations > :pleroma_fe > :" +"logoMask" +msgid "" +"By default it assumes logo used will be monochrome with alpha channel to be " +"compatible with both light and dark themes. If you want a colorful logo you " +"must disable logoMask." msgstr "" "By default it assumes logo used will be monochrome with alpha channel to be " "compatible with both light and dark themes. If you want a colorful logo you " "must disable logoMask." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:frontend_configurations > :pleroma_fe > :minimalScopesMode" -msgid "Limit scope selection to Direct, User default, and Scope of post replying to. Also prevents replying to a DM with a public post from PleromaFE." +#, fuzzy +msgctxt "" +"config description at :pleroma-:frontend_configurations > :pleroma_fe > :" +"minimalScopesMode" +msgid "" +"Limit scope selection to Direct, User default, and Scope of post replying " +"to. Also prevents replying to a DM with a public post from PleromaFE." msgstr "" "Limit scope selection to Direct, User default, and Scope of post replying " "to. Also prevents replying to a DM with a public post from PleromaFE." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:frontend_configurations > :pleroma_fe > :nsfwCensorImage" -msgid "URL of the image to use for hiding NSFW media attachments in the timeline" +#, fuzzy +msgctxt "" +"config description at :pleroma-:frontend_configurations > :pleroma_fe > :" +"nsfwCensorImage" +msgid "" +"URL of the image to use for hiding NSFW media attachments in the timeline" msgstr "" "URL of the image to use for hiding NSFW media attachments in the timeline" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:frontend_configurations > :pleroma_fe > :postContentType" +#, fuzzy +msgctxt "" +"config description at :pleroma-:frontend_configurations > :pleroma_fe > :" +"postContentType" msgid "Default post formatting option" msgstr "Default post formatting option" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:frontend_configurations > :pleroma_fe > :redirectRootLogin" +#, fuzzy +msgctxt "" +"config description at :pleroma-:frontend_configurations > :pleroma_fe > :" +"redirectRootLogin" msgid "Relative URL which indicates where to redirect when a user is logged in" -msgstr "Relative URL which indicates where to redirect when a user is logged in" +msgstr "" +"Relative URL which indicates where to redirect when a user is logged in" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:frontend_configurations > :pleroma_fe > :redirectRootNoLogin" -msgid "Relative URL which indicates where to redirect when a user isn't logged in" +#, fuzzy +msgctxt "" +"config description at :pleroma-:frontend_configurations > :pleroma_fe > :" +"redirectRootNoLogin" +msgid "" +"Relative URL which indicates where to redirect when a user isn't logged in" msgstr "" "Relative URL which indicates where to redirect when a user isn't logged in" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:frontend_configurations > :pleroma_fe > :scopeCopy" +#, fuzzy +msgctxt "" +"config description at :pleroma-:frontend_configurations > :pleroma_fe > :" +"scopeCopy" msgid "Copy the scope (private/unlisted/public) in replies to posts by default" -msgstr "Copy the scope (private/unlisted/public) in replies to posts by default" +msgstr "" +"Copy the scope (private/unlisted/public) in replies to posts by default" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:frontend_configurations > :pleroma_fe > :showFeaturesPanel" -msgid "Enables panel displaying functionality of the instance on the About page" +#, fuzzy +msgctxt "" +"config description at :pleroma-:frontend_configurations > :pleroma_fe > :" +"showFeaturesPanel" +msgid "" +"Enables panel displaying functionality of the instance on the About page" msgstr "" "Enables panel displaying functionality of the instance on the About page" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:frontend_configurations > :pleroma_fe > :showInstanceSpecificPanel" +#, fuzzy +msgctxt "" +"config description at :pleroma-:frontend_configurations > :pleroma_fe > :" +"showInstanceSpecificPanel" msgid "Whether to show the instance's custom panel" msgstr "Whether to show the instance's custom panel" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:frontend_configurations > :pleroma_fe > :sidebarRight" +#, fuzzy +msgctxt "" +"config description at :pleroma-:frontend_configurations > :pleroma_fe > :" +"sidebarRight" msgid "Change alignment of sidebar and panels to the right" msgstr "Change alignment of sidebar and panels to the right" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:frontend_configurations > :pleroma_fe > :subjectLineBehavior" -msgid "Allows changing the default behaviour of subject lines in replies.\n `email`: copy and preprend re:, as in email,\n `masto`: copy verbatim, as in Mastodon,\n `noop`: don't copy the subject." +#, fuzzy +msgctxt "" +"config description at :pleroma-:frontend_configurations > :pleroma_fe > :" +"subjectLineBehavior" +msgid "" +"Allows changing the default behaviour of subject lines in replies.\n" +" `email`: copy and preprend re:, as in email,\n" +" `masto`: copy verbatim, as in Mastodon,\n" +" `noop`: don't copy the subject." msgstr "" "Allows changing the default behaviour of subject lines in replies.\n" " `email`: copy and preprend re:, as in email,\n" @@ -1554,337 +1736,374 @@ msgstr "" " `noop`: don't copy the subject." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:frontend_configurations > :pleroma_fe > :theme" +#, fuzzy +msgctxt "" +"config description at :pleroma-:frontend_configurations > :pleroma_fe > :" +"theme" msgid "Which theme to use. Available themes are defined in styles.json" msgstr "Which theme to use. Available themes are defined in styles.json" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:frontends > :admin" msgid "Admin frontend" msgstr "Admin frontend" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:frontends > :admin > name" -msgid "Name of the installed frontend. Valid config must include both `Name` and `Reference` values." +msgid "" +"Name of the installed frontend. Valid config must include both `Name` and " +"`Reference` values." msgstr "" "Name of the installed frontend. Valid config must include both `Name` and " "`Reference` values." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:frontends > :admin > ref" -msgid "Reference of the installed frontend to be used. Valid config must include both `Name` and `Reference` values." +msgid "" +"Reference of the installed frontend to be used. Valid config must include " +"both `Name` and `Reference` values." msgstr "" "Reference of the installed frontend to be used. Valid config must include " "both `Name` and `Reference` values." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:frontends > :available" -msgid "A map containing available frontends and parameters for their installation." +msgid "" +"A map containing available frontends and parameters for their installation." msgstr "" "A map containing available frontends and parameters for their installation." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:frontends > :available > build_dir" msgid "The directory inside the zip file " msgstr "The directory inside the zip file " #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:frontends > :available > build_url" -msgid "Either an url to a zip file containing the frontend or a template to build it by inserting the `ref`. The string `${ref}` will be replaced by the configured `ref`." +msgid "" +"Either an url to a zip file containing the frontend or a template to build " +"it by inserting the `ref`. The string `${ref}` will be replaced by the " +"configured `ref`." msgstr "" "Either an url to a zip file containing the frontend or a template to build " "it by inserting the `ref`. The string `${ref}` will be replaced by the " "configured `ref`." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:frontends > :available > custom-http-headers" +#, fuzzy +msgctxt "" +"config description at :pleroma-:frontends > :available > custom-http-headers" msgid "The custom HTTP headers for the frontend" msgstr "The custom HTTP headers for the frontend" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:frontends > :available > git" msgid "URL of the git repository of the frontend" msgstr "URL of the git repository of the frontend" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:frontends > :available > name" msgid "Name of the frontend." msgstr "Name of the frontend." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:frontends > :available > ref" msgid "Reference of the frontend to be used." msgstr "Reference of the frontend to be used." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:frontends > :primary" msgid "Primary frontend, the one that is served for all pages by default" msgstr "Primary frontend, the one that is served for all pages by default" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:frontends > :primary > name" -msgid "Name of the installed frontend. Valid config must include both `Name` and `Reference` values." +msgid "" +"Name of the installed frontend. Valid config must include both `Name` and " +"`Reference` values." msgstr "" "Name of the installed frontend. Valid config must include both `Name` and " "`Reference` values." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:frontends > :primary > ref" -msgid "Reference of the installed frontend to be used. Valid config must include both `Name` and `Reference` values." +msgid "" +"Reference of the installed frontend to be used. Valid config must include " +"both `Name` and `Reference` values." msgstr "" "Reference of the installed frontend to be used. Valid config must include " "both `Name` and `Reference` values." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:gopher > :dstport" msgid "Port advertised in URLs (optional, defaults to port)" msgstr "Port advertised in URLs (optional, defaults to port)" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:gopher > :enabled" msgid "Enables the gopher interface" msgstr "Enables the gopher interface" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:gopher > :ip" msgid "IP address to bind to" msgstr "IP address to bind to" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:gopher > :port" msgid "Port to bind to" msgstr "Port to bind to" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:hackney_pools > :federation" msgid "Settings for federation pool." msgstr "Settings for federation pool." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:hackney_pools > :federation > :max_connections" +#, fuzzy +msgctxt "" +"config description at :pleroma-:hackney_pools > :federation > :" +"max_connections" msgid "Number workers in the pool." msgstr "Number workers in the pool." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:hackney_pools > :federation > :timeout" +#, fuzzy +msgctxt "" +"config description at :pleroma-:hackney_pools > :federation > :timeout" msgid "Timeout while `hackney` will wait for response." msgstr "Timeout while `hackney` will wait for response." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:hackney_pools > :media" msgid "Settings for media pool." msgstr "Settings for media pool." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:hackney_pools > :media > :max_connections" +#, fuzzy +msgctxt "" +"config description at :pleroma-:hackney_pools > :media > :max_connections" msgid "Number workers in the pool." msgstr "Number workers in the pool." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:hackney_pools > :media > :timeout" msgid "Timeout while `hackney` will wait for response." msgstr "Timeout while `hackney` will wait for response." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:hackney_pools > :upload" msgid "Settings for upload pool." msgstr "Settings for upload pool." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:hackney_pools > :upload > :max_connections" +#, fuzzy +msgctxt "" +"config description at :pleroma-:hackney_pools > :upload > :max_connections" msgid "Number workers in the pool." msgstr "Number workers in the pool." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:hackney_pools > :upload > :timeout" msgid "Timeout while `hackney` will wait for response." msgstr "Timeout while `hackney` will wait for response." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:http > :adapter" msgid "Adapter specific options" msgstr "Adapter specific options" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:http > :adapter > :ssl_options" msgid "SSL options for HTTP adapter" msgstr "SSL options for HTTP adapter" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:http > :adapter > :ssl_options > :versions" +#, fuzzy +msgctxt "" +"config description at :pleroma-:http > :adapter > :ssl_options > :versions" msgid "List of TLS version to use" msgstr "List of TLS version to use" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:http > :proxy_url" msgid "Proxy URL" msgstr "Proxy URL" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:http > :user_agent" -msgid "What user agent to use. Must be a string or an atom `:default`. Default value is `:default`." +msgid "" +"What user agent to use. Must be a string or an atom `:default`. Default " +"value is `:default`." msgstr "" "What user agent to use. Must be a string or an atom `:default`. Default " "value is `:default`." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:http_security > :enabled" msgid "Whether the managed content security policy is enabled" msgstr "Whether the managed content security policy is enabled" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:http_security > :referrer_policy" msgid "The referrer policy to use, either \"same-origin\" or \"no-referrer\"" msgstr "The referrer policy to use, either \"same-origin\" or \"no-referrer\"" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:http_security > :report_uri" msgid "Adds the specified URL to report-uri and report-to group in CSP header" msgstr "Adds the specified URL to report-uri and report-to group in CSP header" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:http_security > :sts" msgid "Whether to additionally send a Strict-Transport-Security header" msgstr "Whether to additionally send a Strict-Transport-Security header" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:http_security > :sts_max_age" msgid "The maximum age for the Strict-Transport-Security header if sent" msgstr "The maximum age for the Strict-Transport-Security header if sent" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:instance > :account_activation_required" +#, fuzzy +msgctxt "" +"config description at :pleroma-:instance > :account_activation_required" msgid "Require users to confirm their emails before signing in" msgstr "Require users to confirm their emails before signing in" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :account_approval_required" msgid "Require users to be manually approved by an admin before signing in" msgstr "Require users to be manually approved by an admin before signing in" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :account_field_name_length" msgid "An account field name maximum length. Default: 512." msgstr "An account field name maximum length. Default: 512." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:instance > :account_field_value_length" +#, fuzzy +msgctxt "" +"config description at :pleroma-:instance > :account_field_value_length" msgid "An account field value maximum length. Default: 2048." msgstr "An account field value maximum length. Default: 2048." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :allow_relay" -msgid "Permits remote instances to subscribe to all public posts of your instance. (Important!) This may increase the visibility of your instance." +msgid "" +"Permits remote instances to subscribe to all public posts of your instance. " +"(Important!) This may increase the visibility of your instance." msgstr "" "Permits remote instances to subscribe to all public posts of your instance. " "(Important!) This may increase the visibility of your instance." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :allowed_post_formats" msgid "MIME-type list of formats allowed to be posted (transformed into HTML)" msgstr "MIME-type list of formats allowed to be posted (transformed into HTML)" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :attachment_links" msgid "Enable to automatically add attachment link text to statuses" msgstr "Enable to automatically add attachment link text to statuses" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :autofollowed_nicknames" -msgid "Set to nicknames of (local) users that every new user should automatically follow" +msgid "" +"Set to nicknames of (local) users that every new user should automatically " +"follow" msgstr "" "Set to nicknames of (local) users that every new user should automatically " "follow" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :autofollowing_nicknames" -msgid "Set to nicknames of (local) users that automatically follows every newly registered user" +msgid "" +"Set to nicknames of (local) users that automatically follows every newly " +"registered user" msgstr "" "Set to nicknames of (local) users that automatically follows every newly " "registered user" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :avatar_upload_limit" msgid "File size limit of user's profile avatars" msgstr "File size limit of user's profile avatars" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :background_upload_limit" msgid "File size limit of user's profile backgrounds" msgstr "File size limit of user's profile backgrounds" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :banner_upload_limit" msgid "File size limit of user's profile banners" msgstr "File size limit of user's profile banners" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :birthday_min_age" -msgid "Minimum required age for users to create account. Only used if birthday is required." +msgid "" +"Minimum required age for users to create account. Only used if birthday is " +"required." msgstr "" "Minimum required age for users to create account. Only used if birthday is " "required." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :birthday_required" msgid "Require users to enter their birthday." msgstr "Require users to enter their birthday." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :cleanup_attachments" -msgid "Enable to remove associated attachments when status is removed.\nThis will not affect duplicates and attachments without status.\nEnabling this will increase load to database when deleting statuses on larger instances.\n" +msgid "" +"Enable to remove associated attachments when status is removed.\n" +"This will not affect duplicates and attachments without status.\n" +"Enabling this will increase load to database when deleting statuses on " +"larger instances.\n" msgstr "" "Enable to remove associated attachments when status is removed.\n" "This will not affect duplicates and attachments without status.\n" @@ -1892,43 +2111,54 @@ msgstr "" "larger instances.\n" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :description" -msgid "The instance's description. It can be seen in nodeinfo and `/api/v1/instance`" +msgid "" +"The instance's description. It can be seen in nodeinfo and `/api/v1/instance`" msgstr "" "The instance's description. It can be seen in nodeinfo and `/api/v1/instance`" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :email" msgid "Email used to reach an Administrator/Moderator of the instance" msgstr "Email used to reach an Administrator/Moderator of the instance" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :extended_nickname_format" -msgid "Enable to use extended local nicknames format (allows underscores/dashes). This will break federation with older software for theses nicknames." +msgid "" +"Enable to use extended local nicknames format (allows underscores/dashes). " +"This will break federation with older software for theses nicknames." msgstr "" "Enable to use extended local nicknames format (allows underscores/dashes). " "This will break federation with older software for theses nicknames." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:instance > :external_user_synchronization" -msgid "Enabling following/followers counters synchronization for external users" +#, fuzzy +msgctxt "" +"config description at :pleroma-:instance > :external_user_synchronization" +msgid "" +"Enabling following/followers counters synchronization for external users" msgstr "" "Enabling following/followers counters synchronization for external users" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :federating" msgid "Enable federation with other instances" msgstr "Enable federation with other instances" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:instance > :federation_incoming_replies_max_depth" -msgid "Max. depth of reply-to and reply activities fetching on incoming federation, to prevent out-of-memory situations while fetching very long threads. If set to `nil`, threads of any depth will be fetched. Lower this value if you experience out-of-memory crashes." +#, fuzzy +msgctxt "" +"config description at :pleroma-:instance > :" +"federation_incoming_replies_max_depth" +msgid "" +"Max. depth of reply-to and reply activities fetching on incoming federation, " +"to prevent out-of-memory situations while fetching very long threads. If set " +"to `nil`, threads of any depth will be fetched. Lower this value if you " +"experience out-of-memory crashes." msgstr "" "Max. depth of reply-to and reply activities fetching on incoming federation, " "to prevent out-of-memory situations while fetching very long threads. If set " @@ -1936,196 +2166,239 @@ msgstr "" "experience out-of-memory crashes." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:instance > :federation_reachability_timeout_days" -msgid "Timeout (in days) of each external federation target being unreachable prior to pausing federating to it" +#, fuzzy +msgctxt "" +"config description at :pleroma-:instance > :" +"federation_reachability_timeout_days" +msgid "" +"Timeout (in days) of each external federation target being unreachable prior " +"to pausing federating to it" msgstr "" "Timeout (in days) of each external federation target being unreachable prior " "to pausing federating to it" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :healthcheck" msgid "If enabled, system data will be shown on `/api/pleroma/healthcheck`" msgstr "If enabled, system data will be shown on `/api/pleroma/healthcheck`" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :instance_thumbnail" -msgid "The instance thumbnail can be any image that represents your instance and is used by some apps or services when they display information about your instance." +msgid "" +"The instance thumbnail can be any image that represents your instance and is " +"used by some apps or services when they display information about your " +"instance." msgstr "" "The instance thumbnail can be any image that represents your instance and is " "used by some apps or services when they display information about your " "instance." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :invites_enabled" -msgid "Enable user invitations for admins (depends on `registrations_open` being disabled)" +msgid "" +"Enable user invitations for admins (depends on `registrations_open` being " +"disabled)" msgstr "" "Enable user invitations for admins (depends on `registrations_open` being " "disabled)" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :limit" msgid "Posts character limit (CW/Subject included in the counter)" msgstr "Posts character limit (CW/Subject included in the counter)" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :limit_to_local_content" -msgid "Limit unauthenticated users to search for local statutes and users only. Default: `:unauthenticated`." +msgid "" +"Limit unauthenticated users to search for local statutes and users only. " +"Default: `:unauthenticated`." msgstr "" "Limit unauthenticated users to search for local statutes and users only. " "Default: `:unauthenticated`." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :max_account_fields" msgid "The maximum number of custom fields in the user profile. Default: 10." msgstr "The maximum number of custom fields in the user profile. Default: 10." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :max_endorsed_users" msgid "The maximum number of recommended accounts. 0 will disable the feature." -msgstr "The maximum number of recommended accounts. 0 will disable the feature." +msgstr "" +"The maximum number of recommended accounts. 0 will disable the feature." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :max_media_attachments" msgid "Maximum number of post media attachments" msgstr "Maximum number of post media attachments" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :max_pinned_statuses" msgid "The maximum number of pinned statuses. 0 will disable the feature." msgstr "The maximum number of pinned statuses. 0 will disable the feature." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :max_remote_account_fields" -msgid "The maximum number of custom fields in the remote user profile. Default: 20." +msgid "" +"The maximum number of custom fields in the remote user profile. Default: 20." msgstr "" "The maximum number of custom fields in the remote user profile. Default: 20." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :max_report_comment_size" msgid "The maximum size of the report comment. Default: 1000." msgstr "The maximum size of the report comment. Default: 1000." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:instance > :multi_factor_authentication" +#, fuzzy +msgctxt "" +"config description at :pleroma-:instance > :multi_factor_authentication" msgid "Multi-factor authentication settings" msgstr "Multi-factor authentication settings" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:instance > :multi_factor_authentication > :backup_codes" +#, fuzzy +msgctxt "" +"config description at :pleroma-:instance > :multi_factor_authentication > :" +"backup_codes" msgid "MFA backup codes settings" msgstr "MFA backup codes settings" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:instance > :multi_factor_authentication > :backup_codes > :length" -msgid "Determines the length of backup one-time pass-codes, in characters. Defaults to 16 characters." +#, fuzzy +msgctxt "" +"config description at :pleroma-:instance > :multi_factor_authentication > :" +"backup_codes > :length" +msgid "" +"Determines the length of backup one-time pass-codes, in characters. Defaults " +"to 16 characters." msgstr "" "Determines the length of backup one-time pass-codes, in characters. Defaults " "to 16 characters." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:instance > :multi_factor_authentication > :backup_codes > :number" +#, fuzzy +msgctxt "" +"config description at :pleroma-:instance > :multi_factor_authentication > :" +"backup_codes > :number" msgid "Number of backup codes to generate." msgstr "Number of backup codes to generate." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:instance > :multi_factor_authentication > :totp" +#, fuzzy +msgctxt "" +"config description at :pleroma-:instance > :multi_factor_authentication > :" +"totp" msgid "TOTP settings" msgstr "TOTP settings" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:instance > :multi_factor_authentication > :totp > :digits" -msgid "Determines the length of a one-time pass-code, in characters. Defaults to 6 characters." +#, fuzzy +msgctxt "" +"config description at :pleroma-:instance > :multi_factor_authentication > :" +"totp > :digits" +msgid "" +"Determines the length of a one-time pass-code, in characters. Defaults to 6 " +"characters." msgstr "" "Determines the length of a one-time pass-code, in characters. Defaults to 6 " "characters." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:instance > :multi_factor_authentication > :totp > :period" -msgid "A period for which the TOTP code will be valid, in seconds. Defaults to 30 seconds." +#, fuzzy +msgctxt "" +"config description at :pleroma-:instance > :multi_factor_authentication > :" +"totp > :period" +msgid "" +"A period for which the TOTP code will be valid, in seconds. Defaults to 30 " +"seconds." msgstr "" "A period for which the TOTP code will be valid, in seconds. Defaults to 30 " "seconds." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :name" msgid "Name of the instance" msgstr "Name of the instance" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :notify_email" msgid "Envelope FROM address for mail sent via Pleroma" msgstr "Envelope FROM address for mail sent via Pleroma" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :poll_limits" msgid "A map with poll limits for local polls" msgstr "A map with poll limits for local polls" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:instance > :poll_limits > :max_expiration" +#, fuzzy +msgctxt "" +"config description at :pleroma-:instance > :poll_limits > :max_expiration" msgid "Maximum expiration time (in seconds)" msgstr "Maximum expiration time (in seconds)" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:instance > :poll_limits > :max_option_chars" +#, fuzzy +msgctxt "" +"config description at :pleroma-:instance > :poll_limits > :max_option_chars" msgid "Maximum number of characters per option" msgstr "Maximum number of characters per option" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:instance > :poll_limits > :max_options" +#, fuzzy +msgctxt "" +"config description at :pleroma-:instance > :poll_limits > :max_options" msgid "Maximum number of options" msgstr "Maximum number of options" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:instance > :poll_limits > :min_expiration" +#, fuzzy +msgctxt "" +"config description at :pleroma-:instance > :poll_limits > :min_expiration" msgid "Minimum expiration time (in seconds)" msgstr "Minimum expiration time (in seconds)" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :privileged_staff" -msgid "Let moderators access sensitive data (e.g. updating user credentials, get password reset token, delete users, index and read private statuses and chats)" +msgid "" +"Let moderators access sensitive data (e.g. updating user credentials, get " +"password reset token, delete users, index and read private statuses and " +"chats)" msgstr "" "Let moderators access sensitive data (e.g. updating user credentials, get " "password reset token, delete users, index and read private statuses and " "chats)" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :profile_directory" msgid "Enable profile directory." msgstr "Enable profile directory." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :public" -msgid "Makes the client API in authenticated mode-only except for user-profiles. Useful for disabling the Local Timeline and The Whole Known Network. Note: when setting to `false`, please also check `:restrict_unauthenticated` setting." +msgid "" +"Makes the client API in authenticated mode-only except for user-profiles. " +"Useful for disabling the Local Timeline and The Whole Known Network. Note: " +"when setting to `false`, please also check `:restrict_unauthenticated` " +"setting." msgstr "" "Makes the client API in authenticated mode-only except for user-profiles. " "Useful for disabling the Local Timeline and The Whole Known Network. Note: " @@ -2133,292 +2406,339 @@ msgstr "" "setting." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :quarantined_instances" -msgid "List of ActivityPub instances where private (DMs, followers-only) activities will not be sent and the reason for doing so" +msgid "" +"List of ActivityPub instances where private (DMs, followers-only) activities " +"will not be sent and the reason for doing so" msgstr "" "List of ActivityPub instances where private (DMs, followers-only) activities " "will not be sent and the reason for doing so" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:instance > :registration_reason_length" +#, fuzzy +msgctxt "" +"config description at :pleroma-:instance > :registration_reason_length" msgid "Maximum registration reason length. Default: 500." msgstr "Maximum registration reason length. Default: 500." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :registrations_open" -msgid "Enable registrations for anyone. Invitations require this setting to be disabled." +msgid "" +"Enable registrations for anyone. Invitations require this setting to be " +"disabled." msgstr "" "Enable registrations for anyone. Invitations require this setting to be " "disabled." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :remote_limit" msgid "Hard character limit beyond which remote posts will be dropped" msgstr "Hard character limit beyond which remote posts will be dropped" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:instance > :remote_post_retention_days" -msgid "The default amount of days to retain remote posts when pruning the database" +#, fuzzy +msgctxt "" +"config description at :pleroma-:instance > :remote_post_retention_days" +msgid "" +"The default amount of days to retain remote posts when pruning the database" msgstr "" "The default amount of days to retain remote posts when pruning the database" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :safe_dm_mentions" -msgid "If enabled, only mentions at the beginning of a post will be used to address people in direct messages. This is to prevent accidental mentioning of people when talking about them (e.g. \"@admin please keep an eye on @bad_actor\"). Default: disabled" +msgid "" +"If enabled, only mentions at the beginning of a post will be used to address " +"people in direct messages. This is to prevent accidental mentioning of " +"people when talking about them (e.g. \"@admin please keep an eye on " +"@bad_actor\"). Default: disabled" msgstr "" "If enabled, only mentions at the beginning of a post will be used to address " "people in direct messages. This is to prevent accidental mentioning of " -"people when talking about them (e.g. \"@admin please keep an eye on @" -"bad_actor\"). Default: disabled" +"people when talking about them (e.g. \"@admin please keep an eye on " +"@bad_actor\"). Default: disabled" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :show_reactions" msgid "Let favourites and emoji reactions be viewed through the API." msgstr "Let favourites and emoji reactions be viewed through the API." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :skip_thread_containment" msgid "Skip filtering out broken threads. Default: enabled." msgstr "Skip filtering out broken threads. Default: enabled." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :static_dir" msgid "Instance static directory" msgstr "Instance static directory" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :upload_limit" msgid "File size limit of uploads (except for avatar, background, banner)" msgstr "File size limit of uploads (except for avatar, background, banner)" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :user_bio_length" msgid "A user bio maximum length. Default: 5000." msgstr "A user bio maximum length. Default: 5000." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :user_name_length" msgid "A user name maximum length. Default: 100." msgstr "A user name maximum length. Default: 100." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instances_favicons > :enabled" msgid "Allow/disallow displaying and getting instances favicons" msgstr "Allow/disallow displaying and getting instances favicons" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:ldap > :base" msgid "LDAP base, e.g. \"dc=example,dc=com\"" msgstr "LDAP base, e.g. \"dc=example,dc=com\"" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:ldap > :enabled" msgid "Enables LDAP authentication" msgstr "Enables LDAP authentication" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:ldap > :host" msgid "LDAP server hostname" msgstr "LDAP server hostname" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:ldap > :port" msgid "LDAP port, e.g. 389 or 636" msgstr "LDAP port, e.g. 389 or 636" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:ldap > :ssl" msgid "Enable to use SSL, usually implies the port 636" msgstr "Enable to use SSL, usually implies the port 636" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:ldap > :sslopts" msgid "Additional SSL options" msgstr "Additional SSL options" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:ldap > :sslopts > :cacertfile" msgid "Path to file with PEM encoded cacerts" msgstr "Path to file with PEM encoded cacerts" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:ldap > :sslopts > :verify" msgid "Type of cert verification" msgstr "Type of cert verification" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:ldap > :tls" msgid "Enable to use STARTTLS, usually implies the port 389" msgstr "Enable to use STARTTLS, usually implies the port 389" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:ldap > :tlsopts" msgid "Additional TLS options" msgstr "Additional TLS options" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:ldap > :tlsopts > :cacertfile" msgid "Path to file with PEM encoded cacerts" msgstr "Path to file with PEM encoded cacerts" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:ldap > :tlsopts > :verify" msgid "Type of cert verification" msgstr "Type of cert verification" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:ldap > :uid" -msgid "LDAP attribute name to authenticate the user, e.g. when \"cn\", the filter will be \"cn=username,base\"" +msgid "" +"LDAP attribute name to authenticate the user, e.g. when \"cn\", the filter " +"will be \"cn=username,base\"" msgstr "" "LDAP attribute name to authenticate the user, e.g. when \"cn\", the filter " "will be \"cn=username,base\"" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:majic_pool > :size" msgid "Number of majic workers to start." msgstr "Number of majic workers to start." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:manifest > :background_color" msgid "Describe the background color of the app" msgstr "Describe the background color of the app" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:manifest > :icons" msgid "Describe the icons of the app" msgstr "Describe the icons of the app" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:manifest > :theme_color" msgid "Describe the theme color of the app" msgstr "Describe the theme color of the app" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:markup > :scrub_policy" -msgid "Module names are shortened (removed leading `Pleroma.HTML.` part), but on adding custom module you need to use full name." +msgid "" +"Module names are shortened (removed leading `Pleroma.HTML.` part), but on " +"adding custom module you need to use full name." msgstr "" "Module names are shortened (removed leading `Pleroma.HTML.` part), but on " "adding custom module you need to use full name." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:media_preview_proxy > :enabled" -msgid "Enables proxying of remote media preview to the instance's proxy. Requires enabled media proxy." +msgid "" +"Enables proxying of remote media preview to the instance's proxy. Requires " +"enabled media proxy." msgstr "" "Enables proxying of remote media preview to the instance's proxy. Requires " "enabled media proxy." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:media_preview_proxy > :image_quality" -msgid "Quality of the output. Ranges from 0 (min quality) to 100 (max quality)." +msgid "" +"Quality of the output. Ranges from 0 (min quality) to 100 (max quality)." msgstr "" "Quality of the output. Ranges from 0 (min quality) to 100 (max quality)." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:media_preview_proxy > :min_content_length" -msgid "Min content length (in bytes) to perform preview. Media smaller in size will be served without thumbnailing." +#, fuzzy +msgctxt "" +"config description at :pleroma-:media_preview_proxy > :min_content_length" +msgid "" +"Min content length (in bytes) to perform preview. Media smaller in size will " +"be served without thumbnailing." msgstr "" "Min content length (in bytes) to perform preview. Media smaller in size will " "be served without thumbnailing." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:media_preview_proxy > :thumbnail_max_height" -msgid "Max height of preview thumbnail for images (video preview always has original dimensions)." +#, fuzzy +msgctxt "" +"config description at :pleroma-:media_preview_proxy > :thumbnail_max_height" +msgid "" +"Max height of preview thumbnail for images (video preview always has " +"original dimensions)." msgstr "" "Max height of preview thumbnail for images (video preview always has " "original dimensions)." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:media_preview_proxy > :thumbnail_max_width" -msgid "Max width of preview thumbnail for images (video preview always has original dimensions)." +#, fuzzy +msgctxt "" +"config description at :pleroma-:media_preview_proxy > :thumbnail_max_width" +msgid "" +"Max width of preview thumbnail for images (video preview always has original " +"dimensions)." msgstr "" "Max width of preview thumbnail for images (video preview always has original " "dimensions)." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:media_proxy > :base_url" -msgid "The base URL to access a user-uploaded file. Useful when you want to proxy the media files via another host/CDN fronts." +msgid "" +"The base URL to access a user-uploaded file. Useful when you want to proxy " +"the media files via another host/CDN fronts." msgstr "" "The base URL to access a user-uploaded file. Useful when you want to proxy " "the media files via another host/CDN fronts." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:media_proxy > :enabled" msgid "Enables proxying of remote media via the instance's proxy" msgstr "Enables proxying of remote media via the instance's proxy" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:media_proxy > :invalidation > :enabled" +#, fuzzy +msgctxt "" +"config description at :pleroma-:media_proxy > :invalidation > :enabled" msgid "Enables media cache object invalidation." msgstr "Enables media cache object invalidation." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:media_proxy > :invalidation > :provider" +#, fuzzy +msgctxt "" +"config description at :pleroma-:media_proxy > :invalidation > :provider" msgid "Module which will be used to purge objects from the cache." msgstr "Module which will be used to purge objects from the cache." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:media_proxy > :proxy_opts" msgid "Internal Pleroma.ReverseProxy settings" msgstr "Internal Pleroma.ReverseProxy settings" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:media_proxy > :proxy_opts > :max_body_length" -msgid "Maximum file size (in bytes) allowed through the Pleroma MediaProxy cache." +#, fuzzy +msgctxt "" +"config description at :pleroma-:media_proxy > :proxy_opts > :max_body_length" +msgid "" +"Maximum file size (in bytes) allowed through the Pleroma MediaProxy cache." msgstr "" "Maximum file size (in bytes) allowed through the Pleroma MediaProxy cache." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:media_proxy > :proxy_opts > :max_read_duration" +#, fuzzy +msgctxt "" +"config description at :pleroma-:media_proxy > :proxy_opts > :" +"max_read_duration" msgid "Timeout (in milliseconds) of GET request to the remote URI." msgstr "Timeout (in milliseconds) of GET request to the remote URI." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:media_proxy > :proxy_opts > :redirect_on_failure" -msgid "Redirects the client to the origin server upon encountering HTTP errors.\n\nNote that files larger than Max Body Length will trigger an error. (e.g., Peertube videos)\n\n\n**WARNING:** This setting will allow larger files to be accessed, but exposes the\n\nIP addresses of your users to the other servers, bypassing the MediaProxy.\n" +#, fuzzy +msgctxt "" +"config description at :pleroma-:media_proxy > :proxy_opts > :" +"redirect_on_failure" +msgid "" +"Redirects the client to the origin server upon encountering HTTP errors.\n" +"\n" +"Note that files larger than Max Body Length will trigger an error. (e.g., " +"Peertube videos)\n" +"\n" +"\n" +"**WARNING:** This setting will allow larger files to be accessed, but " +"exposes the\n" +"\n" +"IP addresses of your users to the other servers, bypassing the MediaProxy.\n" msgstr "" "Redirects the client to the origin server upon encountering HTTP errors.\n" "\n" @@ -2432,38 +2752,47 @@ msgstr "" "IP addresses of your users to the other servers, bypassing the MediaProxy.\n" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:media_proxy > :whitelist" msgid "List of hosts with scheme to bypass the MediaProxy" msgstr "List of hosts with scheme to bypass the MediaProxy" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:modules > :runtime_dir" msgid "A path to custom Elixir modules (such as MRF policies)." msgstr "A path to custom Elixir modules (such as MRF policies)." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf > :policies" -msgid "A list of MRF policies enabled. Module names are shortened (removed leading `Pleroma.Web.ActivityPub.MRF.` part), but on adding custom module you need to use full name." +msgid "" +"A list of MRF policies enabled. Module names are shortened (removed leading " +"`Pleroma.Web.ActivityPub.MRF.` part), but on adding custom module you need " +"to use full name." msgstr "" "A list of MRF policies enabled. Module names are shortened (removed leading " "`Pleroma.Web.ActivityPub.MRF.` part), but on adding custom module you need " "to use full name." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf > :transparency" -msgid "Make the content of your Message Rewrite Facility settings public (via nodeinfo)" +msgid "" +"Make the content of your Message Rewrite Facility settings public (via " +"nodeinfo)" msgstr "" "Make the content of your Message Rewrite Facility settings public (via " "nodeinfo)" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf > :transparency_exclusions" -msgid "Exclude specific instance names from MRF transparency. The use of the exclusions feature will be disclosed in nodeinfo as a boolean value. You can also provide a reason for excluding these instance names. The instances and reasons won't be publicly disclosed." +msgid "" +"Exclude specific instance names from MRF transparency. The use of the " +"exclusions feature will be disclosed in nodeinfo as a boolean value. You can " +"also provide a reason for excluding these instance names. The instances and " +"reasons won't be publicly disclosed." msgstr "" "Exclude specific instance names from MRF transparency. The use of the " "exclusions feature will be disclosed in nodeinfo as a boolean value. You can " @@ -2471,60 +2800,76 @@ msgstr "" "reasons won't be publicly disclosed." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_activity_expiration > :days" msgid "Default global expiration time for all local activities (in days)" msgstr "Default global expiration time for all local activities (in days)" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_follow_bot > :follower_nickname" -msgid "The name of the bot account to use for following newly discovered users." +msgid "" +"The name of the bot account to use for following newly discovered users." msgstr "" "The name of the bot account to use for following newly discovered users." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:mrf_hashtag > :federated_timeline_removal" -msgid "A list of hashtags which result in message being removed from federated timelines (a.k.a unlisted)." +#, fuzzy +msgctxt "" +"config description at :pleroma-:mrf_hashtag > :federated_timeline_removal" +msgid "" +"A list of hashtags which result in message being removed from federated " +"timelines (a.k.a unlisted)." msgstr "" "A list of hashtags which result in message being removed from federated " "timelines (a.k.a unlisted)." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_hashtag > :reject" msgid "A list of hashtags which result in message being rejected." msgstr "A list of hashtags which result in message being rejected." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_hashtag > :sensitive" -msgid "A list of hashtags which result in message being set as sensitive (a.k.a NSFW/R-18)" +msgid "" +"A list of hashtags which result in message being set as sensitive (a.k.a " +"NSFW/R-18)" msgstr "" "A list of hashtags which result in message being set as sensitive (a.k.a " "NSFW/R-18)" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_hellthread > :delist_threshold" -msgid "Number of mentioned users after which the message gets removed from timelines anddisables notifications. Set to 0 to disable." +msgid "" +"Number of mentioned users after which the message gets removed from " +"timelines anddisables notifications. Set to 0 to disable." msgstr "" "Number of mentioned users after which the message gets removed from " "timelines anddisables notifications. Set to 0 to disable." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_hellthread > :reject_threshold" -msgid "Number of mentioned users after which the messaged gets rejected. Set to 0 to disable." +msgid "" +"Number of mentioned users after which the messaged gets rejected. Set to 0 " +"to disable." msgstr "" "Number of mentioned users after which the messaged gets rejected. Set to 0 " "to disable." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:mrf_keyword > :federated_timeline_removal" -msgid " A list of patterns which result in message being removed from federated timelines (a.k.a unlisted).\n\n Each pattern can be a string or [Regex](https://hexdocs.pm/elixir/Regex.html) in the format of `~r/PATTERN/`.\n" +#, fuzzy +msgctxt "" +"config description at :pleroma-:mrf_keyword > :federated_timeline_removal" +msgid "" +" A list of patterns which result in message being removed from federated " +"timelines (a.k.a unlisted).\n" +"\n" +" Each pattern can be a string or [Regex](https://hexdocs.pm/elixir/Regex." +"html) in the format of `~r/PATTERN/`.\n" msgstr "" " A list of patterns which result in message being removed from federated " "timelines (a.k.a unlisted).\n" @@ -2533,9 +2878,13 @@ msgstr "" "html) in the format of `~r/PATTERN/`.\n" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_keyword > :reject" -msgid " A list of patterns which result in message being rejected.\n\n Each pattern can be a string or [Regex](https://hexdocs.pm/elixir/Regex.html) in the format of `~r/PATTERN/`.\n" +msgid "" +" A list of patterns which result in message being rejected.\n" +"\n" +" Each pattern can be a string or [Regex](https://hexdocs.pm/elixir/Regex." +"html) in the format of `~r/PATTERN/`.\n" msgstr "" " A list of patterns which result in message being rejected.\n" "\n" @@ -2543,9 +2892,13 @@ msgstr "" "html) in the format of `~r/PATTERN/`.\n" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_keyword > :replace" -msgid " **Pattern**: a string or [Regex](https://hexdocs.pm/elixir/Regex.html) in the format of `~r/PATTERN/`.\n\n **Replacement**: a string. Leaving the field empty is permitted.\n" +msgid "" +" **Pattern**: a string or [Regex](https://hexdocs.pm/elixir/Regex.html) in " +"the format of `~r/PATTERN/`.\n" +"\n" +" **Replacement**: a string. Leaving the field empty is permitted.\n" msgstr "" " **Pattern**: a string or [Regex](https://hexdocs.pm/elixir/Regex.html) in " "the format of `~r/PATTERN/`.\n" @@ -2553,15 +2906,19 @@ msgstr "" " **Replacement**: a string. Leaving the field empty is permitted.\n" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_mention > :actors" msgid "A list of actors for which any post mentioning them will be dropped" msgstr "A list of actors for which any post mentioning them will be dropped" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_object_age > :actions" -msgid "A list of actions to apply to the post. `:delist` removes the post from public timelines; `:strip_followers` removes followers from the ActivityPub recipient list ensuring they won't be delivered to home timelines; `:reject` rejects the message entirely" +msgid "" +"A list of actions to apply to the post. `:delist` removes the post from " +"public timelines; `:strip_followers` removes followers from the ActivityPub " +"recipient list ensuring they won't be delivered to home timelines; `:reject` " +"rejects the message entirely" msgstr "" "A list of actions to apply to the post. `:delist` removes the post from " "public timelines; `:strip_followers` removes followers from the ActivityPub " @@ -2569,104 +2926,122 @@ msgstr "" "rejects the message entirely" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_object_age > :threshold" msgid "Required age (in seconds) of a post before actions are taken." msgstr "Required age (in seconds) of a post before actions are taken." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_rejectnonpublic > :allow_direct" msgid "Whether to allow direct messages" msgstr "Whether to allow direct messages" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:mrf_rejectnonpublic > :allow_followersonly" +#, fuzzy +msgctxt "" +"config description at :pleroma-:mrf_rejectnonpublic > :allow_followersonly" msgid "Whether to allow followers-only posts" msgstr "Whether to allow followers-only posts" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_simple > :accept" -msgid "List of instances to only accept activities from (except deletes) and the reason for doing so" +msgid "" +"List of instances to only accept activities from (except deletes) and the " +"reason for doing so" msgstr "" "List of instances to only accept activities from (except deletes) and the " "reason for doing so" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_simple > :avatar_removal" msgid "List of instances to strip avatars from and the reason for doing so" msgstr "List of instances to strip avatars from and the reason for doing so" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_simple > :banner_removal" msgid "List of instances to strip banners from and the reason for doing so" msgstr "List of instances to strip banners from and the reason for doing so" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:mrf_simple > :federated_timeline_removal" -msgid "List of instances to remove from the Federated (aka The Whole Known Network) Timeline and the reason for doing so" +#, fuzzy +msgctxt "" +"config description at :pleroma-:mrf_simple > :federated_timeline_removal" +msgid "" +"List of instances to remove from the Federated (aka The Whole Known Network) " +"Timeline and the reason for doing so" msgstr "" "List of instances to remove from the Federated (aka The Whole Known Network) " "Timeline and the reason for doing so" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_simple > :followers_only" -msgid "Force posts from the given instances to be visible by followers only and the reason for doing so" +msgid "" +"Force posts from the given instances to be visible by followers only and the " +"reason for doing so" msgstr "" "Force posts from the given instances to be visible by followers only and the " "reason for doing so" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_simple > :media_nsfw" -msgid "List of instances to tag all media as NSFW (sensitive) from and the reason for doing so" +msgid "" +"List of instances to tag all media as NSFW (sensitive) from and the reason " +"for doing so" msgstr "" "List of instances to tag all media as NSFW (sensitive) from and the reason " "for doing so" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_simple > :media_removal" -msgid "List of instances to strip media attachments from and the reason for doing so" +msgid "" +"List of instances to strip media attachments from and the reason for doing so" msgstr "" "List of instances to strip media attachments from and the reason for doing so" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_simple > :reject" -msgid "List of instances to reject activities from (except deletes) and the reason for doing so" +msgid "" +"List of instances to reject activities from (except deletes) and the reason " +"for doing so" msgstr "" "List of instances to reject activities from (except deletes) and the reason " "for doing so" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_simple > :reject_deletes" msgid "List of instances to reject deletions from and the reason for doing so" msgstr "List of instances to reject deletions from and the reason for doing so" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_simple > :report_removal" msgid "List of instances to reject reports from and the reason for doing so" msgstr "List of instances to reject reports from and the reason for doing so" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_steal_emoji > :hosts" msgid "List of hosts to steal emojis from" msgstr "List of hosts to steal emojis from" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:mrf_steal_emoji > :rejected_shortcodes" -msgid " A list of patterns or matches to reject shortcodes with.\n\n Each pattern can be a string or [Regex](https://hexdocs.pm/elixir/Regex.html) in the format of `~r/PATTERN/`.\n" +#, fuzzy +msgctxt "" +"config description at :pleroma-:mrf_steal_emoji > :rejected_shortcodes" +msgid "" +" A list of patterns or matches to reject shortcodes with.\n" +"\n" +" Each pattern can be a string or [Regex](https://hexdocs.pm/elixir/Regex." +"html) in the format of `~r/PATTERN/`.\n" msgstr "" " A list of patterns or matches to reject shortcodes with.\n" "\n" @@ -2674,3711 +3049,4054 @@ msgstr "" "html) in the format of `~r/PATTERN/`.\n" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_steal_emoji > :size_limit" -msgid "File size limit (in bytes), checked before an emoji is saved to the disk" +msgid "" +"File size limit (in bytes), checked before an emoji is saved to the disk" msgstr "" "File size limit (in bytes), checked before an emoji is saved to the disk" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_subchain > :match_actor" msgid "Matches a series of regular expressions against the actor field" msgstr "Matches a series of regular expressions against the actor field" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_vocabulary > :accept" -msgid "A list of ActivityStreams terms to accept. If empty, all supported messages are accepted." +msgid "" +"A list of ActivityStreams terms to accept. If empty, all supported messages " +"are accepted." msgstr "" "A list of ActivityStreams terms to accept. If empty, all supported messages " "are accepted." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:mrf_vocabulary > :reject" -msgid "A list of ActivityStreams terms to reject. If empty, no messages are rejected." +msgid "" +"A list of ActivityStreams terms to reject. If empty, no messages are " +"rejected." msgstr "" "A list of ActivityStreams terms to reject. If empty, no messages are " "rejected." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:oauth2 > :clean_expired_tokens" -msgid "Enable a background job to clean expired OAuth tokens. Default: disabled." +msgid "" +"Enable a background job to clean expired OAuth tokens. Default: disabled." msgstr "" "Enable a background job to clean expired OAuth tokens. Default: disabled." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:oauth2 > :issue_new_refresh_token" -msgid "Keeps old refresh token or generate new refresh token when to obtain an access token" +msgid "" +"Keeps old refresh token or generate new refresh token when to obtain an " +"access token" msgstr "" "Keeps old refresh token or generate new refresh token when to obtain an " "access token" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:oauth2 > :token_expires_in" msgid "The lifetime in seconds of the access token" msgstr "The lifetime in seconds of the access token" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:pools > :default" msgid "Settings for default pool." msgstr "Settings for default pool." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:pools > :default > :max_waiting" -msgid "Maximum number of requests waiting for other requests to finish. After this number is reached, the pool will start returning errrors when a new request is made" +msgid "" +"Maximum number of requests waiting for other requests to finish. After this " +"number is reached, the pool will start returning errrors when a new request " +"is made" msgstr "" "Maximum number of requests waiting for other requests to finish. After this " "number is reached, the pool will start returning errrors when a new request " "is made" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:pools > :default > :recv_timeout" msgid "Timeout for the pool while gun will wait for response" msgstr "Timeout for the pool while gun will wait for response" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:pools > :default > :size" msgid "Maximum number of concurrent requests in the pool." msgstr "Maximum number of concurrent requests in the pool." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:pools > :federation" msgid "Settings for federation pool." msgstr "Settings for federation pool." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:pools > :federation > :max_waiting" -msgid "Maximum number of requests waiting for other requests to finish. After this number is reached, the pool will start returning errrors when a new request is made" +msgid "" +"Maximum number of requests waiting for other requests to finish. After this " +"number is reached, the pool will start returning errrors when a new request " +"is made" msgstr "" "Maximum number of requests waiting for other requests to finish. After this " "number is reached, the pool will start returning errrors when a new request " "is made" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:pools > :federation > :recv_timeout" msgid "Timeout for the pool while gun will wait for response" msgstr "Timeout for the pool while gun will wait for response" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:pools > :federation > :size" msgid "Maximum number of concurrent requests in the pool." msgstr "Maximum number of concurrent requests in the pool." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:pools > :media" msgid "Settings for media pool." msgstr "Settings for media pool." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:pools > :media > :max_waiting" -msgid "Maximum number of requests waiting for other requests to finish. After this number is reached, the pool will start returning errrors when a new request is made" +msgid "" +"Maximum number of requests waiting for other requests to finish. After this " +"number is reached, the pool will start returning errrors when a new request " +"is made" msgstr "" "Maximum number of requests waiting for other requests to finish. After this " "number is reached, the pool will start returning errrors when a new request " "is made" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:pools > :media > :recv_timeout" msgid "Timeout for the pool while gun will wait for response" msgstr "Timeout for the pool while gun will wait for response" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:pools > :media > :size" msgid "Maximum number of concurrent requests in the pool." msgstr "Maximum number of concurrent requests in the pool." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:pools > :upload" msgid "Settings for upload pool." msgstr "Settings for upload pool." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:pools > :upload > :max_waiting" -msgid "Maximum number of requests waiting for other requests to finish. After this number is reached, the pool will start returning errrors when a new request is made" +msgid "" +"Maximum number of requests waiting for other requests to finish. After this " +"number is reached, the pool will start returning errrors when a new request " +"is made" msgstr "" "Maximum number of requests waiting for other requests to finish. After this " "number is reached, the pool will start returning errrors when a new request " "is made" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:pools > :upload > :recv_timeout" msgid "Timeout for the pool while gun will wait for response" msgstr "Timeout for the pool while gun will wait for response" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:pools > :upload > :size" msgid "Maximum number of concurrent requests in the pool." msgstr "Maximum number of concurrent requests in the pool." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:populate_hashtags_table > :fault_rate_allowance" -msgid "Max accepted rate of objects that failed in the migration. Any value from 0.0 which tolerates no errors to 1.0 which will enable the feature even if hashtags transfer failed for all records." +#, fuzzy +msgctxt "" +"config description at :pleroma-:populate_hashtags_table > :" +"fault_rate_allowance" +msgid "" +"Max accepted rate of objects that failed in the migration. Any value from " +"0.0 which tolerates no errors to 1.0 which will enable the feature even if " +"hashtags transfer failed for all records." msgstr "" "Max accepted rate of objects that failed in the migration. Any value from " "0.0 which tolerates no errors to 1.0 which will enable the feature even if " "hashtags transfer failed for all records." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:populate_hashtags_table > :sleep_interval_ms" -msgid "Sleep interval between each chunk of processed records in order to decrease the load on the system (defaults to 0 and should be keep default on most instances)." +#, fuzzy +msgctxt "" +"config description at :pleroma-:populate_hashtags_table > :sleep_interval_ms" +msgid "" +"Sleep interval between each chunk of processed records in order to decrease " +"the load on the system (defaults to 0 and should be keep default on most " +"instances)." msgstr "" "Sleep interval between each chunk of processed records in order to decrease " "the load on the system (defaults to 0 and should be keep default on most " "instances)." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:rate_limit > :app_account_creation" msgid "For registering user accounts from the same IP address" msgstr "For registering user accounts from the same IP address" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:rate_limit > :authentication" -msgid "For authentication create / password check / user existence check requests" +msgid "" +"For authentication create / password check / user existence check requests" msgstr "" "For authentication create / password check / user existence check requests" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:rate_limit > :relation_id_action" msgid "For actions on relation with a specific user (follow, unfollow)" msgstr "For actions on relation with a specific user (follow, unfollow)" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:rate_limit > :relations_actions" msgid "For actions on relationships with all users (follow, unfollow)" msgstr "For actions on relationships with all users (follow, unfollow)" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:rate_limit > :search" msgid "For the search requests (account & status search etc.)" msgstr "For the search requests (account & status search etc.)" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:rate_limit > :status_id_action" -msgid "For fav / unfav or reblog / unreblog actions on the same status by the same user" +msgid "" +"For fav / unfav or reblog / unreblog actions on the same status by the same " +"user" msgstr "" "For fav / unfav or reblog / unreblog actions on the same status by the same " "user" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:rate_limit > :statuses_actions" -msgid "For create / delete / fav / unfav / reblog / unreblog actions on any statuses" +msgid "" +"For create / delete / fav / unfav / reblog / unreblog actions on any statuses" msgstr "" "For create / delete / fav / unfav / reblog / unreblog actions on any statuses" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:rate_limit > :timeline" msgid "For requests to timelines (each timeline has it's own limiter)" msgstr "For requests to timelines (each timeline has it's own limiter)" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:restrict_unauthenticated > :activities" +#, fuzzy +msgctxt "" +"config description at :pleroma-:restrict_unauthenticated > :activities" msgid "Settings for statuses." msgstr "Settings for statuses." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:restrict_unauthenticated > :activities > :local" +#, fuzzy +msgctxt "" +"config description at :pleroma-:restrict_unauthenticated > :activities > :" +"local" msgid "Disallow view local statuses." msgstr "Disallow view local statuses." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:restrict_unauthenticated > :activities > :remote" +#, fuzzy +msgctxt "" +"config description at :pleroma-:restrict_unauthenticated > :activities > :" +"remote" msgid "Disallow view remote statuses." msgstr "Disallow view remote statuses." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:restrict_unauthenticated > :profiles" msgid "Settings for user profiles." msgstr "Settings for user profiles." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:restrict_unauthenticated > :profiles > :local" +#, fuzzy +msgctxt "" +"config description at :pleroma-:restrict_unauthenticated > :profiles > :local" msgid "Disallow view local user profiles." msgstr "Disallow view local user profiles." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:restrict_unauthenticated > :profiles > :remote" +#, fuzzy +msgctxt "" +"config description at :pleroma-:restrict_unauthenticated > :profiles > :" +"remote" msgid "Disallow view remote user profiles." msgstr "Disallow view remote user profiles." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:restrict_unauthenticated > :timelines" msgid "Settings for public and federated timelines." msgstr "Settings for public and federated timelines." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:restrict_unauthenticated > :timelines > :federated" +#, fuzzy +msgctxt "" +"config description at :pleroma-:restrict_unauthenticated > :timelines > :" +"federated" msgid "Disallow view federated timeline." msgstr "Disallow view federated timeline." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:restrict_unauthenticated > :timelines > :local" +#, fuzzy +msgctxt "" +"config description at :pleroma-:restrict_unauthenticated > :timelines > :" +"local" msgid "Disallow view public timeline." msgstr "Disallow view public timeline." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:rich_media > :enabled" msgid "Enables RichMedia parsing of URLs" msgstr "Enables RichMedia parsing of URLs" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:rich_media > :failure_backoff" -msgid "Amount of milliseconds after request failure, during which the request will not be retried." +msgid "" +"Amount of milliseconds after request failure, during which the request will " +"not be retried." msgstr "" "Amount of milliseconds after request failure, during which the request will " "not be retried." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:rich_media > :ignore_hosts" msgid "List of hosts which will be ignored by the metadata parser" msgstr "List of hosts which will be ignored by the metadata parser" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:rich_media > :ignore_tld" msgid "List TLDs (top-level domains) which will ignore for parse metadata" msgstr "List TLDs (top-level domains) which will ignore for parse metadata" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:rich_media > :parsers" -msgid "List of Rich Media parsers. Module names are shortened (removed leading `Pleroma.Web.RichMedia.Parsers.` part), but on adding custom module you need to use full name." +msgid "" +"List of Rich Media parsers. Module names are shortened (removed leading " +"`Pleroma.Web.RichMedia.Parsers.` part), but on adding custom module you need " +"to use full name." msgstr "" "List of Rich Media parsers. Module names are shortened (removed leading " "`Pleroma.Web.RichMedia.Parsers.` part), but on adding custom module you need " "to use full name." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:rich_media > :ttl_setters" -msgid "List of rich media TTL setters. Module names are shortened (removed leading `Pleroma.Web.RichMedia.Parser.` part), but on adding custom module you need to use full name." +msgid "" +"List of rich media TTL setters. Module names are shortened (removed leading " +"`Pleroma.Web.RichMedia.Parser.` part), but on adding custom module you need " +"to use full name." msgstr "" "List of rich media TTL setters. Module names are shortened (removed leading " "`Pleroma.Web.RichMedia.Parser.` part), but on adding custom module you need " "to use full name." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:shout > :enabled" msgid "Enables the backend Shoutbox chat feature." msgstr "Enables the backend Shoutbox chat feature." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:shout > :limit" msgid "Shout message character limit." msgstr "Shout message character limit." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:static_fe > :enabled" msgid "Enables the rendering of static HTML. Default: disabled." msgstr "Enables the rendering of static HTML. Default: disabled." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:streamer > :overflow_workers" msgid "Maximum number of workers created if pool is empty" msgstr "Maximum number of workers created if pool is empty" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:streamer > :workers" msgid "Number of workers to send notifications" msgstr "Number of workers to send notifications" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:uri_schemes > :valid_schemes" msgid "List of the scheme part that is considered valid to be an URL" msgstr "List of the scheme part that is considered valid to be an URL" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:web_cache_ttl > :activity_pub" -msgid "Activity pub routes (except question activities). Default: `nil` (no expiration)." +msgid "" +"Activity pub routes (except question activities). Default: `nil` (no " +"expiration)." msgstr "" "Activity pub routes (except question activities). Default: `nil` (no " "expiration)." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:web_cache_ttl > :activity_pub_question" -msgid "Activity pub routes (question activities). Default: `30_000` (30 seconds)." +#, fuzzy +msgctxt "" +"config description at :pleroma-:web_cache_ttl > :activity_pub_question" +msgid "" +"Activity pub routes (question activities). Default: `30_000` (30 seconds)." msgstr "" "Activity pub routes (question activities). Default: `30_000` (30 seconds)." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:welcome > :chat_message > :enabled" msgid "Enables sending a chat message to newly registered users" msgstr "Enables sending a chat message to newly registered users" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:welcome > :chat_message > :message" msgid "A message that will be sent to newly registered users as a chat message" -msgstr "A message that will be sent to newly registered users as a chat message" +msgstr "" +"A message that will be sent to newly registered users as a chat message" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:welcome > :chat_message > :sender_nickname" +#, fuzzy +msgctxt "" +"config description at :pleroma-:welcome > :chat_message > :sender_nickname" msgid "The nickname of the local user that sends a welcome chat message" msgstr "The nickname of the local user that sends a welcome chat message" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:welcome > :direct_message > :enabled" msgid "Enables sending a direct message to newly registered users" msgstr "Enables sending a direct message to newly registered users" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:welcome > :direct_message > :message" msgid "A message that will be sent to newly registered users" msgstr "A message that will be sent to newly registered users" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:welcome > :direct_message > :sender_nickname" +#, fuzzy +msgctxt "" +"config description at :pleroma-:welcome > :direct_message > :sender_nickname" msgid "The nickname of the local user that sends a welcome message" msgstr "The nickname of the local user that sends a welcome message" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:welcome > :email > :enabled" msgid "Enables sending an email to newly registered users" msgstr "Enables sending an email to newly registered users" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:welcome > :email > :html" -msgid "HTML content of the welcome email. EEX template with user and instance_name variables can be used." +msgid "" +"HTML content of the welcome email. EEX template with user and instance_name " +"variables can be used." msgstr "" "HTML content of the welcome email. EEX template with user and instance_name " "variables can be used." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:welcome > :email > :sender" -msgid "Email address and/or nickname that will be used to send the welcome email." +msgid "" +"Email address and/or nickname that will be used to send the welcome email." msgstr "" "Email address and/or nickname that will be used to send the welcome email." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:welcome > :email > :subject" -msgid "Subject of the welcome email. EEX template with user and instance_name variables can be used." +msgid "" +"Subject of the welcome email. EEX template with user and instance_name " +"variables can be used." msgstr "" "Subject of the welcome email. EEX template with user and instance_name " "variables can be used." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:welcome > :email > :text" -msgid "Text content of the welcome email. EEX template with user and instance_name variables can be used." +msgid "" +"Text content of the welcome email. EEX template with user and instance_name " +"variables can be used." msgstr "" "Text content of the welcome email. EEX template with user and instance_name " "variables can be used." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:workers > :retries" msgid "Max retry attempts for failed jobs, per `Oban` queue" msgstr "Max retry attempts for failed jobs, per `Oban` queue" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-ConcurrentLimiter > Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy" +#, fuzzy +msgctxt "" +"config description at :pleroma-ConcurrentLimiter > Pleroma.Web.ActivityPub." +"MRF.MediaProxyWarmingPolicy" msgid "Concurrent limits configuration for MediaProxyWarmingPolicy." msgstr "Concurrent limits configuration for MediaProxyWarmingPolicy." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-ConcurrentLimiter > Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy > :max_running" +#, fuzzy +msgctxt "" +"config description at :pleroma-ConcurrentLimiter > Pleroma.Web.ActivityPub." +"MRF.MediaProxyWarmingPolicy > :max_running" msgid "Max running concurrently jobs." msgstr "Max running concurrently jobs." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-ConcurrentLimiter > Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy > :max_waiting" +#, fuzzy +msgctxt "" +"config description at :pleroma-ConcurrentLimiter > Pleroma.Web.ActivityPub." +"MRF.MediaProxyWarmingPolicy > :max_waiting" msgid "Max waiting jobs." msgstr "Max waiting jobs." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-ConcurrentLimiter > Pleroma.Web.RichMedia.Helpers" +#, fuzzy +msgctxt "" +"config description at :pleroma-ConcurrentLimiter > Pleroma.Web.RichMedia." +"Helpers" msgid "Concurrent limits configuration for getting RichMedia for activities." msgstr "Concurrent limits configuration for getting RichMedia for activities." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-ConcurrentLimiter > Pleroma.Web.RichMedia.Helpers > :max_running" +#, fuzzy +msgctxt "" +"config description at :pleroma-ConcurrentLimiter > Pleroma.Web.RichMedia." +"Helpers > :max_running" msgid "Max running concurrently jobs." msgstr "Max running concurrently jobs." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-ConcurrentLimiter > Pleroma.Web.RichMedia.Helpers > :max_waiting" +#, fuzzy +msgctxt "" +"config description at :pleroma-ConcurrentLimiter > Pleroma.Web.RichMedia." +"Helpers > :max_waiting" msgid "Max waiting jobs." msgstr "Max waiting jobs." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Oban > :crontab" msgid "Settings for cron background jobs" msgstr "Settings for cron background jobs" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Oban > :log" msgid "Logs verbose mode" msgstr "Logs verbose mode" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Oban > :queues" -msgid "Background jobs queues (keys: queues, values: max numbers of concurrent jobs)" +msgid "" +"Background jobs queues (keys: queues, values: max numbers of concurrent jobs)" msgstr "" "Background jobs queues (keys: queues, values: max numbers of concurrent jobs)" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Oban > :queues > :activity_expiration" msgid "Activity expiration queue" msgstr "Activity expiration queue" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Oban > :queues > :attachments_cleanup" msgid "Attachment deletion queue" msgstr "Attachment deletion queue" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Oban > :queues > :background" msgid "Background queue" msgstr "Background queue" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Oban > :queues > :backup" msgid "Backup queue" msgstr "Backup queue" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Oban > :queues > :federator_incoming" msgid "Incoming federation queue" msgstr "Incoming federation queue" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Oban > :queues > :federator_outgoing" msgid "Outgoing federation queue" msgstr "Outgoing federation queue" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Oban > :queues > :mailer" msgid "Email sender queue, see Pleroma.Emails.Mailer" msgstr "Email sender queue, see Pleroma.Emails.Mailer" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Oban > :queues > :scheduled_activities" msgid "Scheduled activities queue, see Pleroma.ScheduledActivities" msgstr "Scheduled activities queue, see Pleroma.ScheduledActivities" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Oban > :queues > :transmogrifier" msgid "Transmogrifier queue" msgstr "Transmogrifier queue" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Oban > :queues > :web_push" msgid "Web push notifications queue" msgstr "Web push notifications queue" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Captcha > :enabled" msgid "Whether the captcha should be shown on registration" msgstr "Whether the captcha should be shown on registration" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Captcha > :method" msgid "The method/service to use for captcha" msgstr "The method/service to use for captcha" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Captcha > :seconds_valid" msgid "The time in seconds for which the captcha is valid" msgstr "The time in seconds for which the captcha is valid" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Captcha.Kocaptcha > :endpoint" msgid "The kocaptcha endpoint to use" msgstr "The kocaptcha endpoint to use" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Emails.Mailer > :adapter" -msgid "One of the mail adapters listed in [Swoosh documentation](https://hexdocs.pm/swoosh/Swoosh.html#module-adapters)" +msgid "" +"One of the mail adapters listed in [Swoosh documentation](https://hexdocs.pm/" +"swoosh/Swoosh.html#module-adapters)" msgstr "" "One of the mail adapters listed in [Swoosh documentation](https://hexdocs.pm/" "swoosh/Swoosh.html#module-adapters)" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SMTP-:auth" +#, fuzzy +msgctxt "" +"config description at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SMTP-:" +"auth" msgid "SMTP AUTH enforcement mode" msgstr "SMTP AUTH enforcement mode" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SMTP-:password" +#, fuzzy +msgctxt "" +"config description at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SMTP-:" +"password" msgid "SMTP AUTH password" msgstr "SMTP AUTH password" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SMTP-:port" +#, fuzzy +msgctxt "" +"config description at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SMTP-:" +"port" msgid "SMTP port" msgstr "SMTP port" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SMTP-:relay" +#, fuzzy +msgctxt "" +"config description at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SMTP-:" +"relay" msgid "Hostname or IP address" msgstr "Hostname or IP address" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SMTP-:retries" +#, fuzzy +msgctxt "" +"config description at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SMTP-:" +"retries" msgid "SMTP temporary (4xx) error retries" msgstr "SMTP temporary (4xx) error retries" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SMTP-:ssl" +#, fuzzy +msgctxt "" +"config description at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SMTP-:" +"ssl" msgid "Use Implicit SSL/TLS. e.g. port 465" msgstr "Use Implicit SSL/TLS. e.g. port 465" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SMTP-:tls" +#, fuzzy +msgctxt "" +"config description at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SMTP-:" +"tls" msgid "Explicit TLS (STARTTLS) enforcement mode" msgstr "Explicit TLS (STARTTLS) enforcement mode" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SMTP-:username" +#, fuzzy +msgctxt "" +"config description at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SMTP-:" +"username" msgid "SMTP AUTH username" msgstr "SMTP AUTH username" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-Pleroma.Emails.NewUsersDigestEmail > :enabled" +#, fuzzy +msgctxt "" +"config description at :pleroma-Pleroma.Emails.NewUsersDigestEmail > :enabled" msgid "Enables new users admin digest email when `true`" msgstr "Enables new users admin digest email when `true`" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Emails.UserEmail > :logo" -msgid "A path to a custom logo. Set it to `nil` to use the default Pleroma logo." +msgid "" +"A path to a custom logo. Set it to `nil` to use the default Pleroma logo." msgstr "" "A path to a custom logo. Set it to `nil` to use the default Pleroma logo." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Emails.UserEmail > :styling" msgid "A map with color settings for email templates." msgstr "A map with color settings for email templates." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Formatter > :class" msgid "Specify the class to be added to the generated link. Disable to clear." msgstr "Specify the class to be added to the generated link. Disable to clear." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Formatter > :extra" msgid "Link URLs with rarely used schemes (magnet, ipfs, irc, etc.)" msgstr "Link URLs with rarely used schemes (magnet, ipfs, irc, etc.)" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Formatter > :new_window" msgid "Link URLs will open in a new window/tab." msgstr "Link URLs will open in a new window/tab." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Formatter > :rel" msgid "Override the rel attribute. Disable to clear." msgstr "Override the rel attribute. Disable to clear." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Formatter > :strip_prefix" msgid "Strip the scheme prefix." msgstr "Strip the scheme prefix." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Formatter > :truncate" -msgid "Set to a number to truncate URLs longer than the number. Truncated URLs will end in `...`" +msgid "" +"Set to a number to truncate URLs longer than the number. Truncated URLs will " +"end in `...`" msgstr "" "Set to a number to truncate URLs longer than the number. Truncated URLs will " "end in `...`" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Formatter > :validate_tld" -msgid "Set to false to disable TLD validation for URLs/emails. Can be set to :no_scheme to validate TLDs only for URLs without a scheme (e.g `example.com` will be validated, but `http://example.loki` won't)" +msgid "" +"Set to false to disable TLD validation for URLs/emails. Can be set to :" +"no_scheme to validate TLDs only for URLs without a scheme (e.g `example.com` " +"will be validated, but `http://example.loki` won't)" msgstr "" "Set to false to disable TLD validation for URLs/emails. Can be set to :" "no_scheme to validate TLDs only for URLs without a scheme (e.g `example.com` " "will be validated, but `http://example.loki` won't)" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-Pleroma.ScheduledActivity > :daily_user_limit" -msgid "The number of scheduled activities a user is allowed to create in a single day. Default: 25." +#, fuzzy +msgctxt "" +"config description at :pleroma-Pleroma.ScheduledActivity > :daily_user_limit" +msgid "" +"The number of scheduled activities a user is allowed to create in a single " +"day. Default: 25." msgstr "" "The number of scheduled activities a user is allowed to create in a single " "day. Default: 25." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.ScheduledActivity > :enabled" msgid "Whether scheduled activities are sent to the job queue to be executed" msgstr "Whether scheduled activities are sent to the job queue to be executed" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-Pleroma.ScheduledActivity > :total_user_limit" -msgid "The number of scheduled activities a user is allowed to create in total. Default: 300." +#, fuzzy +msgctxt "" +"config description at :pleroma-Pleroma.ScheduledActivity > :total_user_limit" +msgid "" +"The number of scheduled activities a user is allowed to create in total. " +"Default: 300." msgstr "" "The number of scheduled activities a user is allowed to create in total. " "Default: 300." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Upload > :base_url" -msgid "Base URL for the uploads. Required if you use a CDN or host attachments under a different domain." +msgid "" +"Base URL for the uploads. Required if you use a CDN or host attachments " +"under a different domain." msgstr "" "Base URL for the uploads. Required if you use a CDN or host attachments " "under a different domain." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-Pleroma.Upload > :filename_display_max_length" +#, fuzzy +msgctxt "" +"config description at :pleroma-Pleroma.Upload > :filename_display_max_length" msgid "Set max length of a filename to display. 0 = no limit. Default: 30" msgstr "Set max length of a filename to display. 0 = no limit. Default: 30" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Upload > :filters" -msgid "List of filter modules for uploads. Module names are shortened (removed leading `Pleroma.Upload.Filter.` part), but on adding custom module you need to use full name." +msgid "" +"List of filter modules for uploads. Module names are shortened (removed " +"leading `Pleroma.Upload.Filter.` part), but on adding custom module you need " +"to use full name." msgstr "" "List of filter modules for uploads. Module names are shortened (removed " "leading `Pleroma.Upload.Filter.` part), but on adding custom module you need " "to use full name." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Upload > :link_name" -msgid "If enabled, a name parameter will be added to the URL of the upload. For example `https://instance.tld/media/imagehash.png?name=realname.png`." +msgid "" +"If enabled, a name parameter will be added to the URL of the upload. For " +"example `https://instance.tld/media/imagehash.png?name=realname.png`." msgstr "" "If enabled, a name parameter will be added to the URL of the upload. For " "example `https://instance.tld/media/imagehash.png?name=realname.png`." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Upload > :proxy_remote" -msgid "Proxy requests to the remote uploader.\n\nUseful if media upload endpoint is not internet accessible.\n" +msgid "" +"Proxy requests to the remote uploader.\n" +"\n" +"Useful if media upload endpoint is not internet accessible.\n" msgstr "" "Proxy requests to the remote uploader.\n" "\n" "Useful if media upload endpoint is not internet accessible.\n" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Upload > :uploader" msgid "Module which will be used for uploads" msgstr "Module which will be used for uploads" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-Pleroma.Upload.Filter.AnonymizeFilename > :text" -msgid "Text to replace filenames in links. If no setting, {random}.extension will be used. You can get the original filename extension by using {extension}, for example custom-file-name.{extension}." +#, fuzzy +msgctxt "" +"config description at :pleroma-Pleroma.Upload.Filter.AnonymizeFilename > :" +"text" +msgid "" +"Text to replace filenames in links. If no setting, {random}.extension will " +"be used. You can get the original filename extension by using {extension}, " +"for example custom-file-name.{extension}." msgstr "" "Text to replace filenames in links. If no setting, {random}.extension will " "be used. You can get the original filename extension by using {extension}, " "for example custom-file-name.{extension}." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Upload.Filter.Mogrify > :args" -msgid "List of actions for the mogrify command. It's possible to add self-written settings as string. For example `auto-orient, strip, {\"resize\", \"3840x1080>\"}` value will be parsed into valid list of the settings." +msgid "" +"List of actions for the mogrify command. It's possible to add self-written " +"settings as string. For example `auto-orient, strip, {\"resize\", " +"\"3840x1080>\"}` value will be parsed into valid list of the settings." msgstr "" "List of actions for the mogrify command. It's possible to add self-written " -"settings as string. For example `auto-orient, strip, {\"resize\", \"3840x1080" -">\"}` value will be parsed into valid list of the settings." +"settings as string. For example `auto-orient, strip, {\"resize\", " +"\"3840x1080>\"}` value will be parsed into valid list of the settings." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Uploaders.Local > :uploads" msgid "Path where user's uploads will be saved" msgstr "Path where user's uploads will be saved" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Uploaders.S3 > :bucket" msgid "S3 bucket" msgstr "S3 bucket" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-Pleroma.Uploaders.S3 > :bucket_namespace" +#, fuzzy +msgctxt "" +"config description at :pleroma-Pleroma.Uploaders.S3 > :bucket_namespace" msgid "S3 bucket namespace" msgstr "S3 bucket namespace" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-Pleroma.Uploaders.S3 > :streaming_enabled" -msgid "Enable streaming uploads, when enabled the file will be sent to the server in chunks as it's being read. This may be unsupported by some providers, try disabling this if you have upload problems." +#, fuzzy +msgctxt "" +"config description at :pleroma-Pleroma.Uploaders.S3 > :streaming_enabled" +msgid "" +"Enable streaming uploads, when enabled the file will be sent to the server " +"in chunks as it's being read. This may be unsupported by some providers, try " +"disabling this if you have upload problems." msgstr "" "Enable streaming uploads, when enabled the file will be sent to the server " "in chunks as it's being read. This may be unsupported by some providers, try " "disabling this if you have upload problems." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-Pleroma.Uploaders.S3 > :truncated_namespace" -msgid "If you use S3 compatible service such as Digital Ocean Spaces or CDN, set folder name or \"\" etc. For example, when using CDN to S3 virtual host format, set \"\". At this time, write CNAME to CDN in Upload base_url." +#, fuzzy +msgctxt "" +"config description at :pleroma-Pleroma.Uploaders.S3 > :truncated_namespace" +msgid "" +"If you use S3 compatible service such as Digital Ocean Spaces or CDN, set " +"folder name or \"\" etc. For example, when using CDN to S3 virtual host " +"format, set \"\". At this time, write CNAME to CDN in Upload base_url." msgstr "" "If you use S3 compatible service such as Digital Ocean Spaces or CDN, set " "folder name or \"\" etc. For example, when using CDN to S3 virtual host " "format, set \"\". At this time, write CNAME to CDN in Upload base_url." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.User > :email_blacklist" msgid "List of email domains users may not register with." msgstr "List of email domains users may not register with." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.User > :restricted_nicknames" msgid "List of nicknames users may not register with." msgstr "List of nicknames users may not register with." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.User.Backup > :limit_days" msgid "Limit user to export not more often than once per N days" msgstr "Limit user to export not more often than once per N days" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-Pleroma.User.Backup > :purge_after_days" +#, fuzzy +msgctxt "" +"config description at :pleroma-Pleroma.User.Backup > :purge_after_days" msgid "Remove backup achives after N days" msgstr "Remove backup achives after N days" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-Pleroma.Web.ApiSpec.CastAndValidate > :strict" -msgid "Enables strict input validation (useful in development, not recommended in production)" +#, fuzzy +msgctxt "" +"config description at :pleroma-Pleroma.Web.ApiSpec.CastAndValidate > :strict" +msgid "" +"Enables strict input validation (useful in development, not recommended in " +"production)" msgstr "" "Enables strict input validation (useful in development, not recommended in " "production)" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-Pleroma.Web.MediaProxy.Invalidation.Http > :headers" +#, fuzzy +msgctxt "" +"config description at :pleroma-Pleroma.Web.MediaProxy.Invalidation.Http > :" +"headers" msgid "HTTP headers of request" msgstr "HTTP headers of request" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-Pleroma.Web.MediaProxy.Invalidation.Http > :method" +#, fuzzy +msgctxt "" +"config description at :pleroma-Pleroma.Web.MediaProxy.Invalidation.Http > :" +"method" msgid "HTTP method of request. Default: :purge" msgstr "HTTP method of request. Default: :purge" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-Pleroma.Web.MediaProxy.Invalidation.Http > :options" +#, fuzzy +msgctxt "" +"config description at :pleroma-Pleroma.Web.MediaProxy.Invalidation.Http > :" +"options" msgid "Request options" msgstr "Request options" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-Pleroma.Web.MediaProxy.Invalidation.Script > :script_path" +#, fuzzy +msgctxt "" +"config description at :pleroma-Pleroma.Web.MediaProxy.Invalidation.Script > :" +"script_path" msgid "Path to executable script which will purge cached items." msgstr "Path to executable script which will purge cached items." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-Pleroma.Web.MediaProxy.Invalidation.Script > :url_format" -msgid "Optional URL format preprocessing. Only required for Apache's htcacheclean." +#, fuzzy +msgctxt "" +"config description at :pleroma-Pleroma.Web.MediaProxy.Invalidation.Script > :" +"url_format" +msgid "" +"Optional URL format preprocessing. Only required for Apache's htcacheclean." msgstr "" "Optional URL format preprocessing. Only required for Apache's htcacheclean." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Web.Metadata > :providers" msgid "List of metadata providers to enable" msgstr "List of metadata providers to enable" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Web.Metadata > :unfurl_nsfw" msgid "When enabled NSFW attachments will be shown in previews" msgstr "When enabled NSFW attachments will be shown in previews" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Web.Plugs.RemoteIp > :enabled" msgid "Enable/disable the plug. Default: disabled." msgstr "Enable/disable the plug. Default: disabled." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Web.Plugs.RemoteIp > :headers" -msgid " A list of strings naming the HTTP headers to use when deriving the true client IP. Default: `[\"x-forwarded-for\"]`.\n" +msgid "" +" A list of strings naming the HTTP headers to use when deriving the true " +"client IP. Default: `[\"x-forwarded-for\"]`.\n" msgstr "" " A list of strings naming the HTTP headers to use when deriving the true " "client IP. Default: `[\"x-forwarded-for\"]`.\n" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Web.Plugs.RemoteIp > :proxies" -msgid "A list of upstream proxy IP subnets in CIDR notation from which we will parse the content of `headers`. Defaults to `[]`. IPv4 entries without a bitmask will be assumed to be /32 and IPv6 /128." +msgid "" +"A list of upstream proxy IP subnets in CIDR notation from which we will " +"parse the content of `headers`. Defaults to `[]`. IPv4 entries without a " +"bitmask will be assumed to be /32 and IPv6 /128." msgstr "" "A list of upstream proxy IP subnets in CIDR notation from which we will " "parse the content of `headers`. Defaults to `[]`. IPv4 entries without a " "bitmask will be assumed to be /32 and IPv6 /128." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Web.Plugs.RemoteIp > :reserved" -msgid " A list of reserved IP subnets in CIDR notation which should be ignored if found in `headers`. Defaults to `[\"127.0.0.0/8\", \"::1/128\", \"fc00::/7\", \"10.0.0.0/8\", \"172.16.0.0/12\", \"192.168.0.0/16\"]`\n" +msgid "" +" A list of reserved IP subnets in CIDR notation which should be ignored if " +"found in `headers`. Defaults to `[\"127.0.0.0/8\", \"::1/128\", " +"\"fc00::/7\", \"10.0.0.0/8\", \"172.16.0.0/12\", \"192.168.0.0/16\"]`\n" msgstr "" " A list of reserved IP subnets in CIDR notation which should be ignored if " -"found in `headers`. Defaults to `[\"127.0.0.0/8\", \"::1/128\", \"fc00::/7\"" -", \"10.0.0.0/8\", \"172.16.0.0/12\", \"192.168.0.0/16\"]`\n" +"found in `headers`. Defaults to `[\"127.0.0.0/8\", \"::1/128\", " +"\"fc00::/7\", \"10.0.0.0/8\", \"172.16.0.0/12\", \"192.168.0.0/16\"]`\n" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-Pleroma.Web.Preload > :providers" msgid "List of preload providers to enable" msgstr "List of preload providers to enable" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-Pleroma.Workers.PurgeExpiredActivity > :enabled" +#, fuzzy +msgctxt "" +"config description at :pleroma-Pleroma.Workers.PurgeExpiredActivity > :" +"enabled" msgid "Enables expired activities addition & deletion" msgstr "Enables expired activities addition & deletion" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-Pleroma.Workers.PurgeExpiredActivity > :min_lifetime" +#, fuzzy +msgctxt "" +"config description at :pleroma-Pleroma.Workers.PurgeExpiredActivity > :" +"min_lifetime" msgid "Minimum lifetime for ephemeral activity (in seconds)" msgstr "Minimum lifetime for ephemeral activity (in seconds)" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :prometheus-Pleroma.Web.Endpoint.MetricsExporter > :auth" +#, fuzzy +msgctxt "" +"config description at :prometheus-Pleroma.Web.Endpoint.MetricsExporter > :" +"auth" msgid "Enables HTTP Basic Auth for app metrics endpoint." msgstr "Enables HTTP Basic Auth for app metrics endpoint." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :prometheus-Pleroma.Web.Endpoint.MetricsExporter > :enabled" +#, fuzzy +msgctxt "" +"config description at :prometheus-Pleroma.Web.Endpoint.MetricsExporter > :" +"enabled" msgid "[Pleroma extension] Enables app metrics endpoint." msgstr "[Pleroma extension] Enables app metrics endpoint." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :prometheus-Pleroma.Web.Endpoint.MetricsExporter > :format" +#, fuzzy +msgctxt "" +"config description at :prometheus-Pleroma.Web.Endpoint.MetricsExporter > :" +"format" msgid "App metrics endpoint output format." msgstr "App metrics endpoint output format." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :prometheus-Pleroma.Web.Endpoint.MetricsExporter > :ip_whitelist" +#, fuzzy +msgctxt "" +"config description at :prometheus-Pleroma.Web.Endpoint.MetricsExporter > :" +"ip_whitelist" msgid "Restrict access of app metrics endpoint to the specified IP addresses." msgstr "Restrict access of app metrics endpoint to the specified IP addresses." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :prometheus-Pleroma.Web.Endpoint.MetricsExporter > :path" +#, fuzzy +msgctxt "" +"config description at :prometheus-Pleroma.Web.Endpoint.MetricsExporter > :" +"path" msgid "App metrics endpoint URI path." msgstr "App metrics endpoint URI path." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :quack > :level" msgid "Log level" msgstr "Log level" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :quack > :meta" msgid "Configure which metadata you want to report on" msgstr "Configure which metadata you want to report on" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :quack > :webhook_url" msgid "Configure the Slack incoming webhook" msgstr "Configure the Slack incoming webhook" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :web_push_encryption-:vapid_details > :private_key" +#, fuzzy +msgctxt "" +"config description at :web_push_encryption-:vapid_details > :private_key" msgid "VAPID private key" msgstr "VAPID private key" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :web_push_encryption-:vapid_details > :public_key" +#, fuzzy +msgctxt "" +"config description at :web_push_encryption-:vapid_details > :public_key" msgid "VAPID public key" msgstr "VAPID public key" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :web_push_encryption-:vapid_details > :subject" -msgid "A mailto link for the administrative contact. It's best if this email is not a personal email address, but rather a group email to the instance moderation team." +msgid "" +"A mailto link for the administrative contact. It's best if this email is not " +"a personal email address, but rather a group email to the instance " +"moderation team." msgstr "" "A mailto link for the administrative contact. It's best if this email is not " "a personal email address, but rather a group email to the instance " "moderation team." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :cors_plug > :credentials" msgid "Credentials" msgstr "Credentials" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :cors_plug > :expose" msgid "Expose" msgstr "Expose" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :cors_plug > :headers" msgid "Headers" msgstr "Headers" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :cors_plug > :max_age" msgid "Max age" msgstr "Max age" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :cors_plug > :methods" msgid "Methods" msgstr "Methods" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :esshd > :enabled" msgid "Enabled" msgstr "Enabled" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :esshd > :handler" msgid "Handler" msgstr "Handler" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :esshd > :password_authenticator" msgid "Password authenticator" msgstr "Password authenticator" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :esshd > :port" msgid "Port" msgstr "Port" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :esshd > :priv_dir" msgid "Priv dir" msgstr "Priv dir" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :ex_aws-:s3 > :access_key_id" msgid "Access key" msgstr "Access key" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :ex_aws-:s3 > :host" msgid "Host" msgstr "Host" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :ex_aws-:s3 > :region" msgid "Region" msgstr "Region" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :ex_aws-:s3 > :secret_access_key" msgid "Secret access key" msgstr "Secret access key" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :logger > :backends" msgid "Backends" msgstr "Backends" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :logger-:console > :format" msgid "Format" msgstr "Format" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :logger-:console > :level" msgid "Level" msgstr "Level" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :logger-:console > :metadata" msgid "Metadata" msgstr "Metadata" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :logger-:ex_syslogger > :format" msgid "Format" msgstr "Format" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :logger-:ex_syslogger > :ident" msgid "Ident" msgstr "Ident" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :logger-:ex_syslogger > :level" msgid "Level" msgstr "Level" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :logger-:ex_syslogger > :metadata" msgid "Metadata" msgstr "Metadata" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :mime > :types" msgid "Types" msgstr "Types" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :mime > :types > application/activity+json" msgid "\"application/activity+json\"" msgstr "\"application/activity+json\"" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :mime > :types > application/jrd+json" msgid "\"application/jrd+json\"" msgstr "\"application/jrd+json\"" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :mime > :types > application/ld+json" msgid "\"application/ld+json\"" msgstr "\"application/ld+json\"" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :mime > :types > application/xml" msgid "\"application/xml\"" msgstr "\"application/xml\"" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :mime > :types > application/xrd+xml" msgid "\"application/xrd+xml\"" msgstr "\"application/xrd+xml\"" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma > :admin_token" msgid "Admin token" msgstr "Admin token" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma > Pleroma.Web.Auth.Authenticator" msgid "Pleroma.Web.Auth.Authenticator" msgstr "Pleroma.Web.Auth.Authenticator" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:activitypub > :blockers_visible" msgid "Blockers visible" msgstr "Blockers visible" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:activitypub > :follow_handshake_timeout" msgid "Follow handshake timeout" msgstr "Follow handshake timeout" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:activitypub > :note_replies_output_limit" msgid "Note replies output limit" msgstr "Note replies output limit" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:activitypub > :outgoing_blocks" msgid "Outgoing blocks" msgstr "Outgoing blocks" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:activitypub > :sign_object_fetches" msgid "Sign object fetches" msgstr "Sign object fetches" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:activitypub > :unfollow_blocked" msgid "Unfollow blocked" msgstr "Unfollow blocked" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:assets > :default_mascot" msgid "Default mascot" msgstr "Default mascot" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:assets > :default_user_avatar" msgid "Default user avatar" msgstr "Default user avatar" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:assets > :mascots" msgid "Mascots" msgstr "Mascots" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:auth > :auth_template" msgid "Auth template" msgstr "Auth template" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:auth > :enforce_oauth_admin_scope_usage" msgid "Enforce OAuth admin scope usage" msgstr "Enforce OAuth admin scope usage" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:auth > :oauth_consumer_strategies" msgid "OAuth consumer strategies" msgstr "OAuth consumer strategies" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:auth > :oauth_consumer_template" msgid "OAuth consumer template" msgstr "OAuth consumer template" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:connections_pool > :connect_timeout" msgid "Connect timeout" msgstr "Connect timeout" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:connections_pool > :connection_acquisition_retries" +#, fuzzy +msgctxt "" +"config label at :pleroma-:connections_pool > :connection_acquisition_retries" msgid "Connection acquisition retries" msgstr "Connection acquisition retries" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:connections_pool > :connection_acquisition_wait" +#, fuzzy +msgctxt "" +"config label at :pleroma-:connections_pool > :connection_acquisition_wait" msgid "Connection acquisition wait" msgstr "Connection acquisition wait" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:connections_pool > :max_connections" msgid "Max connections" msgstr "Max connections" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:connections_pool > :reclaim_multiplier" msgid "Reclaim multiplier" msgstr "Reclaim multiplier" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:email_notifications > :digest" msgid "Digest" msgstr "Digest" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:email_notifications > :digest > :active" msgid "Enabled" msgstr "Enabled" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:email_notifications > :digest > :inactivity_threshold" +#, fuzzy +msgctxt "" +"config label at :pleroma-:email_notifications > :digest > :" +"inactivity_threshold" msgid "Inactivity threshold" msgstr "Inactivity threshold" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:email_notifications > :digest > :interval" msgid "Interval" msgstr "Interval" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:email_notifications > :digest > :schedule" msgid "Schedule" msgstr "Schedule" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:emoji > :default_manifest" msgid "Default manifest" msgstr "Default manifest" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:emoji > :groups" msgid "Groups" msgstr "Groups" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:emoji > :pack_extensions" msgid "Pack extensions" msgstr "Pack extensions" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:emoji > :shared_pack_cache_seconds_per_file" msgid "Shared pack cache s/file" msgstr "Shared pack cache s/file" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:emoji > :shortcode_globs" msgid "Shortcode globs" msgstr "Shortcode globs" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:features > :improved_hashtag_timeline" msgid "Improved hashtag timeline" msgstr "Improved hashtag timeline" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:feed > :post_title" msgid "Post title" msgstr "Post title" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:feed > :post_title > :max_length" msgid "Max length" msgstr "Max length" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:feed > :post_title > :omission" msgid "Omission" msgstr "Omission" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:frontend_configurations > :pleroma_fe" msgid "Pleroma FE" msgstr "Pleroma FE" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:frontend_configurations > :pleroma_fe > :alwaysShowSubjectInput" +#, fuzzy +msgctxt "" +"config label at :pleroma-:frontend_configurations > :pleroma_fe > :" +"alwaysShowSubjectInput" msgid "Always show subject input" msgstr "Always show subject input" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:frontend_configurations > :pleroma_fe > :background" +#, fuzzy +msgctxt "" +"config label at :pleroma-:frontend_configurations > :pleroma_fe > :background" msgid "Background" msgstr "Background" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:frontend_configurations > :pleroma_fe > :collapseMessageWithSubject" +#, fuzzy +msgctxt "" +"config label at :pleroma-:frontend_configurations > :pleroma_fe > :" +"collapseMessageWithSubject" msgid "Collapse message with subject" msgstr "Collapse message with subject" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:frontend_configurations > :pleroma_fe > :greentext" +#, fuzzy +msgctxt "" +"config label at :pleroma-:frontend_configurations > :pleroma_fe > :greentext" msgid "Greentext" msgstr "Greentext" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:frontend_configurations > :pleroma_fe > :hideFilteredStatuses" +#, fuzzy +msgctxt "" +"config label at :pleroma-:frontend_configurations > :pleroma_fe > :" +"hideFilteredStatuses" msgid "Hide Filtered Statuses" msgstr "Hide Filtered Statuses" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:frontend_configurations > :pleroma_fe > :hideMutedPosts" +#, fuzzy +msgctxt "" +"config label at :pleroma-:frontend_configurations > :pleroma_fe > :" +"hideMutedPosts" msgid "Hide Muted Posts" msgstr "Hide Muted Posts" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:frontend_configurations > :pleroma_fe > :hidePostStats" +#, fuzzy +msgctxt "" +"config label at :pleroma-:frontend_configurations > :pleroma_fe > :" +"hidePostStats" msgid "Hide post stats" msgstr "Hide post stats" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:frontend_configurations > :pleroma_fe > :hideSitename" +#, fuzzy +msgctxt "" +"config label at :pleroma-:frontend_configurations > :pleroma_fe > :" +"hideSitename" msgid "Hide Sitename" msgstr "Hide Sitename" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:frontend_configurations > :pleroma_fe > :hideUserStats" +#, fuzzy +msgctxt "" +"config label at :pleroma-:frontend_configurations > :pleroma_fe > :" +"hideUserStats" msgid "Hide user stats" msgstr "Hide user stats" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:frontend_configurations > :pleroma_fe > :logo" +#, fuzzy +msgctxt "" +"config label at :pleroma-:frontend_configurations > :pleroma_fe > :logo" msgid "Logo" msgstr "Logo" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:frontend_configurations > :pleroma_fe > :logoMargin" +#, fuzzy +msgctxt "" +"config label at :pleroma-:frontend_configurations > :pleroma_fe > :logoMargin" msgid "Logo margin" msgstr "Logo margin" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:frontend_configurations > :pleroma_fe > :logoMask" +#, fuzzy +msgctxt "" +"config label at :pleroma-:frontend_configurations > :pleroma_fe > :logoMask" msgid "Logo mask" msgstr "Logo mask" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:frontend_configurations > :pleroma_fe > :minimalScopesMode" +#, fuzzy +msgctxt "" +"config label at :pleroma-:frontend_configurations > :pleroma_fe > :" +"minimalScopesMode" msgid "Minimal scopes mode" msgstr "Minimal scopes mode" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:frontend_configurations > :pleroma_fe > :nsfwCensorImage" +#, fuzzy +msgctxt "" +"config label at :pleroma-:frontend_configurations > :pleroma_fe > :" +"nsfwCensorImage" msgid "NSFW Censor Image" msgstr "NSFW Censor Image" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:frontend_configurations > :pleroma_fe > :postContentType" +#, fuzzy +msgctxt "" +"config label at :pleroma-:frontend_configurations > :pleroma_fe > :" +"postContentType" msgid "Post Content Type" msgstr "Post Content Type" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:frontend_configurations > :pleroma_fe > :redirectRootLogin" +#, fuzzy +msgctxt "" +"config label at :pleroma-:frontend_configurations > :pleroma_fe > :" +"redirectRootLogin" msgid "Redirect root login" msgstr "Redirect root login" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:frontend_configurations > :pleroma_fe > :redirectRootNoLogin" +#, fuzzy +msgctxt "" +"config label at :pleroma-:frontend_configurations > :pleroma_fe > :" +"redirectRootNoLogin" msgid "Redirect root no login" msgstr "Redirect root no login" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:frontend_configurations > :pleroma_fe > :scopeCopy" +#, fuzzy +msgctxt "" +"config label at :pleroma-:frontend_configurations > :pleroma_fe > :scopeCopy" msgid "Scope copy" msgstr "Scope copy" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:frontend_configurations > :pleroma_fe > :showFeaturesPanel" +#, fuzzy +msgctxt "" +"config label at :pleroma-:frontend_configurations > :pleroma_fe > :" +"showFeaturesPanel" msgid "Show instance features panel" msgstr "Show instance features panel" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:frontend_configurations > :pleroma_fe > :showInstanceSpecificPanel" +#, fuzzy +msgctxt "" +"config label at :pleroma-:frontend_configurations > :pleroma_fe > :" +"showInstanceSpecificPanel" msgid "Show instance specific panel" msgstr "Show instance specific panel" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:frontend_configurations > :pleroma_fe > :sidebarRight" +#, fuzzy +msgctxt "" +"config label at :pleroma-:frontend_configurations > :pleroma_fe > :" +"sidebarRight" msgid "Sidebar on Right" msgstr "Sidebar on Right" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:frontend_configurations > :pleroma_fe > :subjectLineBehavior" +#, fuzzy +msgctxt "" +"config label at :pleroma-:frontend_configurations > :pleroma_fe > :" +"subjectLineBehavior" msgid "Subject line behavior" msgstr "Subject line behavior" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:frontend_configurations > :pleroma_fe > :theme" +#, fuzzy +msgctxt "" +"config label at :pleroma-:frontend_configurations > :pleroma_fe > :theme" msgid "Theme" msgstr "Theme" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:frontends > :admin" msgid "Admin" msgstr "Admin" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:frontends > :admin > name" msgid "Name" msgstr "Name" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:frontends > :admin > ref" msgid "Reference" msgstr "Reference" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:frontends > :available" msgid "Available" msgstr "Available" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:frontends > :available > build_dir" msgid "Build directory" msgstr "Build directory" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:frontends > :available > build_url" msgid "Build URL" msgstr "Build URL" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:frontends > :available > custom-http-headers" +#, fuzzy +msgctxt "" +"config label at :pleroma-:frontends > :available > custom-http-headers" msgid "Custom HTTP headers" msgstr "Custom HTTP headers" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:frontends > :available > git" msgid "Git Repository URL" msgstr "Git Repository URL" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:frontends > :available > name" msgid "Name" msgstr "Name" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:frontends > :available > ref" msgid "Reference" msgstr "Reference" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:frontends > :primary" msgid "Primary" msgstr "Primary" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:frontends > :primary > name" msgid "Name" msgstr "Name" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:frontends > :primary > ref" msgid "Reference" msgstr "Reference" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:gopher > :dstport" msgid "Dstport" msgstr "Dstport" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:gopher > :enabled" msgid "Enabled" msgstr "Enabled" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:gopher > :ip" msgid "IP" msgstr "IP" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:gopher > :port" msgid "Port" msgstr "Port" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:hackney_pools > :federation" msgid "Federation" msgstr "Federation" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:hackney_pools > :federation > :max_connections" +#, fuzzy +msgctxt "" +"config label at :pleroma-:hackney_pools > :federation > :max_connections" msgid "Max connections" msgstr "Max connections" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:hackney_pools > :federation > :timeout" msgid "Timeout" msgstr "Timeout" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:hackney_pools > :media" msgid "Media" msgstr "Media" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:hackney_pools > :media > :max_connections" msgid "Max connections" msgstr "Max connections" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:hackney_pools > :media > :timeout" msgid "Timeout" msgstr "Timeout" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:hackney_pools > :upload" msgid "Upload" msgstr "Upload" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:hackney_pools > :upload > :max_connections" msgid "Max connections" msgstr "Max connections" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:hackney_pools > :upload > :timeout" msgid "Timeout" msgstr "Timeout" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:http > :adapter" msgid "Adapter" msgstr "Adapter" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:http > :adapter > :ssl_options" msgid "SSL Options" msgstr "SSL Options" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:http > :adapter > :ssl_options > :versions" msgid "Versions" msgstr "Versions" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:http > :proxy_url" msgid "Proxy URL" msgstr "Proxy URL" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:http > :send_user_agent" msgid "Send user agent" msgstr "Send user agent" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:http > :user_agent" msgid "User agent" msgstr "User agent" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:http_security > :enabled" msgid "Enabled" msgstr "Enabled" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:http_security > :referrer_policy" msgid "Referrer policy" msgstr "Referrer policy" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:http_security > :report_uri" msgid "Report URI" msgstr "Report URI" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:http_security > :sts" msgid "STS" msgstr "STS" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:http_security > :sts_max_age" msgid "STS max age" msgstr "STS max age" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :account_activation_required" msgid "Account activation required" msgstr "Account activation required" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :account_approval_required" msgid "Account approval required" msgstr "Account approval required" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :account_field_name_length" msgid "Account field name length" msgstr "Account field name length" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :account_field_value_length" msgid "Account field value length" msgstr "Account field value length" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :allow_relay" msgid "Allow relay" msgstr "Allow relay" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :allowed_post_formats" msgid "Allowed post formats" msgstr "Allowed post formats" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :attachment_links" msgid "Attachment links" msgstr "Attachment links" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :autofollowed_nicknames" msgid "Autofollowed nicknames" msgstr "Autofollowed nicknames" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :autofollowing_nicknames" msgid "Autofollowing nicknames" msgstr "Autofollowing nicknames" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :avatar_upload_limit" msgid "Avatar upload limit" msgstr "Avatar upload limit" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :background_upload_limit" msgid "Background upload limit" msgstr "Background upload limit" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :banner_upload_limit" msgid "Banner upload limit" msgstr "Banner upload limit" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :birthday_min_age" msgid "Birthday min age" msgstr "Birthday min age" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :birthday_required" msgid "Birthday required" msgstr "Birthday required" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :cleanup_attachments" msgid "Cleanup attachments" msgstr "Cleanup attachments" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :description" msgid "Description" msgstr "Description" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :email" msgid "Admin Email Address" msgstr "Admin Email Address" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :extended_nickname_format" msgid "Extended nickname format" msgstr "Extended nickname format" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :external_user_synchronization" msgid "External user synchronization" msgstr "External user synchronization" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :federating" msgid "Federating" msgstr "Federating" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:instance > :federation_incoming_replies_max_depth" +#, fuzzy +msgctxt "" +"config label at :pleroma-:instance > :federation_incoming_replies_max_depth" msgid "Fed. incoming replies max depth" msgstr "Fed. incoming replies max depth" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:instance > :federation_reachability_timeout_days" +#, fuzzy +msgctxt "" +"config label at :pleroma-:instance > :federation_reachability_timeout_days" msgid "Fed. reachability timeout days" msgstr "Fed. reachability timeout days" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :healthcheck" msgid "Healthcheck" msgstr "Healthcheck" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :instance_thumbnail" msgid "Instance thumbnail" msgstr "Instance thumbnail" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :invites_enabled" msgid "Invites enabled" msgstr "Invites enabled" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :limit" msgid "Limit" msgstr "Limit" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :limit_to_local_content" msgid "Limit to local content" msgstr "Limit to local content" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :max_account_fields" msgid "Max account fields" msgstr "Max account fields" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :max_endorsed_users" msgid "Max endorsed users" msgstr "Max endorsed users" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :max_media_attachments" msgid "Max media attachments" msgstr "Max media attachments" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :max_pinned_statuses" msgid "Max pinned statuses" msgstr "Max pinned statuses" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :max_remote_account_fields" msgid "Max remote account fields" msgstr "Max remote account fields" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :max_report_comment_size" msgid "Max report comment size" msgstr "Max report comment size" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :multi_factor_authentication" msgid "Multi factor authentication" msgstr "Multi factor authentication" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:instance > :multi_factor_authentication > :backup_codes" +#, fuzzy +msgctxt "" +"config label at :pleroma-:instance > :multi_factor_authentication > :" +"backup_codes" msgid "Backup codes" msgstr "Backup codes" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:instance > :multi_factor_authentication > :backup_codes > :length" +#, fuzzy +msgctxt "" +"config label at :pleroma-:instance > :multi_factor_authentication > :" +"backup_codes > :length" msgid "Length" msgstr "Length" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:instance > :multi_factor_authentication > :backup_codes > :number" +#, fuzzy +msgctxt "" +"config label at :pleroma-:instance > :multi_factor_authentication > :" +"backup_codes > :number" msgid "Number" msgstr "Number" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:instance > :multi_factor_authentication > :totp" +#, fuzzy +msgctxt "" +"config label at :pleroma-:instance > :multi_factor_authentication > :totp" msgid "TOTP settings" msgstr "TOTP settings" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:instance > :multi_factor_authentication > :totp > :digits" +#, fuzzy +msgctxt "" +"config label at :pleroma-:instance > :multi_factor_authentication > :totp > :" +"digits" msgid "Digits" msgstr "Digits" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:instance > :multi_factor_authentication > :totp > :period" +#, fuzzy +msgctxt "" +"config label at :pleroma-:instance > :multi_factor_authentication > :totp > :" +"period" msgid "Period" msgstr "Period" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :name" msgid "Name" msgstr "Name" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :notify_email" msgid "Sender Email Address" msgstr "Sender Email Address" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :poll_limits" msgid "Poll limits" msgstr "Poll limits" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :poll_limits > :max_expiration" msgid "Max expiration" msgstr "Max expiration" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :poll_limits > :max_option_chars" msgid "Max option chars" msgstr "Max option chars" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :poll_limits > :max_options" msgid "Max options" msgstr "Max options" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :poll_limits > :min_expiration" msgid "Min expiration" msgstr "Min expiration" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :privileged_staff" msgid "Privileged staff" msgstr "Privileged staff" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :profile_directory" msgid "Profile directory" msgstr "Profile directory" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :public" msgid "Public" msgstr "Public" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :quarantined_instances" msgid "Quarantined instances" msgstr "Quarantined instances" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :registration_reason_length" msgid "Registration reason length" msgstr "Registration reason length" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :registrations_open" msgid "Registrations open" msgstr "Registrations open" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :remote_limit" msgid "Remote limit" msgstr "Remote limit" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :remote_post_retention_days" msgid "Remote post retention days" msgstr "Remote post retention days" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :safe_dm_mentions" msgid "Safe DM mentions" msgstr "Safe DM mentions" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :show_reactions" msgid "Show reactions" msgstr "Show reactions" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :skip_thread_containment" msgid "Skip thread containment" msgstr "Skip thread containment" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :static_dir" msgid "Static dir" msgstr "Static dir" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :upload_limit" msgid "Upload limit" msgstr "Upload limit" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :user_bio_length" msgid "User bio length" msgstr "User bio length" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :user_name_length" msgid "User name length" msgstr "User name length" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instances_favicons > :enabled" msgid "Enabled" msgstr "Enabled" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:ldap > :base" msgid "Base" msgstr "Base" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:ldap > :enabled" msgid "Enabled" msgstr "Enabled" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:ldap > :host" msgid "Host" msgstr "Host" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:ldap > :port" msgid "Port" msgstr "Port" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:ldap > :ssl" msgid "SSL" msgstr "SSL" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:ldap > :sslopts" msgid "SSL options" msgstr "SSL options" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:ldap > :sslopts > :cacertfile" msgid "Cacertfile" msgstr "Cacertfile" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:ldap > :sslopts > :verify" msgid "Verify" msgstr "Verify" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:ldap > :tls" msgid "TLS" msgstr "TLS" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:ldap > :tlsopts" msgid "TLS options" msgstr "TLS options" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:ldap > :tlsopts > :cacertfile" msgid "Cacertfile" msgstr "Cacertfile" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:ldap > :tlsopts > :verify" msgid "Verify" msgstr "Verify" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:ldap > :uid" msgid "UID" msgstr "UID" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:majic_pool > :size" msgid "Size" msgstr "Size" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:manifest > :background_color" msgid "Background color" msgstr "Background color" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:manifest > :icons" msgid "Icons" msgstr "Icons" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:manifest > :theme_color" msgid "Theme color" msgstr "Theme color" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:markup > :allow_fonts" msgid "Allow fonts" msgstr "Allow fonts" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:markup > :allow_headings" msgid "Allow headings" msgstr "Allow headings" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:markup > :allow_inline_images" msgid "Allow inline images" msgstr "Allow inline images" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:markup > :allow_tables" msgid "Allow tables" msgstr "Allow tables" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:markup > :scrub_policy" msgid "Scrub policy" msgstr "Scrub policy" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:media_preview_proxy > :enabled" msgid "Enabled" msgstr "Enabled" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:media_preview_proxy > :image_quality" msgid "Image quality" msgstr "Image quality" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:media_preview_proxy > :min_content_length" msgid "Min content length" msgstr "Min content length" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:media_preview_proxy > :thumbnail_max_height" msgid "Thumbnail max height" msgstr "Thumbnail max height" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:media_preview_proxy > :thumbnail_max_width" msgid "Thumbnail max width" msgstr "Thumbnail max width" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:media_proxy > :base_url" msgid "Base URL" msgstr "Base URL" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:media_proxy > :enabled" msgid "Enabled" msgstr "Enabled" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:media_proxy > :invalidation" msgid "Invalidation" msgstr "Invalidation" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:media_proxy > :invalidation > :enabled" msgid "Enabled" msgstr "Enabled" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:media_proxy > :invalidation > :provider" msgid "Provider" msgstr "Provider" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:media_proxy > :proxy_opts" msgid "Advanced MediaProxy Options" msgstr "Advanced MediaProxy Options" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:media_proxy > :proxy_opts > :max_body_length" +#, fuzzy +msgctxt "" +"config label at :pleroma-:media_proxy > :proxy_opts > :max_body_length" msgid "Max body length" msgstr "Max body length" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:media_proxy > :proxy_opts > :max_read_duration" +#, fuzzy +msgctxt "" +"config label at :pleroma-:media_proxy > :proxy_opts > :max_read_duration" msgid "Max read duration" msgstr "Max read duration" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:media_proxy > :proxy_opts > :redirect_on_failure" +#, fuzzy +msgctxt "" +"config label at :pleroma-:media_proxy > :proxy_opts > :redirect_on_failure" msgid "Redirect on failure" msgstr "Redirect on failure" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:media_proxy > :whitelist" msgid "Whitelist" msgstr "Whitelist" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:modules > :runtime_dir" msgid "Runtime dir" msgstr "Runtime dir" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf > :policies" msgid "Policies" msgstr "Policies" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf > :transparency" msgid "MRF transparency" msgstr "MRF transparency" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf > :transparency_exclusions" msgid "MRF transparency exclusions" msgstr "MRF transparency exclusions" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_activity_expiration > :days" msgid "Days" msgstr "Days" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_follow_bot > :follower_nickname" msgid "Follower nickname" msgstr "Follower nickname" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_hashtag > :federated_timeline_removal" msgid "Federated timeline removal" msgstr "Federated timeline removal" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_hashtag > :reject" msgid "Reject" msgstr "Reject" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_hashtag > :sensitive" msgid "Sensitive" msgstr "Sensitive" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_hellthread > :delist_threshold" msgid "Delist threshold" msgstr "Delist threshold" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_hellthread > :reject_threshold" msgid "Reject threshold" msgstr "Reject threshold" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_keyword > :federated_timeline_removal" msgid "Federated timeline removal" msgstr "Federated timeline removal" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_keyword > :reject" msgid "Reject" msgstr "Reject" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_keyword > :replace" msgid "Replace" msgstr "Replace" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_mention > :actors" msgid "Actors" msgstr "Actors" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_normalize_markup > :scrub_policy" msgid "Scrub policy" msgstr "Scrub policy" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_object_age > :actions" msgid "Actions" msgstr "Actions" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_object_age > :threshold" msgid "Threshold" msgstr "Threshold" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_rejectnonpublic > :allow_direct" msgid "Allow direct" msgstr "Allow direct" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_rejectnonpublic > :allow_followersonly" msgid "Allow followers-only" msgstr "Allow followers-only" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_simple > :accept" msgid "Accept" msgstr "Accept" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_simple > :avatar_removal" msgid "Avatar removal" msgstr "Avatar removal" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_simple > :banner_removal" msgid "Banner removal" msgstr "Banner removal" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_simple > :federated_timeline_removal" msgid "Federated timeline removal" msgstr "Federated timeline removal" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_simple > :followers_only" msgid "Followers only" msgstr "Followers only" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_simple > :media_nsfw" msgid "Media NSFW" msgstr "Media NSFW" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_simple > :media_removal" msgid "Media removal" msgstr "Media removal" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_simple > :reject" msgid "Reject" msgstr "Reject" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_simple > :reject_deletes" msgid "Reject deletes" msgstr "Reject deletes" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_simple > :report_removal" msgid "Report removal" msgstr "Report removal" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_steal_emoji > :hosts" msgid "Hosts" msgstr "Hosts" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_steal_emoji > :rejected_shortcodes" msgid "Rejected shortcodes" msgstr "Rejected shortcodes" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_steal_emoji > :size_limit" msgid "Size limit" msgstr "Size limit" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_subchain > :match_actor" msgid "Match actor" msgstr "Match actor" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_vocabulary > :accept" msgid "Accept" msgstr "Accept" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:mrf_vocabulary > :reject" msgid "Reject" msgstr "Reject" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:oauth2 > :clean_expired_tokens" msgid "Clean expired tokens" msgstr "Clean expired tokens" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:oauth2 > :issue_new_refresh_token" msgid "Issue new refresh token" msgstr "Issue new refresh token" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:oauth2 > :token_expires_in" msgid "Token expires in" msgstr "Token expires in" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:pools > :default" msgid "Default" msgstr "Default" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:pools > :default > :max_waiting" msgid "Max waiting" msgstr "Max waiting" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:pools > :default > :recv_timeout" msgid "Recv timeout" msgstr "Recv timeout" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:pools > :default > :size" msgid "Size" msgstr "Size" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:pools > :federation" msgid "Federation" msgstr "Federation" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:pools > :federation > :max_waiting" msgid "Max waiting" msgstr "Max waiting" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:pools > :federation > :recv_timeout" msgid "Recv timeout" msgstr "Recv timeout" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:pools > :federation > :size" msgid "Size" msgstr "Size" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:pools > :media" msgid "Media" msgstr "Media" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:pools > :media > :max_waiting" msgid "Max waiting" msgstr "Max waiting" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:pools > :media > :recv_timeout" msgid "Recv timeout" msgstr "Recv timeout" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:pools > :media > :size" msgid "Size" msgstr "Size" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:pools > :upload" msgid "Upload" msgstr "Upload" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:pools > :upload > :max_waiting" msgid "Max waiting" msgstr "Max waiting" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:pools > :upload > :recv_timeout" msgid "Recv timeout" msgstr "Recv timeout" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:pools > :upload > :size" msgid "Size" msgstr "Size" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:populate_hashtags_table > :fault_rate_allowance" +#, fuzzy +msgctxt "" +"config label at :pleroma-:populate_hashtags_table > :fault_rate_allowance" msgid "Fault rate allowance" msgstr "Fault rate allowance" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:populate_hashtags_table > :sleep_interval_ms" +#, fuzzy +msgctxt "" +"config label at :pleroma-:populate_hashtags_table > :sleep_interval_ms" msgid "Sleep interval ms" msgstr "Sleep interval ms" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:rate_limit > :app_account_creation" msgid "App account creation" msgstr "App account creation" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:rate_limit > :authentication" msgid "Authentication" msgstr "Authentication" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:rate_limit > :relation_id_action" msgid "Relation ID action" msgstr "Relation ID action" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:rate_limit > :relations_actions" msgid "Relations actions" msgstr "Relations actions" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:rate_limit > :search" msgid "Search" msgstr "Search" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:rate_limit > :status_id_action" msgid "Status ID action" msgstr "Status ID action" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:rate_limit > :statuses_actions" msgid "Statuses actions" msgstr "Statuses actions" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:rate_limit > :timeline" msgid "Timeline" msgstr "Timeline" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:restrict_unauthenticated > :activities" msgid "Activities" msgstr "Activities" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:restrict_unauthenticated > :activities > :local" +#, fuzzy +msgctxt "" +"config label at :pleroma-:restrict_unauthenticated > :activities > :local" msgid "Local" msgstr "Local" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:restrict_unauthenticated > :activities > :remote" +#, fuzzy +msgctxt "" +"config label at :pleroma-:restrict_unauthenticated > :activities > :remote" msgid "Remote" msgstr "Remote" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:restrict_unauthenticated > :profiles" msgid "Profiles" msgstr "Profiles" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:restrict_unauthenticated > :profiles > :local" +#, fuzzy +msgctxt "" +"config label at :pleroma-:restrict_unauthenticated > :profiles > :local" msgid "Local" msgstr "Local" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:restrict_unauthenticated > :profiles > :remote" +#, fuzzy +msgctxt "" +"config label at :pleroma-:restrict_unauthenticated > :profiles > :remote" msgid "Remote" msgstr "Remote" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:restrict_unauthenticated > :timelines" msgid "Timelines" msgstr "Timelines" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:restrict_unauthenticated > :timelines > :federated" +#, fuzzy +msgctxt "" +"config label at :pleroma-:restrict_unauthenticated > :timelines > :federated" msgid "Federated" msgstr "Federated" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:restrict_unauthenticated > :timelines > :local" +#, fuzzy +msgctxt "" +"config label at :pleroma-:restrict_unauthenticated > :timelines > :local" msgid "Local" msgstr "Local" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:rich_media > :enabled" msgid "Enabled" msgstr "Enabled" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:rich_media > :failure_backoff" msgid "Failure backoff" msgstr "Failure backoff" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:rich_media > :ignore_hosts" msgid "Ignore hosts" msgstr "Ignore hosts" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:rich_media > :ignore_tld" msgid "Ignore TLD" msgstr "Ignore TLD" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:rich_media > :parsers" msgid "Parsers" msgstr "Parsers" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:rich_media > :ttl_setters" msgid "TTL setters" msgstr "TTL setters" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:shout > :enabled" msgid "Enabled" msgstr "Enabled" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:shout > :limit" msgid "Limit" msgstr "Limit" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:static_fe > :enabled" msgid "Enabled" msgstr "Enabled" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:streamer > :overflow_workers" msgid "Overflow workers" msgstr "Overflow workers" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:streamer > :workers" msgid "Workers" msgstr "Workers" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:uri_schemes > :valid_schemes" msgid "Valid schemes" msgstr "Valid schemes" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:user > :deny_follow_blocked" msgid "Deny follow blocked" msgstr "Deny follow blocked" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:web_cache_ttl > :activity_pub" msgid "Activity pub" msgstr "Activity pub" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:web_cache_ttl > :activity_pub_question" msgid "Activity pub question" msgstr "Activity pub question" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:welcome > :chat_message" msgid "Chat message" msgstr "Chat message" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:welcome > :chat_message > :enabled" msgid "Enabled" msgstr "Enabled" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:welcome > :chat_message > :message" msgid "Message" msgstr "Message" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:welcome > :chat_message > :sender_nickname" msgid "Sender nickname" msgstr "Sender nickname" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:welcome > :direct_message" msgid "Direct message" msgstr "Direct message" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:welcome > :direct_message > :enabled" msgid "Enabled" msgstr "Enabled" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:welcome > :direct_message > :message" msgid "Message" msgstr "Message" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:welcome > :direct_message > :sender_nickname" +#, fuzzy +msgctxt "" +"config label at :pleroma-:welcome > :direct_message > :sender_nickname" msgid "Sender nickname" msgstr "Sender nickname" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:welcome > :email" msgid "Email" msgstr "Email" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:welcome > :email > :enabled" msgid "Enabled" msgstr "Enabled" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:welcome > :email > :html" msgid "Html" msgstr "Html" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:welcome > :email > :sender" msgid "Sender" msgstr "Sender" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:welcome > :email > :subject" msgid "Subject" msgstr "Subject" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:welcome > :email > :text" msgid "Text" msgstr "Text" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:workers > :retries" msgid "Retries" msgstr "Retries" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-ConcurrentLimiter > Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy" +#, fuzzy +msgctxt "" +"config label at :pleroma-ConcurrentLimiter > Pleroma.Web.ActivityPub.MRF." +"MediaProxyWarmingPolicy" msgid "Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy" msgstr "Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-ConcurrentLimiter > Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy > :max_running" +#, fuzzy +msgctxt "" +"config label at :pleroma-ConcurrentLimiter > Pleroma.Web.ActivityPub.MRF." +"MediaProxyWarmingPolicy > :max_running" msgid "Max running" msgstr "Max running" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-ConcurrentLimiter > Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy > :max_waiting" +#, fuzzy +msgctxt "" +"config label at :pleroma-ConcurrentLimiter > Pleroma.Web.ActivityPub.MRF." +"MediaProxyWarmingPolicy > :max_waiting" msgid "Max waiting" msgstr "Max waiting" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-ConcurrentLimiter > Pleroma.Web.RichMedia.Helpers" +#, fuzzy +msgctxt "" +"config label at :pleroma-ConcurrentLimiter > Pleroma.Web.RichMedia.Helpers" msgid "Pleroma.Web.RichMedia.Helpers" msgstr "Pleroma.Web.RichMedia.Helpers" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-ConcurrentLimiter > Pleroma.Web.RichMedia.Helpers > :max_running" +#, fuzzy +msgctxt "" +"config label at :pleroma-ConcurrentLimiter > Pleroma.Web.RichMedia.Helpers " +"> :max_running" msgid "Max running" msgstr "Max running" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-ConcurrentLimiter > Pleroma.Web.RichMedia.Helpers > :max_waiting" +#, fuzzy +msgctxt "" +"config label at :pleroma-ConcurrentLimiter > Pleroma.Web.RichMedia.Helpers " +"> :max_waiting" msgid "Max waiting" msgstr "Max waiting" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Oban > :crontab" msgid "Crontab" msgstr "Crontab" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Oban > :log" msgid "Log" msgstr "Log" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Oban > :queues" msgid "Queues" msgstr "Queues" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Oban > :queues > :activity_expiration" msgid "Activity expiration" msgstr "Activity expiration" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Oban > :queues > :attachments_cleanup" msgid "Attachments cleanup" msgstr "Attachments cleanup" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Oban > :queues > :background" msgid "Background" msgstr "Background" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Oban > :queues > :backup" msgid "Backup" msgstr "Backup" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Oban > :queues > :federator_incoming" msgid "Federator incoming" msgstr "Federator incoming" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Oban > :queues > :federator_outgoing" msgid "Federator outgoing" msgstr "Federator outgoing" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Oban > :queues > :mailer" msgid "Mailer" msgstr "Mailer" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Oban > :queues > :scheduled_activities" msgid "Scheduled activities" msgstr "Scheduled activities" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Oban > :queues > :transmogrifier" msgid "Transmogrifier" msgstr "Transmogrifier" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Oban > :queues > :web_push" msgid "Web push" msgstr "Web push" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Captcha > :enabled" msgid "Enabled" msgstr "Enabled" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Captcha > :method" msgid "Method" msgstr "Method" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Captcha > :seconds_valid" msgid "Seconds valid" msgstr "Seconds valid" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Captcha.Kocaptcha > :endpoint" msgid "Endpoint" msgstr "Endpoint" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Emails.Mailer > :adapter" msgid "Adapter" msgstr "Adapter" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Emails.Mailer > :enabled" msgid "Mailer Enabled" msgstr "Mailer Enabled" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.AmazonSES-:access_key" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.AmazonSES-:" +"access_key" msgid "AWS Access Key" msgstr "AWS Access Key" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.AmazonSES-:region" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.AmazonSES-:" +"region" msgid "AWS Region" msgstr "AWS Region" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.AmazonSES-:secret" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.AmazonSES-:" +"secret" msgid "AWS Secret Key" msgstr "AWS Secret Key" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.Dyn-:api_key" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.Dyn-:api_key" msgid "Dyn API Key" msgstr "Dyn API Key" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.Gmail-:access_token" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.Gmail-:" +"access_token" msgid "GMail API Access Token" msgstr "GMail API Access Token" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.Mailgun-:api_key" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.Mailgun-:" +"api_key" msgid "Mailgun API Key" msgstr "Mailgun API Key" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.Mailgun-:domain" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.Mailgun-:" +"domain" msgid "Domain" msgstr "Domain" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.Mailjet-:api_key" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.Mailjet-:" +"api_key" msgid "MailJet Public API Key" msgstr "MailJet Public API Key" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.Mailjet-:secret" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.Mailjet-:" +"secret" msgid "MailJet Private API Key" msgstr "MailJet Private API Key" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.Mandrill-:api_key" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.Mandrill-:" +"api_key" msgid "Mandrill API Key" msgstr "Mandrill API Key" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.Postmark-:api_key" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.Postmark-:" +"api_key" msgid "Postmark API Key" msgstr "Postmark API Key" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SMTP-:auth" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SMTP-:auth" msgid "AUTH Mode" msgstr "AUTH Mode" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SMTP-:password" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SMTP-:" +"password" msgid "Password" msgstr "Password" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SMTP-:port" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SMTP-:port" msgid "Port" msgstr "Port" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SMTP-:relay" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SMTP-:relay" msgid "Relay" msgstr "Relay" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SMTP-:retries" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SMTP-:" +"retries" msgid "Retries" msgstr "Retries" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SMTP-:ssl" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SMTP-:ssl" msgid "Use SSL" msgstr "Use SSL" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SMTP-:tls" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SMTP-:tls" msgid "STARTTLS Mode" msgstr "STARTTLS Mode" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SMTP-:username" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SMTP-:" +"username" msgid "Username" msgstr "Username" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.Sendgrid-:api_key" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.Sendgrid-:" +"api_key" msgid "SendGrid API Key" msgstr "SendGrid API Key" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.Sendmail-:cmd_args" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.Sendmail-:" +"cmd_args" msgid "Cmd args" msgstr "Cmd args" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.Sendmail-:cmd_path" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.Sendmail-:" +"cmd_path" msgid "Cmd path" msgstr "Cmd path" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.Sendmail-:qmail" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.Sendmail-:" +"qmail" msgid "Qmail compat mode" msgstr "Qmail compat mode" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SocketLabs-:api_key" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SocketLabs-:" +"api_key" msgid "SocketLabs API Key" msgstr "SocketLabs API Key" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SocketLabs-:server_id" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SocketLabs-:" +"server_id" msgid "Server ID" msgstr "Server ID" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SparkPost-:api_key" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SparkPost-:" +"api_key" msgid "SparkPost API key" msgstr "SparkPost API key" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SparkPost-:endpoint" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Emails.Mailer > Swoosh.Adapters.SparkPost-:" +"endpoint" msgid "Endpoint" msgstr "Endpoint" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Emails.NewUsersDigestEmail > :enabled" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Emails.NewUsersDigestEmail > :enabled" msgid "Enabled" msgstr "Enabled" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Emails.UserEmail > :logo" msgid "Logo" msgstr "Logo" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Emails.UserEmail > :styling" msgid "Styling" msgstr "Styling" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Emails.UserEmail > :styling > :background_color" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Emails.UserEmail > :styling > :" +"background_color" msgid "Background color" msgstr "Background color" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Emails.UserEmail > :styling > :content_background_color" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Emails.UserEmail > :styling > :" +"content_background_color" msgid "Content background color" msgstr "Content background color" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Emails.UserEmail > :styling > :header_color" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Emails.UserEmail > :styling > :header_color" msgid "Header color" msgstr "Header color" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Emails.UserEmail > :styling > :link_color" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Emails.UserEmail > :styling > :link_color" msgid "Link color" msgstr "Link color" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Emails.UserEmail > :styling > :text_color" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Emails.UserEmail > :styling > :text_color" msgid "Text color" msgstr "Text color" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Emails.UserEmail > :styling > :text_muted_color" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Emails.UserEmail > :styling > :" +"text_muted_color" msgid "Text muted color" msgstr "Text muted color" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Formatter > :class" msgid "Class" msgstr "Class" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Formatter > :extra" msgid "Extra" msgstr "Extra" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Formatter > :new_window" msgid "New window" msgstr "New window" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Formatter > :rel" msgid "Rel" msgstr "Rel" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Formatter > :strip_prefix" msgid "Strip prefix" msgstr "Strip prefix" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Formatter > :truncate" msgid "Truncate" msgstr "Truncate" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Formatter > :validate_tld" msgid "Validate tld" msgstr "Validate tld" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.ScheduledActivity > :daily_user_limit" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.ScheduledActivity > :daily_user_limit" msgid "Daily user limit" msgstr "Daily user limit" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.ScheduledActivity > :enabled" msgid "Enabled" msgstr "Enabled" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.ScheduledActivity > :total_user_limit" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.ScheduledActivity > :total_user_limit" msgid "Total user limit" msgstr "Total user limit" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Upload > :base_url" msgid "Base URL" msgstr "Base URL" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Upload > :filename_display_max_length" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Upload > :filename_display_max_length" msgid "Filename display max length" msgstr "Filename display max length" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Upload > :filters" msgid "Filters" msgstr "Filters" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Upload > :link_name" msgid "Link name" msgstr "Link name" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Upload > :proxy_remote" msgid "Proxy remote" msgstr "Proxy remote" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Upload > :uploader" msgid "Uploader" msgstr "Uploader" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Upload.Filter.AnonymizeFilename > :text" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Upload.Filter.AnonymizeFilename > :text" msgid "Text" msgstr "Text" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Upload.Filter.Mogrify > :args" msgid "Args" msgstr "Args" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Uploaders.Local > :uploads" msgid "Uploads" msgstr "Uploads" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Uploaders.S3 > :bucket" msgid "Bucket" msgstr "Bucket" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Uploaders.S3 > :bucket_namespace" msgid "Bucket namespace" msgstr "Bucket namespace" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Uploaders.S3 > :streaming_enabled" msgid "Streaming enabled" msgstr "Streaming enabled" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Uploaders.S3 > :truncated_namespace" msgid "Truncated namespace" msgstr "Truncated namespace" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.User > :email_blacklist" msgid "Email blacklist" msgstr "Email blacklist" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.User > :restricted_nicknames" msgid "Restricted nicknames" msgstr "Restricted nicknames" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.User.Backup > :limit_days" msgid "Limit days" msgstr "Limit days" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.User.Backup > :purge_after_days" msgid "Purge after days" msgstr "Purge after days" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Web.ApiSpec.CastAndValidate > :strict" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Web.ApiSpec.CastAndValidate > :strict" msgid "Strict" msgstr "Strict" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Web.MediaProxy.Invalidation.Http > :headers" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Web.MediaProxy.Invalidation.Http > :headers" msgid "Headers" msgstr "Headers" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Web.MediaProxy.Invalidation.Http > :method" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Web.MediaProxy.Invalidation.Http > :method" msgid "Method" msgstr "Method" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Web.MediaProxy.Invalidation.Http > :options" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Web.MediaProxy.Invalidation.Http > :options" msgid "Options" msgstr "Options" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Web.MediaProxy.Invalidation.Http > :options > :params" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Web.MediaProxy.Invalidation.Http > :options " +"> :params" msgid "Params" msgstr "Params" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Web.MediaProxy.Invalidation.Script > :script_path" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Web.MediaProxy.Invalidation.Script > :" +"script_path" msgid "Script path" msgstr "Script path" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Web.MediaProxy.Invalidation.Script > :url_format" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Web.MediaProxy.Invalidation.Script > :" +"url_format" msgid "URL Format" msgstr "URL Format" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Web.Metadata > :providers" msgid "Providers" msgstr "Providers" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Web.Metadata > :unfurl_nsfw" msgid "Unfurl NSFW" msgstr "Unfurl NSFW" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Web.Plugs.RemoteIp > :enabled" msgid "Enabled" msgstr "Enabled" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Web.Plugs.RemoteIp > :headers" msgid "Headers" msgstr "Headers" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Web.Plugs.RemoteIp > :proxies" msgid "Proxies" msgstr "Proxies" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Web.Plugs.RemoteIp > :reserved" msgid "Reserved" msgstr "Reserved" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-Pleroma.Web.Preload > :providers" msgid "Providers" msgstr "Providers" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Workers.PurgeExpiredActivity > :enabled" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Workers.PurgeExpiredActivity > :enabled" msgid "Enabled" msgstr "Enabled" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-Pleroma.Workers.PurgeExpiredActivity > :min_lifetime" +#, fuzzy +msgctxt "" +"config label at :pleroma-Pleroma.Workers.PurgeExpiredActivity > :min_lifetime" msgid "Min lifetime" msgstr "Min lifetime" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :prometheus-Pleroma.Web.Endpoint.MetricsExporter > :auth" +#, fuzzy +msgctxt "" +"config label at :prometheus-Pleroma.Web.Endpoint.MetricsExporter > :auth" msgid "Auth" msgstr "Auth" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :prometheus-Pleroma.Web.Endpoint.MetricsExporter > :enabled" +#, fuzzy +msgctxt "" +"config label at :prometheus-Pleroma.Web.Endpoint.MetricsExporter > :enabled" msgid "Enabled" msgstr "Enabled" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :prometheus-Pleroma.Web.Endpoint.MetricsExporter > :format" +#, fuzzy +msgctxt "" +"config label at :prometheus-Pleroma.Web.Endpoint.MetricsExporter > :format" msgid "Format" msgstr "Format" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :prometheus-Pleroma.Web.Endpoint.MetricsExporter > :ip_whitelist" +#, fuzzy +msgctxt "" +"config label at :prometheus-Pleroma.Web.Endpoint.MetricsExporter > :" +"ip_whitelist" msgid "IP Whitelist" msgstr "IP Whitelist" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :prometheus-Pleroma.Web.Endpoint.MetricsExporter > :path" +#, fuzzy +msgctxt "" +"config label at :prometheus-Pleroma.Web.Endpoint.MetricsExporter > :path" msgid "Path" msgstr "Path" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :quack > :level" msgid "Level" msgstr "Level" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :quack > :meta" msgid "Meta" msgstr "Meta" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :quack > :webhook_url" msgid "Webhook URL" msgstr "Webhook URL" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :web_push_encryption-:vapid_details > :private_key" msgid "Private key" msgstr "Private key" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :web_push_encryption-:vapid_details > :public_key" msgid "Public key" msgstr "Public key" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :web_push_encryption-:vapid_details > :subject" msgid "Subject" msgstr "Subject" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:activitypub > :authorized_fetch_mode" msgid "Require HTTP signatures for AP fetches" msgstr "Require HTTP signatures for AP fetches" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config description at :pleroma-:instance > :short_description" -msgid "Shorter version of instance description. It can be seen on `/api/v1/instance`" +msgid "" +"Shorter version of instance description. It can be seen on `/api/v1/instance`" msgstr "" "Shorter version of instance description. It can be seen on `/api/v1/instance`" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:activitypub > :authorized_fetch_mode" msgid "Authorized fetch mode" msgstr "Authorized fetch mode" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, fuzzy msgctxt "config label at :pleroma-:instance > :short_description" msgid "Short description" msgstr "Short description" From a1515f9a606f6e5bdc2acb969cff2baad986efc4 Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Fri, 9 Dec 2022 23:45:51 +0000 Subject: [PATCH 116/631] Add some extra info around possible nils --- lib/pleroma/user.ex | 2 +- lib/pleroma/web/activity_pub/activity_pub.ex | 2 +- lib/pleroma/web/activity_pub/transmogrifier.ex | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index c8262b37b..e32dd161e 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -1922,7 +1922,7 @@ def get_or_fetch_by_ap_id(ap_id) do {:ok, user} e -> - Logger.error("Could not fetch user, #{inspect(e)}") + Logger.error("Could not fetch user #{ap_id}, #{inspect(e)}") {:error, :not_found} end end diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 521c8b852..3adb4ab54 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -1711,7 +1711,7 @@ def fetch_and_prepare_user_from_ap_id(ap_id, additional \\ []) do {:ok, maybe_update_follow_information(data)} else # If this has been deleted, only log a debug and not an error - {:error, {"Object has been deleted" = e, _, _}} -> + {:error, {"Object has been deleted", _, _} = e} -> Logger.debug("Could not decode user at fetch #{ap_id}, #{inspect(e)}") {:error, e} diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index b9d853610..77015241b 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -136,7 +136,7 @@ def fix_in_reply_to(%{"inReplyTo" => in_reply_to} = object, options) |> Map.drop(["conversation", "inReplyToAtomUri"]) else e -> - Logger.warn("Couldn't fetch #{inspect(in_reply_to_id)}, error: #{inspect(e)}") + Logger.warn("Couldn't fetch reply@#{inspect(in_reply_to_id)}, error: #{inspect(e)}") object end else @@ -159,7 +159,7 @@ def fix_quote_url(%{"quoteUri" => quote_url} = object, options) |> Map.put("quoteUri", quoted_object.data["id"]) else e -> - Logger.warn("Couldn't fetch #{inspect(quote_url)}, error: #{inspect(e)}") + Logger.warn("Couldn't fetch quote@#{inspect(quote_url)}, error: #{inspect(e)}") object end else @@ -833,7 +833,7 @@ def maybe_fix_object_url(%{"object" => object} = data) when is_binary(object) do Map.put(data, "object", external_url) else {:fetch, e} -> - Logger.error("Couldn't fetch #{object} #{inspect(e)}") + Logger.error("Couldn't fetch fixed_object@#{object} #{inspect(e)}") data _ -> From 68894089e845220e06d77401d15e399cb0d3882c Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Sat, 10 Dec 2022 00:09:45 +0000 Subject: [PATCH 117/631] Do not fetch anything from blocked instances --- CHANGELOG.md | 1 + lib/pleroma/object/fetcher.ex | 9 +++++++- .../web/activity_pub/mrf/simple_policy.ex | 4 ++-- test/pleroma/object/fetcher_test.exs | 22 +++++++++++++++++++ 4 files changed, 33 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eef3c53b8..e2737611c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Follow/Block/Mute imports now spin off into *n* tasks to avoid the oban timeout - Transient activities recieved from remote servers are no longer persisted in the database - Overhauled static-fe view for logged-out users +- Blocked instances will now not be sent _any_ requests, even fetch ones that would get rejected by MRF anyhow ## Removed - FollowBotPolicy diff --git a/lib/pleroma/object/fetcher.ex b/lib/pleroma/object/fetcher.ex index cde4e5039..8309ef64a 100644 --- a/lib/pleroma/object/fetcher.ex +++ b/lib/pleroma/object/fetcher.ex @@ -116,7 +116,11 @@ def refetch_object(%Object{data: %{"id" => id}} = object) do # Note: will create a Create activity, which we need internally at the moment. def fetch_object_from_id(id, options \\ []) do - with {_, nil} <- {:fetch_object, Object.get_cached_by_ap_id(id)}, + with %URI{} = uri <- URI.parse(id), + # If we have instance restrictions, apply them here to prevent fetching from unwanted instances + {:ok, nil} <- Pleroma.Web.ActivityPub.MRF.SimplePolicy.check_reject(uri), + {:ok, _} <- Pleroma.Web.ActivityPub.MRF.SimplePolicy.check_accept(uri), + {_, nil} <- {:fetch_object, Object.get_cached_by_ap_id(id)}, {_, true} <- {:allowed_depth, Federator.allowed_thread_distance?(options[:depth])}, {_, {:ok, data}} <- {:fetch, fetch_and_contain_remote_object_from_id(id)}, {_, nil} <- {:normalize, Object.normalize(data, fetch: false)}, @@ -155,6 +159,9 @@ def fetch_object_from_id(id, options \\ []) do {:fetch, {:error, error}} -> {:error, error} + {:reject, reason} -> + {:reject, reason} + e -> e end diff --git a/lib/pleroma/web/activity_pub/mrf/simple_policy.ex b/lib/pleroma/web/activity_pub/mrf/simple_policy.ex index f7eb0f159..ba54eb674 100644 --- a/lib/pleroma/web/activity_pub/mrf/simple_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/simple_policy.ex @@ -13,7 +13,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do require Pleroma.Constants - defp check_accept(%{host: actor_host} = _actor_info) do + def check_accept(%{host: actor_host} = _actor_info) do accepts = instance_list(:accept) |> MRF.subdomains_regex() @@ -26,7 +26,7 @@ defp check_accept(%{host: actor_host} = _actor_info) do end end - defp check_reject(%{host: actor_host} = _actor_info) do + def check_reject(%{host: actor_host} = _actor_info) do rejects = instance_list(:reject) |> MRF.subdomains_regex() diff --git a/test/pleroma/object/fetcher_test.exs b/test/pleroma/object/fetcher_test.exs index 22192d98f..c76a09fd7 100644 --- a/test/pleroma/object/fetcher_test.exs +++ b/test/pleroma/object/fetcher_test.exs @@ -161,6 +161,28 @@ test "it does not fetch a spoofed object uploaded on an instance as an attachmen ) end + test "does not fetch anything from a rejected instance" do + clear_config([:mrf_simple, :reject], [{"evil.example.org", "i said so"}]) + + assert {:reject, _} = + Fetcher.fetch_object_from_id("http://evil.example.org/@admin/99541947525187367") + end + + test "does not fetch anything if mrf_simple accept is on" do + clear_config([:mrf_simple, :accept], [{"mastodon.example.org", "i said so"}]) + clear_config([:mrf_simple, :reject], []) + + assert {:reject, _} = + Fetcher.fetch_object_from_id( + "http://notlisted.example.org/@admin/99541947525187367" + ) + + assert {:ok, _object} = + Fetcher.fetch_object_from_id( + "http://mastodon.example.org/@admin/99541947525187367" + ) + end + test "it resets instance reachability on successful fetch" do id = "http://mastodon.example.org/@admin/99541947525187367" Instances.set_consistently_unreachable(id) From 90fce918b2cea86c14cc3b126c5b2a3c04d9cd4e Mon Sep 17 00:00:00 2001 From: r3g_5z Date: Fri, 9 Dec 2022 19:10:20 -0500 Subject: [PATCH 118/631] Remove unnecessary KillMode=process It's unclear why this is the default as this is highly not recommended. KillMode=process ends up leaving leftover orphaned processes that escape resource management and process lifecycles, wasting resources on servers. Signed-off-by: r3g_5z --- installation/akkoma.service | 1 - 1 file changed, 1 deletion(-) diff --git a/installation/akkoma.service b/installation/akkoma.service index 2b2e3d568..f5865a91a 100644 --- a/installation/akkoma.service +++ b/installation/akkoma.service @@ -4,7 +4,6 @@ After=network.target postgresql.service [Service] ExecReload=/bin/kill $MAINPID -KillMode=process Restart=on-failure ; Uncomment this if you're on Arch Linux From 77174acc7ba92f455219c1c8610fc76b6e6d4d8a Mon Sep 17 00:00:00 2001 From: r3g_5z Date: Fri, 9 Dec 2022 21:36:21 -0500 Subject: [PATCH 119/631] Don't listen Erlang Port Mapper Daemon (4369/tcp) on 0.0.0.0 Signed-off-by: r3g_5z --- Dockerfile | 1 + docker-resources/env.example | 1 + installation/akkoma.service | 3 +++ installation/akkoma.supervisord | 3 ++- installation/freebsd/rc.d/akkoma | 3 ++- installation/init.d/akkoma | 1 + installation/netbsd/rc.d/akkoma | 2 +- 7 files changed, 11 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index 6ba7a2269..0551a4c9e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,7 @@ FROM hexpm/elixir:1.13.4-erlang-24.3.4.5-alpine-3.15.6 ENV MIX_ENV=prod +ENV ERL_EPMD_ADDRESS=127.0.0.1 ARG HOME=/opt/akkoma diff --git a/docker-resources/env.example b/docker-resources/env.example index d6cf0c7b8..23ca15221 100644 --- a/docker-resources/env.example +++ b/docker-resources/env.example @@ -1,4 +1,5 @@ MIX_ENV=prod +ERL_EPMD_ADDRESS=127.0.0.1 DB_NAME=akkoma DB_USER=akkoma DB_PASS=akkoma diff --git a/installation/akkoma.service b/installation/akkoma.service index f5865a91a..3d7c062ff 100644 --- a/installation/akkoma.service +++ b/installation/akkoma.service @@ -14,6 +14,9 @@ User=akkoma ; Declares that Akkoma runs in production mode. Environment="MIX_ENV=prod" +; Don't listen epmd on 0.0.0.0 +Environment="ERL_EPMD_ADDRESS=127.0.0.1" + ; Make sure that all paths fit your installation. ; Path to the home directory of the user running the Akkoma service. Environment="HOME=/var/lib/akkoma" diff --git a/installation/akkoma.supervisord b/installation/akkoma.supervisord index 8fd5e8d42..1e0ee9744 100644 --- a/installation/akkoma.supervisord +++ b/installation/akkoma.supervisord @@ -12,7 +12,8 @@ environment = HOME=/home/akkoma, USER=akkoma, PATH="/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin:/home/akkoma/bin:%(ENV_PATH)s", - PWD=/home/akkoma/akkoma + PWD=/home/akkoma/akkoma, + ERL_EPMD_ADDRESS=127.0.0.1 stdout_logfile=/home/akkoma/logs/stdout.log stdout_logfile_maxbytes=50MB stdout_logfile_backups=10 diff --git a/installation/freebsd/rc.d/akkoma b/installation/freebsd/rc.d/akkoma index 38186522b..e87c26b57 100755 --- a/installation/freebsd/rc.d/akkoma +++ b/installation/freebsd/rc.d/akkoma @@ -18,7 +18,8 @@ load_rc_config ${name} : ${akkoma_user:=akkoma} : ${akkoma_home:=$(getent passwd ${akkoma_user} | awk -F: '{print $6}')} : ${akkoma_chdir:="${akkoma_home}/akkoma"} -: ${akkoma_env:="HOME=${akkoma_home} MIX_ENV=prod"} +: ${akkoma_env:="HOME=${akkoma_home} MIX_ENV=prod ERL_EPMD_ADDRESS=127.0.0.1"} + command=/usr/local/bin/elixir command_args="--erl \"-detached\" -S /usr/local/bin/mix phx.server" diff --git a/installation/init.d/akkoma b/installation/init.d/akkoma index bf70c34fb..6c1973db4 100755 --- a/installation/init.d/akkoma +++ b/installation/init.d/akkoma @@ -31,6 +31,7 @@ else fi export MIX_ENV=prod +export ERL_EPMD_ADDRESS=127.0.0.1 depend() { need nginx postgresql diff --git a/installation/netbsd/rc.d/akkoma b/installation/netbsd/rc.d/akkoma index 7b80bc414..6dfe80f4a 100755 --- a/installation/netbsd/rc.d/akkoma +++ b/installation/netbsd/rc.d/akkoma @@ -14,7 +14,7 @@ start_precmd="ulimit -n unlimited" pidfile="/dev/null" akkoma_chdir="${akkoma_home}/akkoma" -akkoma_env="HOME=${akkoma_home} MIX_ENV=prod" +akkoma_env="HOME=${akkoma_home} MIX_ENV=prod ERL_EPMD_ADDRESS=127.0.0.1" check_pidfile() { From fbfffccc1d7ede96b4d72523ed813b7f4c365bf3 Mon Sep 17 00:00:00 2001 From: r3g_5z Date: Fri, 9 Dec 2022 22:49:25 -0500 Subject: [PATCH 120/631] Add dark and light theme mode to docs, detection, and button my eyes hurt Signed-off-by: r3g_5z --- docs/mkdocs.yml | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index b554d3df3..655abdd69 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -12,8 +12,21 @@ theme: - navigation.instant - navigation.sections palette: - primary: 'deep purple' - accent: 'blue grey' + - media: "(prefers-color-scheme: light)" + scheme: default + toggle: + icon: material/brightness-7 + name: Switch to dark mode + primary: 'deep purple' + accent: 'blue grey' + + - media: "(prefers-color-scheme: dark)" + scheme: slate + toggle: + icon: material/brightness-4 + name: Switch to light mode + primary: 'deep purple' + accent: 'blue grey' extra_css: - css/extra.css From 1f0ef9427115862d7a858171dd810f6807705048 Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Sat, 10 Dec 2022 14:50:02 +0000 Subject: [PATCH 121/631] Bump versions --- CHANGELOG.md | 2 +- mix.exs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e2737611c..bf5513fbb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). -## Unreleased +## 2022.12 ## Added - Config: HTTP timeout options, :pool\_timeout and :receive\_timeout diff --git a/mix.exs b/mix.exs index 69b708572..39cb4b5ac 100644 --- a/mix.exs +++ b/mix.exs @@ -4,7 +4,7 @@ defmodule Pleroma.Mixfile do def project do [ app: :pleroma, - version: version("3.4.0"), + version: version("3.5.0"), elixir: "~> 1.12", elixirc_paths: elixirc_paths(Mix.env()), compilers: [:phoenix, :gettext] ++ Mix.compilers(), From affc910372c7b41670c05531b22ff1dfaecb7edd Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Sun, 11 Dec 2022 19:19:31 +0000 Subject: [PATCH 122/631] Remove hackney/gun in favour of finch --- config/config.exs | 4 + docs/docs/configuration/cheatsheet.md | 48 ------ lib/pleroma/emails/mailer.ex | 5 - lib/pleroma/gun/api.ex | 46 ------ lib/pleroma/gun/conn.ex | 131 --------------- lib/pleroma/gun/connection_pool.ex | 86 ---------- lib/pleroma/gun/connection_pool/reclaimer.ex | 89 ---------- lib/pleroma/gun/connection_pool/worker.ex | 153 ------------------ .../gun/connection_pool/worker_supervisor.ex | 49 ------ lib/pleroma/reverse_proxy/client/hackney.ex | 25 --- mix.exs | 3 +- mix.lock | 7 +- test/pleroma/user_test.exs | 3 - .../controllers/admin_api_controller_test.exs | 3 - 14 files changed, 8 insertions(+), 644 deletions(-) delete mode 100644 lib/pleroma/gun/api.ex delete mode 100644 lib/pleroma/gun/conn.ex delete mode 100644 lib/pleroma/gun/connection_pool.ex delete mode 100644 lib/pleroma/gun/connection_pool/reclaimer.ex delete mode 100644 lib/pleroma/gun/connection_pool/worker.ex delete mode 100644 lib/pleroma/gun/connection_pool/worker_supervisor.ex delete mode 100644 lib/pleroma/reverse_proxy/client/hackney.ex diff --git a/config/config.exs b/config/config.exs index 4d6150634..bbf3d2072 100644 --- a/config/config.exs +++ b/config/config.exs @@ -655,6 +655,10 @@ config :pleroma, Pleroma.Emails.Mailer, adapter: Swoosh.Adapters.Sendmail, enabled: false +config :swoosh, + api_client: Swoosh.ApiClient.Finch, + finch_name: MyFinch + config :pleroma, Pleroma.Emails.UserEmail, logo: nil, styling: %{ diff --git a/docs/docs/configuration/cheatsheet.md b/docs/docs/configuration/cheatsheet.md index 3c8bbcf84..b956d26e4 100644 --- a/docs/docs/configuration/cheatsheet.md +++ b/docs/docs/configuration/cheatsheet.md @@ -528,54 +528,6 @@ Available caches: * `user_agent`: what user agent should we use? (default: `:default`), must be string or `:default` * `adapter`: array of adapter options -### :hackney_pools - -Advanced. Tweaks Hackney (http client) connections pools. - -There's three pools used: - -* `:federation` for the federation jobs. - You may want this pool max_connections to be at least equal to the number of federator jobs + retry queue jobs. -* `:media` for rich media, media proxy -* `:upload` for uploaded media (if using a remote uploader and `proxy_remote: true`) - -For each pool, the options are: - -* `max_connections` - how much connections a pool can hold -* `timeout` - retention duration for connections - - -### :connections_pool - -*For `gun` adapter* - -Settings for HTTP connection pool. - -* `:connection_acquisition_wait` - Timeout to acquire a connection from pool.The total max time is this value multiplied by the number of retries. -* `connection_acquisition_retries` - Number of attempts to acquire the connection from the pool if it is overloaded. Each attempt is timed `:connection_acquisition_wait` apart. -* `:max_connections` - Maximum number of connections in the pool. -* `:connect_timeout` - Timeout to connect to the host. -* `:reclaim_multiplier` - Multiplied by `:max_connections` this will be the maximum number of idle connections that will be reclaimed in case the pool is overloaded. - -### :pools - -*For `gun` adapter* - -Settings for request pools. These pools are limited on top of `:connections_pool`. - -There are four pools used: - -* `:federation` for the federation jobs. You may want this pool's max_connections to be at least equal to the number of federator jobs + retry queue jobs. -* `:media` - for rich media, media proxy. -* `:upload` - for proxying media when a remote uploader is used and `proxy_remote: true`. -* `:default` - for other requests. - -For each pool, the options are: - -* `:size` - limit to how much requests can be concurrently executed. -* `:recv_timeout` - timeout while `gun` will wait for response -* `:max_waiting` - limit to how much requests can be waiting for others to finish, after this is reached, subsequent requests will be dropped. - ## Captcha ### Pleroma.Captcha diff --git a/lib/pleroma/emails/mailer.ex b/lib/pleroma/emails/mailer.ex index c68550bee..d42236c5e 100644 --- a/lib/pleroma/emails/mailer.ex +++ b/lib/pleroma/emails/mailer.ex @@ -35,11 +35,6 @@ def perform(:deliver_async, email, config), do: deliver(email, config) def deliver(email, config \\ []) def deliver(email, config) do - # temporary hackney fix until hackney max_connections bug is fixed - # https://git.pleroma.social/pleroma/pleroma/-/issues/2101 - email = - Swoosh.Email.put_private(email, :hackney_options, ssl_options: [versions: [:"tlsv1.2"]]) - case enabled?() do true -> Swoosh.Mailer.deliver(email, parse_config(config)) false -> {:error, :deliveries_disabled} diff --git a/lib/pleroma/gun/api.ex b/lib/pleroma/gun/api.ex deleted file mode 100644 index 24d542781..000000000 --- a/lib/pleroma/gun/api.ex +++ /dev/null @@ -1,46 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2021 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Gun.API do - @behaviour Pleroma.Gun - - alias Pleroma.Gun - - @gun_keys [ - :connect_timeout, - :http_opts, - :http2_opts, - :protocols, - :retry, - :retry_timeout, - :trace, - :transport, - :tls_opts, - :tcp_opts, - :socks_opts, - :ws_opts, - :supervise - ] - - @impl Gun - def open(host, port, opts \\ %{}), do: :gun.open(host, port, Map.take(opts, @gun_keys)) - - @impl Gun - defdelegate info(pid), to: :gun - - @impl Gun - defdelegate close(pid), to: :gun - - @impl Gun - defdelegate await_up(pid, timeout \\ 5_000), to: :gun - - @impl Gun - defdelegate connect(pid, opts), to: :gun - - @impl Gun - defdelegate await(pid, ref), to: :gun - - @impl Gun - defdelegate set_owner(pid, owner), to: :gun -end diff --git a/lib/pleroma/gun/conn.ex b/lib/pleroma/gun/conn.ex deleted file mode 100644 index a1210eabf..000000000 --- a/lib/pleroma/gun/conn.ex +++ /dev/null @@ -1,131 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2021 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Gun.Conn do - alias Pleroma.Gun - - require Logger - - def open(%URI{} = uri, opts) do - pool_opts = Pleroma.Config.get([:connections_pool], []) - - opts = - opts - |> Enum.into(%{}) - |> Map.put_new(:connect_timeout, pool_opts[:connect_timeout] || 5_000) - |> Map.put_new(:supervise, false) - |> maybe_add_tls_opts(uri) - - do_open(uri, opts) - end - - defp maybe_add_tls_opts(opts, %URI{scheme: "http"}), do: opts - - defp maybe_add_tls_opts(opts, %URI{scheme: "https"}) do - tls_opts = [ - verify: :verify_peer, - cacertfile: CAStore.file_path(), - depth: 20, - reuse_sessions: false, - log_level: :warning, - customize_hostname_check: [match_fun: :public_key.pkix_verify_hostname_match_fun(:https)] - ] - - tls_opts = - if Keyword.keyword?(opts[:tls_opts]) do - Keyword.merge(tls_opts, opts[:tls_opts]) - else - tls_opts - end - - Map.put(opts, :tls_opts, tls_opts) - end - - defp do_open(uri, %{proxy: {proxy_host, proxy_port}} = opts) do - connect_opts = - uri - |> destination_opts() - |> add_http2_opts(uri.scheme, Map.get(opts, :tls_opts, [])) - - with open_opts <- Map.delete(opts, :tls_opts), - {:ok, conn} <- Gun.open(proxy_host, proxy_port, open_opts), - {:ok, protocol} <- Gun.await_up(conn, opts[:connect_timeout]), - stream <- Gun.connect(conn, connect_opts), - {:response, :fin, 200, _} <- Gun.await(conn, stream) do - {:ok, conn, protocol} - else - error -> - Logger.warn( - "Opening proxied connection to #{compose_uri_log(uri)} failed with error #{inspect(error)}" - ) - - error - end - end - - defp do_open(uri, %{proxy: {proxy_type, proxy_host, proxy_port}} = opts) do - version = - proxy_type - |> to_string() - |> String.last() - |> case do - "4" -> 4 - _ -> 5 - end - - socks_opts = - uri - |> destination_opts() - |> add_http2_opts(uri.scheme, Map.get(opts, :tls_opts, [])) - |> Map.put(:version, version) - - opts = - opts - |> Map.put(:protocols, [:socks]) - |> Map.put(:socks_opts, socks_opts) - - with {:ok, conn} <- Gun.open(proxy_host, proxy_port, opts), - {:ok, protocol} <- Gun.await_up(conn, opts[:connect_timeout]) do - {:ok, conn, protocol} - else - error -> - Logger.warn( - "Opening socks proxied connection to #{compose_uri_log(uri)} failed with error #{inspect(error)}" - ) - - error - end - end - - defp do_open(%URI{host: host, port: port} = uri, opts) do - host = Pleroma.HTTP.AdapterHelper.parse_host(host) - - with {:ok, conn} <- Gun.open(host, port, opts), - {:ok, protocol} <- Gun.await_up(conn, opts[:connect_timeout]) do - {:ok, conn, protocol} - else - error -> - Logger.warn( - "Opening connection to #{compose_uri_log(uri)} failed with error #{inspect(error)}" - ) - - error - end - end - - defp destination_opts(%URI{host: host, port: port}) do - host = Pleroma.HTTP.AdapterHelper.parse_host(host) - %{host: host, port: port} - end - - defp add_http2_opts(opts, "https", tls_opts) do - Map.merge(opts, %{protocols: [:http2], transport: :tls, tls_opts: tls_opts}) - end - - defp add_http2_opts(opts, _, _), do: opts - - def compose_uri_log(%URI{scheme: scheme, host: host, path: path}) do - "#{scheme}://#{host}#{path}" - end -end diff --git a/lib/pleroma/gun/connection_pool.ex b/lib/pleroma/gun/connection_pool.ex deleted file mode 100644 index f9fd77ade..000000000 --- a/lib/pleroma/gun/connection_pool.ex +++ /dev/null @@ -1,86 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2021 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Gun.ConnectionPool do - @registry __MODULE__ - - alias Pleroma.Gun.ConnectionPool.WorkerSupervisor - - def children do - [ - {Registry, keys: :unique, name: @registry}, - Pleroma.Gun.ConnectionPool.WorkerSupervisor - ] - end - - @spec get_conn(URI.t(), keyword()) :: {:ok, pid()} | {:error, term()} - def get_conn(uri, opts) do - key = "#{uri.scheme}:#{uri.host}:#{uri.port}" - - case Registry.lookup(@registry, key) do - # The key has already been registered, but connection is not up yet - [{worker_pid, nil}] -> - get_gun_pid_from_worker(worker_pid, true) - - [{worker_pid, {gun_pid, _used_by, _crf, _last_reference}}] -> - GenServer.call(worker_pid, :add_client) - {:ok, gun_pid} - - [] -> - # :gun.set_owner fails in :connected state for whatevever reason, - # so we open the connection in the process directly and send it's pid back - # We trust gun to handle timeouts by itself - case WorkerSupervisor.start_worker([key, uri, opts, self()]) do - {:ok, worker_pid} -> - get_gun_pid_from_worker(worker_pid, false) - - {:error, {:already_started, worker_pid}} -> - get_gun_pid_from_worker(worker_pid, true) - - err -> - err - end - end - end - - defp get_gun_pid_from_worker(worker_pid, register) do - # GenServer.call will block the process for timeout length if - # the server crashes on startup (which will happen if gun fails to connect) - # so instead we use cast + monitor - - ref = Process.monitor(worker_pid) - if register, do: GenServer.cast(worker_pid, {:add_client, self()}) - - receive do - {:conn_pid, pid} -> - Process.demonitor(ref) - {:ok, pid} - - {:DOWN, ^ref, :process, ^worker_pid, reason} -> - case reason do - {:shutdown, {:error, _} = error} -> error - {:shutdown, error} -> {:error, error} - _ -> {:error, reason} - end - end - end - - @spec release_conn(pid()) :: :ok - def release_conn(conn_pid) do - # :ets.fun2ms(fn {_, {worker_pid, {gun_pid, _, _, _}}} when gun_pid == conn_pid -> - # worker_pid end) - query_result = - Registry.select(@registry, [ - {{:_, :"$1", {:"$2", :_, :_, :_}}, [{:==, :"$2", conn_pid}], [:"$1"]} - ]) - - case query_result do - [worker_pid] -> - GenServer.call(worker_pid, :remove_client) - - [] -> - :ok - end - end -end diff --git a/lib/pleroma/gun/connection_pool/reclaimer.ex b/lib/pleroma/gun/connection_pool/reclaimer.ex deleted file mode 100644 index 4c643d7cb..000000000 --- a/lib/pleroma/gun/connection_pool/reclaimer.ex +++ /dev/null @@ -1,89 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2021 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Gun.ConnectionPool.Reclaimer do - use GenServer, restart: :temporary - - defp registry, do: Pleroma.Gun.ConnectionPool - - def start_monitor do - pid = - case :gen_server.start(__MODULE__, [], name: {:via, Registry, {registry(), "reclaimer"}}) do - {:ok, pid} -> - pid - - {:error, {:already_registered, pid}} -> - pid - end - - {pid, Process.monitor(pid)} - end - - @impl true - def init(_) do - {:ok, nil, {:continue, :reclaim}} - end - - @impl true - def handle_continue(:reclaim, _) do - max_connections = Pleroma.Config.get([:connections_pool, :max_connections]) - - reclaim_max = - [:connections_pool, :reclaim_multiplier] - |> Pleroma.Config.get() - |> Kernel.*(max_connections) - |> round - |> max(1) - - :telemetry.execute([:pleroma, :connection_pool, :reclaim, :start], %{}, %{ - max_connections: max_connections, - reclaim_max: reclaim_max - }) - - # :ets.fun2ms( - # fn {_, {worker_pid, {_, used_by, crf, last_reference}}} when used_by == [] -> - # {worker_pid, crf, last_reference} end) - unused_conns = - Registry.select( - registry(), - [ - {{:_, :"$1", {:_, :"$2", :"$3", :"$4"}}, [{:==, :"$2", []}], [{{:"$1", :"$3", :"$4"}}]} - ] - ) - - case unused_conns do - [] -> - :telemetry.execute( - [:pleroma, :connection_pool, :reclaim, :stop], - %{reclaimed_count: 0}, - %{ - max_connections: max_connections - } - ) - - {:stop, :no_unused_conns, nil} - - unused_conns -> - reclaimed = - unused_conns - |> Enum.sort(fn {_pid1, crf1, last_reference1}, {_pid2, crf2, last_reference2} -> - crf1 <= crf2 and last_reference1 <= last_reference2 - end) - |> Enum.take(reclaim_max) - - reclaimed - |> Enum.each(fn {pid, _, _} -> - DynamicSupervisor.terminate_child(Pleroma.Gun.ConnectionPool.WorkerSupervisor, pid) - end) - - :telemetry.execute( - [:pleroma, :connection_pool, :reclaim, :stop], - %{reclaimed_count: Enum.count(reclaimed)}, - %{max_connections: max_connections} - ) - - {:stop, :normal, nil} - end - end -end diff --git a/lib/pleroma/gun/connection_pool/worker.ex b/lib/pleroma/gun/connection_pool/worker.ex deleted file mode 100644 index a3fa75386..000000000 --- a/lib/pleroma/gun/connection_pool/worker.ex +++ /dev/null @@ -1,153 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2021 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Gun.ConnectionPool.Worker do - alias Pleroma.Gun - use GenServer, restart: :temporary - - defp registry, do: Pleroma.Gun.ConnectionPool - - def start_link([key | _] = opts) do - GenServer.start_link(__MODULE__, opts, name: {:via, Registry, {registry(), key}}) - end - - @impl true - def init([_key, _uri, _opts, _client_pid] = opts) do - {:ok, nil, {:continue, {:connect, opts}}} - end - - @impl true - def handle_continue({:connect, [key, uri, opts, client_pid]}, _) do - with {:ok, conn_pid, protocol} <- Gun.Conn.open(uri, opts), - Process.link(conn_pid) do - time = :erlang.monotonic_time(:millisecond) - - {_, _} = - Registry.update_value(registry(), key, fn _ -> - {conn_pid, [client_pid], 1, time} - end) - - send(client_pid, {:conn_pid, conn_pid}) - - {:noreply, - %{ - key: key, - timer: nil, - client_monitors: %{client_pid => Process.monitor(client_pid)}, - protocol: protocol - }, :hibernate} - else - err -> - {:stop, {:shutdown, err}, nil} - end - end - - @impl true - def handle_cast({:add_client, client_pid}, state) do - case handle_call(:add_client, {client_pid, nil}, state) do - {:reply, conn_pid, state, :hibernate} -> - send(client_pid, {:conn_pid, conn_pid}) - {:noreply, state, :hibernate} - end - end - - @impl true - def handle_cast({:remove_client, client_pid}, state) do - case handle_call(:remove_client, {client_pid, nil}, state) do - {:reply, _, state, :hibernate} -> - {:noreply, state, :hibernate} - end - end - - @impl true - def handle_call(:add_client, {client_pid, _}, %{key: key, protocol: protocol} = state) do - time = :erlang.monotonic_time(:millisecond) - - {{conn_pid, used_by, _, _}, _} = - Registry.update_value(registry(), key, fn {conn_pid, used_by, crf, last_reference} -> - {conn_pid, [client_pid | used_by], crf(time - last_reference, crf), time} - end) - - :telemetry.execute( - [:pleroma, :connection_pool, :client, :add], - %{client_pid: client_pid, clients: used_by}, - %{key: state.key, protocol: protocol} - ) - - state = - if state.timer != nil do - Process.cancel_timer(state[:timer]) - %{state | timer: nil} - else - state - end - - ref = Process.monitor(client_pid) - - state = put_in(state.client_monitors[client_pid], ref) - {:reply, conn_pid, state, :hibernate} - end - - @impl true - def handle_call(:remove_client, {client_pid, _}, %{key: key} = state) do - {{_conn_pid, used_by, _crf, _last_reference}, _} = - Registry.update_value(registry(), key, fn {conn_pid, used_by, crf, last_reference} -> - {conn_pid, List.delete(used_by, client_pid), crf, last_reference} - end) - - {ref, state} = pop_in(state.client_monitors[client_pid]) - - Process.demonitor(ref, [:flush]) - - timer = - if used_by == [] do - max_idle = Pleroma.Config.get([:connections_pool, :max_idle_time], 30_000) - Process.send_after(self(), :idle_close, max_idle) - else - nil - end - - {:reply, :ok, %{state | timer: timer}, :hibernate} - end - - @impl true - def handle_info(:idle_close, state) do - # Gun monitors the owner process, and will close the connection automatically - # when it's terminated - {:stop, :normal, state} - end - - @impl true - def handle_info({:gun_up, _pid, _protocol}, state) do - {:noreply, state, :hibernate} - end - - # Gracefully shutdown if the connection got closed without any streams left - @impl true - def handle_info({:gun_down, _pid, _protocol, _reason, []}, state) do - {:stop, :normal, state} - end - - # Otherwise, wait for retry - @impl true - def handle_info({:gun_down, _pid, _protocol, _reason, _killed_streams}, state) do - {:noreply, state, :hibernate} - end - - @impl true - def handle_info({:DOWN, _ref, :process, pid, reason}, state) do - :telemetry.execute( - [:pleroma, :connection_pool, :client, :dead], - %{client_pid: pid, reason: reason}, - %{key: state.key} - ) - - handle_cast({:remove_client, pid}, state) - end - - # LRFU policy: https://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.55.1478 - defp crf(time_delta, prev_crf) do - 1 + :math.pow(0.5, 0.0001 * time_delta) * prev_crf - end -end diff --git a/lib/pleroma/gun/connection_pool/worker_supervisor.ex b/lib/pleroma/gun/connection_pool/worker_supervisor.ex deleted file mode 100644 index 016b675f4..000000000 --- a/lib/pleroma/gun/connection_pool/worker_supervisor.ex +++ /dev/null @@ -1,49 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2021 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Gun.ConnectionPool.WorkerSupervisor do - @moduledoc "Supervisor for pool workers. Does not do anything except enforce max connection limit" - - use DynamicSupervisor - - def start_link(opts) do - DynamicSupervisor.start_link(__MODULE__, opts, name: __MODULE__) - end - - def init(_opts) do - DynamicSupervisor.init( - strategy: :one_for_one, - max_children: Pleroma.Config.get([:connections_pool, :max_connections]) - ) - end - - def start_worker(opts, retry \\ false) do - case DynamicSupervisor.start_child(__MODULE__, {Pleroma.Gun.ConnectionPool.Worker, opts}) do - {:error, :max_children} -> - if retry or free_pool() == :error do - :telemetry.execute([:pleroma, :connection_pool, :provision_failure], %{opts: opts}) - {:error, :pool_full} - else - start_worker(opts, true) - end - - res -> - res - end - end - - defp free_pool do - wait_for_reclaimer_finish(Pleroma.Gun.ConnectionPool.Reclaimer.start_monitor()) - end - - defp wait_for_reclaimer_finish({pid, mon}) do - receive do - {:DOWN, ^mon, :process, ^pid, :no_unused_conns} -> - :error - - {:DOWN, ^mon, :process, ^pid, :normal} -> - :ok - end - end -end diff --git a/lib/pleroma/reverse_proxy/client/hackney.ex b/lib/pleroma/reverse_proxy/client/hackney.ex deleted file mode 100644 index dba946308..000000000 --- a/lib/pleroma/reverse_proxy/client/hackney.ex +++ /dev/null @@ -1,25 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2021 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.ReverseProxy.Client.Hackney do - @behaviour Pleroma.ReverseProxy.Client - - @impl true - def request(method, url, headers, body, opts \\ []) do - opts = Keyword.put(opts, :ssl_options, versions: [:"tlsv1.2", :"tlsv1.1", :tlsv1]) - :hackney.request(method, url, headers, body, opts) - end - - @impl true - def stream_body(ref) do - case :hackney.stream_body(ref) do - :done -> :done - {:ok, data} -> {:ok, data, ref} - {:error, error} -> {:error, error} - end - end - - @impl true - def close(ref), do: :hackney.close(ref) -end diff --git a/mix.exs b/mix.exs index 39cb4b5ac..0c65c74be 100644 --- a/mix.exs +++ b/mix.exs @@ -138,8 +138,7 @@ defp deps do {:tesla, "~> 1.4.4", override: true}, {:castore, "~> 0.1"}, {:cowlib, "~> 2.9", override: true}, - {:gun, "~> 2.0.0-rc.1", override: true}, - {:finch, "~> 0.13.0"}, + {:finch, "~> 0.14.0"}, {:jason, "~> 1.2"}, {:mogrify, "~> 0.9.1"}, {:ex_aws, "~> 2.1.6"}, diff --git a/mix.lock b/mix.lock index dda8f92ec..1af08a896 100644 --- a/mix.lock +++ b/mix.lock @@ -7,7 +7,7 @@ "cachex": {:hex, :cachex, "3.4.0", "868b2959ea4aeb328c6b60ff66c8d5123c083466ad3c33d3d8b5f142e13101fb", [:mix], [{:eternal, "~> 1.2", [hex: :eternal, repo: "hexpm", optional: false]}, {:jumper, "~> 1.0", [hex: :jumper, repo: "hexpm", optional: false]}, {:sleeplocks, "~> 1.1", [hex: :sleeplocks, repo: "hexpm", optional: false]}, {:unsafe, "~> 1.0", [hex: :unsafe, repo: "hexpm", optional: false]}], "hexpm", "370123b1ab4fba4d2965fb18f87fd758325709787c8c5fce35b3fe80645ccbe5"}, "calendar": {:hex, :calendar, "1.0.0", "f52073a708528482ec33d0a171954ca610fe2bd28f1e871f247dc7f1565fa807", [:mix], [{:tzdata, "~> 0.1.201603 or ~> 0.5.20 or ~> 1.0", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm", "990e9581920c82912a5ee50e62ff5ef96da6b15949a2ee4734f935fdef0f0a6f"}, "captcha": {:git, "https://git.pleroma.social/pleroma/elixir-libraries/elixir-captcha.git", "e0f16822d578866e186a0974d65ad58cddc1e2ab", [ref: "e0f16822d578866e186a0974d65ad58cddc1e2ab"]}, - "castore": {:hex, :castore, "0.1.19", "a2c3e46d62b7f3aa2e6f88541c21d7400381e53704394462b9fd4f06f6d42bb6", [:mix], [], "hexpm", "e96e0161a5dc82ef441da24d5fa74aefc40d920f3a6645d15e1f9f3e66bb2109"}, + "castore": {:hex, :castore, "0.1.20", "62a0126cbb7cb3e259257827b9190f88316eb7aa3fdac01fd6f2dfd64e7f46e9", [:mix], [], "hexpm", "a020b7650529c986c454a4035b6b13a328e288466986307bea3aadb4c95ac98a"}, "certifi": {:hex, :certifi, "2.9.0", "6f2a475689dd47f19fb74334859d460a2dc4e3252a3324bd2111b8f0429e7e21", [:rebar3], [], "hexpm", "266da46bdb06d6c6d35fde799bcb28d36d985d424ad7c08b5bb48f5b5cdd4641"}, "combine": {:hex, :combine, "0.10.0", "eff8224eeb56498a2af13011d142c5e7997a80c8f5b97c499f84c841032e429f", [:mix], [], "hexpm", "1b1dbc1790073076580d0d1d64e42eae2366583e7aecd455d1215b0d16f2451b"}, "comeonin": {:hex, :comeonin, "5.3.3", "2c564dac95a35650e9b6acfe6d2952083d8a08e4a89b93a481acb552b325892e", [:mix], [], "hexpm", "3e38c9c2cb080828116597ca8807bb482618a315bfafd98c90bc22a821cc84df"}, @@ -43,12 +43,11 @@ "fast_html": {:hex, :fast_html, "2.0.5", "c61760340606c1077ff1f196f17834056cb1dd3d5cb92a9f2cabf28bc6221c3c", [:make, :mix], [{:elixir_make, "~> 0.4", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.2.0", [hex: :nimble_pool, repo: "hexpm", optional: false]}], "hexpm", "605f4f4829443c14127694ebabb681778712ceecb4470ec32aa31012330e6506"}, "fast_sanitize": {:hex, :fast_sanitize, "0.2.3", "67b93dfb34e302bef49fec3aaab74951e0f0602fd9fa99085987af05bd91c7a5", [:mix], [{:fast_html, "~> 2.0", [hex: :fast_html, repo: "hexpm", optional: false]}, {:plug, "~> 1.8", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "e8ad286d10d0386e15d67d0ee125245ebcfbc7d7290b08712ba9013c8c5e56e2"}, "file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"}, - "finch": {:hex, :finch, "0.13.0", "c881e5460ec563bf02d4f4584079e62201db676ed4c0ef3e59189331c4eddf7b", [:mix], [{:castore, "~> 0.1", [hex: :castore, repo: "hexpm", optional: false]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.3", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.2.6", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "49957dcde10dcdc042a123a507a9c5ec5a803f53646d451db2f7dea696fba6cc"}, + "finch": {:hex, :finch, "0.14.0", "619bfdee18fc135190bf590356c4bf5d5f71f916adb12aec94caa3fa9267a4bc", [:mix], [{:castore, "~> 0.1", [hex: :castore, repo: "hexpm", optional: false]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.3", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.2.6", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "5459acaf18c4fdb47a8c22fb3baff5d8173106217c8e56c5ba0b93e66501a8dd"}, "flake_id": {:hex, :flake_id, "0.1.0", "7716b086d2e405d09b647121a166498a0d93d1a623bead243e1f74216079ccb3", [:mix], [{:base62, "~> 1.2", [hex: :base62, repo: "hexpm", optional: false]}, {:ecto, ">= 2.0.0", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm", "31fc8090fde1acd267c07c36ea7365b8604055f897d3a53dd967658c691bd827"}, "floki": {:hex, :floki, "0.34.0", "002d0cc194b48794d74711731db004fafeb328fe676976f160685262d43706a8", [:mix], [], "hexpm", "9c3a9f43f40dde00332a589bd9d389b90c1f518aef500364d00636acc5ebc99c"}, "gen_smtp": {:hex, :gen_smtp, "0.15.0", "9f51960c17769b26833b50df0b96123605a8024738b62db747fece14eb2fbfcc", [:rebar3], [], "hexpm", "29bd14a88030980849c7ed2447b8db6d6c9278a28b11a44cafe41b791205440f"}, "gettext": {:git, "https://github.com/tusooa/gettext.git", "72fb2496b6c5280ed911bdc3756890e7f38a4808", [ref: "72fb2496b6c5280ed911bdc3756890e7f38a4808"]}, - "gun": {:hex, :gun, "2.0.0-rc.2", "7c489a32dedccb77b6e82d1f3c5a7dadfbfa004ec14e322cdb5e579c438632d2", [:make, :rebar3], [{:cowlib, "2.11.0", [hex: :cowlib, repo: "hexpm", optional: false]}], "hexpm", "6b9d1eae146410d727140dbf8b404b9631302ecc2066d1d12f22097ad7d254fc"}, "hackney": {:hex, :hackney, "1.18.1", "f48bf88f521f2a229fc7bae88cf4f85adc9cd9bcf23b5dc8eb6a1788c662c4f6", [:rebar3], [{:certifi, "~> 2.9.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~> 6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~> 1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~> 1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.3.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "a4ecdaff44297e9b5894ae499e9a070ea1888c84afdd1fd9b7b2bc384950128e"}, "hpax": {:hex, :hpax, "0.1.2", "09a75600d9d8bbd064cdd741f21fc06fc1f4cf3d0fcc335e5aa19be1a7235c84", [:mix], [], "hexpm", "2c87843d5a23f5f16748ebe77969880e29809580efdaccd615cd3bed628a8c13"}, "html_entities": {:hex, :html_entities, "0.5.2", "9e47e70598da7de2a9ff6af8758399251db6dbb7eebe2b013f2bbd2515895c3c", [:mix], [], "hexpm", "c53ba390403485615623b9531e97696f076ed415e8d8058b1dbaa28181f4fdcc"}, @@ -74,7 +73,7 @@ "mock": {:hex, :mock, "0.3.7", "75b3bbf1466d7e486ea2052a73c6e062c6256fb429d6797999ab02fa32f29e03", [:mix], [{:meck, "~> 0.9.2", [hex: :meck, repo: "hexpm", optional: false]}], "hexpm", "4da49a4609e41fd99b7836945c26f373623ea968cfb6282742bcb94440cf7e5c"}, "mogrify": {:hex, :mogrify, "0.9.2", "b360984adea7dd6a55f18028e6327973c58de7f548fdb86c9859848aa904d5b0", [:mix], [], "hexpm", "c18d10fd70ca20e2585301616c89f6e4f7159d92efc9cc8ee579e00c886f699d"}, "mox": {:hex, :mox, "1.0.2", "dc2057289ac478b35760ba74165b4b3f402f68803dd5aecd3bfd19c183815d64", [:mix], [], "hexpm", "f9864921b3aaf763c8741b5b8e6f908f44566f1e427b2630e89e9a73b981fef2"}, - "nimble_options": {:hex, :nimble_options, "0.4.0", "c89babbab52221a24b8d1ff9e7d838be70f0d871be823165c94dd3418eea728f", [:mix], [], "hexpm", "e6701c1af326a11eea9634a3b1c62b475339ace9456c1a23ec3bc9a847bca02d"}, + "nimble_options": {:hex, :nimble_options, "0.5.1", "5c166f7669e40333191bea38e3bd3811cc13f459f1e4be49e89128a21b5d8c4d", [:mix], [], "hexpm", "d176cf7baa4fef0ceb301ca3eb8b55bd7de3e45f489c4f8b4f2849f1f114ef3e"}, "nimble_parsec": {:hex, :nimble_parsec, "1.2.3", "244836e6e3f1200c7f30cb56733fd808744eca61fd182f731eac4af635cc6d0b", [:mix], [], "hexpm", "c8d789e39b9131acf7b99291e93dae60ab48ef14a7ee9d58c6964f59efb570b0"}, "nimble_pool": {:hex, :nimble_pool, "0.2.6", "91f2f4c357da4c4a0a548286c84a3a28004f68f05609b4534526871a22053cde", [:mix], [], "hexpm", "1c715055095d3f2705c4e236c18b618420a35490da94149ff8b580a2144f653f"}, "oban": {:hex, :oban, "2.12.1", "f604d7e6a8be9fda4a9b0f6cebbd633deba569f85dbff70c4d25d99a6f023177", [:mix], [{:ecto_sql, "~> 3.6", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.16", [hex: :postgrex, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "9b1844c2b74e0d788b73e5144b0c9d5674cb775eae29d88a36f3c3b48d42d058"}, diff --git a/test/pleroma/user_test.exs b/test/pleroma/user_test.exs index cc6634aba..a590946c2 100644 --- a/test/pleroma/user_test.exs +++ b/test/pleroma/user_test.exs @@ -499,9 +499,6 @@ test "it sends a confirm email" do ObanHelpers.perform_all() Pleroma.Emails.UserEmail.account_confirmation_email(registered_user) - # temporary hackney fix until hackney max_connections bug is fixed - # https://git.pleroma.social/pleroma/pleroma/-/issues/2101 - |> Swoosh.Email.put_private(:hackney_options, ssl_options: [versions: [:"tlsv1.2"]]) |> assert_email_sent() end diff --git a/test/pleroma/web/admin_api/controllers/admin_api_controller_test.exs b/test/pleroma/web/admin_api/controllers/admin_api_controller_test.exs index d74e0281c..7c001ada3 100644 --- a/test/pleroma/web/admin_api/controllers/admin_api_controller_test.exs +++ b/test/pleroma/web/admin_api/controllers/admin_api_controller_test.exs @@ -800,9 +800,6 @@ test "it resend emails for two users", %{conn: conn, admin: admin} do ObanHelpers.perform_all() Pleroma.Emails.UserEmail.account_confirmation_email(first_user) - # temporary hackney fix until hackney max_connections bug is fixed - # https://git.pleroma.social/pleroma/pleroma/-/issues/2101 - |> Swoosh.Email.put_private(:hackney_options, ssl_options: [versions: [:"tlsv1.2"]]) |> assert_email_sent() end end From 9d9c26b833a698d48fefecc25e64f04a844168c1 Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Sun, 11 Dec 2022 19:26:21 +0000 Subject: [PATCH 123/631] Ensure Gun is Gone --- CHANGELOG.md | 8 +++ lib/pleroma/frontend.ex | 2 +- lib/pleroma/gun.ex | 29 ----------- lib/pleroma/reverse_proxy/client/tesla.ex | 6 --- lib/pleroma/reverse_proxy/client/wrapper.ex | 4 +- .../tesla/middleware/connection_pool.ex | 50 ------------------- .../mrf/media_proxy_warming_policy.ex | 2 +- lib/pleroma/web/rel_me.ex | 2 +- lib/pleroma/web/rich_media/helpers.ex | 2 +- 9 files changed, 13 insertions(+), 92 deletions(-) delete mode 100644 lib/pleroma/gun.ex delete mode 100644 lib/pleroma/tesla/middleware/connection_pool.ex diff --git a/CHANGELOG.md b/CHANGELOG.md index bf5513fbb..f1dd50ddc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,14 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). +## Unreleased + +## Removed +- Non-finch HTTP adapters + +## Upgrade notes +- Ensure `config :tesla, :adapter` is either unset, or set to `{Tesla.Adapter.Finch, name: MyFinch}` in your .exs config + ## 2022.12 ## Added diff --git a/lib/pleroma/frontend.ex b/lib/pleroma/frontend.ex index adda71eef..dc9d55646 100644 --- a/lib/pleroma/frontend.ex +++ b/lib/pleroma/frontend.ex @@ -93,7 +93,7 @@ defp download_build(frontend_info, dest) do url = String.replace(frontend_info["build_url"], "${ref}", frontend_info["ref"]) with {:ok, %{status: 200, body: zip_body}} <- - Pleroma.HTTP.get(url, [], recv_timeout: 120_000) do + Pleroma.HTTP.get(url, [], receive_timeout: 120_000) do unzip(zip_body, dest) else {:error, e} -> {:error, e} diff --git a/lib/pleroma/gun.ex b/lib/pleroma/gun.ex deleted file mode 100644 index bef1c9872..000000000 --- a/lib/pleroma/gun.ex +++ /dev/null @@ -1,29 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2021 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Gun do - @callback open(charlist(), pos_integer(), map()) :: {:ok, pid()} - @callback info(pid()) :: map() - @callback close(pid()) :: :ok - @callback await_up(pid, pos_integer()) :: {:ok, atom()} | {:error, atom()} - @callback connect(pid(), map()) :: reference() - @callback await(pid(), reference()) :: {:response, :fin, 200, []} - @callback set_owner(pid(), pid()) :: :ok - - defp api, do: Pleroma.Config.get([Pleroma.Gun], Pleroma.Gun.API) - - def open(host, port, opts), do: api().open(host, port, opts) - - def info(pid), do: api().info(pid) - - def close(pid), do: api().close(pid) - - def await_up(pid, timeout \\ 5_000), do: api().await_up(pid, timeout) - - def connect(pid, opts), do: api().connect(pid, opts) - - def await(pid, ref), do: api().await(pid, ref) - - def set_owner(pid, owner), do: api().set_owner(pid, owner) -end diff --git a/lib/pleroma/reverse_proxy/client/tesla.ex b/lib/pleroma/reverse_proxy/client/tesla.ex index 36a0a2060..b21dc9036 100644 --- a/lib/pleroma/reverse_proxy/client/tesla.ex +++ b/lib/pleroma/reverse_proxy/client/tesla.ex @@ -5,8 +5,6 @@ defmodule Pleroma.ReverseProxy.Client.Tesla do @behaviour Pleroma.ReverseProxy.Client - alias Pleroma.Gun.ConnectionPool - @type headers() :: [{String.t(), String.t()}] @type status() :: pos_integer() @@ -77,10 +75,6 @@ def close(%{pid: pid}) do defp check_adapter do adapter = Application.get_env(:tesla, :adapter) - unless adapter == Tesla.Adapter.Gun do - raise "#{adapter} doesn't support reading body in chunks" - end - adapter end end diff --git a/lib/pleroma/reverse_proxy/client/wrapper.ex b/lib/pleroma/reverse_proxy/client/wrapper.ex index ce144559f..b9a05ce11 100644 --- a/lib/pleroma/reverse_proxy/client/wrapper.ex +++ b/lib/pleroma/reverse_proxy/client/wrapper.ex @@ -23,8 +23,6 @@ defp client do |> client() end - defp client(Tesla.Adapter.Hackney), do: Pleroma.ReverseProxy.Client.Hackney - defp client(Tesla.Adapter.Gun), do: Pleroma.ReverseProxy.Client.Tesla - defp client({Tesla.Adapter.Finch, _}), do: Pleroma.ReverseProxy.Client.Hackney + defp client({Tesla.Adapter.Finch, _}), do: Pleroma.ReverseProxy.Client.Tesla defp client(_), do: Pleroma.Config.get!(Pleroma.ReverseProxy.Client) end diff --git a/lib/pleroma/tesla/middleware/connection_pool.ex b/lib/pleroma/tesla/middleware/connection_pool.ex deleted file mode 100644 index 906706d39..000000000 --- a/lib/pleroma/tesla/middleware/connection_pool.ex +++ /dev/null @@ -1,50 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2021 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Tesla.Middleware.ConnectionPool do - @moduledoc """ - Middleware to get/release connections from `Pleroma.Gun.ConnectionPool` - """ - - @behaviour Tesla.Middleware - - alias Pleroma.Gun.ConnectionPool - - @impl Tesla.Middleware - def call(%Tesla.Env{url: url, opts: opts} = env, next, _) do - uri = URI.parse(url) - - # Avoid leaking connections when the middleware is called twice - # with body_as: :chunks. We assume only the middleware can set - # opts[:adapter][:conn] - if opts[:adapter][:conn] do - ConnectionPool.release_conn(opts[:adapter][:conn]) - end - - case ConnectionPool.get_conn(uri, opts[:adapter]) do - {:ok, conn_pid} -> - adapter_opts = Keyword.merge(opts[:adapter], conn: conn_pid, close_conn: false) - opts = Keyword.put(opts, :adapter, adapter_opts) - env = %{env | opts: opts} - - case Tesla.run(env, next) do - {:ok, env} -> - unless opts[:adapter][:body_as] == :chunks do - ConnectionPool.release_conn(conn_pid) - {_, res} = pop_in(env.opts[:adapter][:conn]) - {:ok, res} - else - {:ok, env} - end - - err -> - ConnectionPool.release_conn(conn_pid) - err - end - - err -> - err - end - end -end diff --git a/lib/pleroma/web/activity_pub/mrf/media_proxy_warming_policy.ex b/lib/pleroma/web/activity_pub/mrf/media_proxy_warming_policy.ex index 72455afd0..e5449b576 100644 --- a/lib/pleroma/web/activity_pub/mrf/media_proxy_warming_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/media_proxy_warming_policy.ex @@ -12,7 +12,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy do require Logger @adapter_options [ - recv_timeout: 10_000 + receive_timeout: 10_000 ] @impl true diff --git a/lib/pleroma/web/rel_me.ex b/lib/pleroma/web/rel_me.ex index da92b5754..1826031dd 100644 --- a/lib/pleroma/web/rel_me.ex +++ b/lib/pleroma/web/rel_me.ex @@ -5,7 +5,7 @@ defmodule Pleroma.Web.RelMe do @options [ max_body: 2_000_000, - recv_timeout: 2_000 + receive_timeout: 2_000 ] if Pleroma.Config.get(:env) == :test do diff --git a/lib/pleroma/web/rich_media/helpers.ex b/lib/pleroma/web/rich_media/helpers.ex index ba3524307..061c1a795 100644 --- a/lib/pleroma/web/rich_media/helpers.ex +++ b/lib/pleroma/web/rich_media/helpers.ex @@ -11,7 +11,7 @@ defmodule Pleroma.Web.RichMedia.Helpers do @options [ max_body: 2_000_000, - recv_timeout: 2_000 + receive_timeout: 2_000 ] @spec validate_page_url(URI.t() | binary()) :: :ok | :error From e6da301296e45af5e5024fb74484cabe011e44e4 Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Sun, 11 Dec 2022 22:57:18 +0000 Subject: [PATCH 124/631] Add diagnostics http --- lib/mix/tasks/pleroma/diagnostics.ex | 7 +++++++ lib/pleroma/reverse_proxy/client/tesla.ex | 8 ++------ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/lib/mix/tasks/pleroma/diagnostics.ex b/lib/mix/tasks/pleroma/diagnostics.ex index 6e83bf6f0..b8d8167bb 100644 --- a/lib/mix/tasks/pleroma/diagnostics.ex +++ b/lib/mix/tasks/pleroma/diagnostics.ex @@ -9,6 +9,13 @@ defmodule Mix.Tasks.Pleroma.Diagnostics do import Ecto.Query use Mix.Task + def run(["http", url]) do + start_pleroma() + + Pleroma.HTTP.get(url) + |> IO.inspect() + end + def run(["home_timeline", nickname]) do start_pleroma() user = Repo.get_by!(User, nickname: nickname) diff --git a/lib/pleroma/reverse_proxy/client/tesla.ex b/lib/pleroma/reverse_proxy/client/tesla.ex index b21dc9036..59fd5493c 100644 --- a/lib/pleroma/reverse_proxy/client/tesla.ex +++ b/lib/pleroma/reverse_proxy/client/tesla.ex @@ -31,8 +31,6 @@ def request(method, url, headers, body, opts \\ []) do if is_map(response.body) and method != :head do {:ok, response.status, response.headers, response.body} else - conn_pid = response.opts[:adapter][:conn] - ConnectionPool.release_conn(conn_pid) {:ok, response.status, response.headers} end else @@ -43,8 +41,7 @@ def request(method, url, headers, body, opts \\ []) do @impl true @spec stream_body(map()) :: {:ok, binary(), map()} | {:error, atom() | String.t()} | :done | no_return() - def stream_body(%{pid: pid, fin: true}) do - ConnectionPool.release_conn(pid) + def stream_body(%{pid: _pid, fin: true}) do :done end @@ -68,8 +65,7 @@ defp read_chunk!(%{pid: pid, stream: stream, opts: opts}) do @impl true @spec close(map) :: :ok | no_return() - def close(%{pid: pid}) do - ConnectionPool.release_conn(pid) + def close(%{pid: _pid}) do end defp check_adapter do From d81d8c9731b5a068338ee705b4689f5a511e04d8 Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Sun, 11 Dec 2022 22:58:26 +0000 Subject: [PATCH 125/631] uppdate excoveralls --- mix.exs | 3 +-- mix.lock | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/mix.exs b/mix.exs index 0c65c74be..64f96b29c 100644 --- a/mix.exs +++ b/mix.exs @@ -202,8 +202,7 @@ defp deps do {:ex_machina, "~> 2.4", only: :test}, {:credo, "~> 1.6", only: [:dev, :test], runtime: false}, {:mock, "~> 0.3.5", only: :test}, - # temporary downgrade for excoveralls, hackney until hackney max_connections bug will be fixed - {:excoveralls, "0.12.3", only: :test}, + {:excoveralls, "0.15.1", only: :test}, {:mox, "~> 1.0", only: :test}, {:websockex, "~> 0.4.3", only: :test} ] ++ oauth_deps() diff --git a/mix.lock b/mix.lock index 1af08a896..605b0235f 100644 --- a/mix.lock +++ b/mix.lock @@ -39,7 +39,7 @@ "ex_doc": {:hex, :ex_doc, "0.29.1", "b1c652fa5f92ee9cf15c75271168027f92039b3877094290a75abcaac82a9f77", [:mix], [{:earmark_parser, "~> 1.4.19", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "b7745fa6374a36daf484e2a2012274950e084815b936b1319aeebcf7809574f6"}, "ex_machina": {:hex, :ex_machina, "2.7.0", "b792cc3127fd0680fecdb6299235b4727a4944a09ff0fa904cc639272cd92dc7", [:mix], [{:ecto, "~> 2.2 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_sql, "~> 3.0", [hex: :ecto_sql, repo: "hexpm", optional: true]}], "hexpm", "419aa7a39bde11894c87a615c4ecaa52d8f107bbdd81d810465186f783245bf8"}, "ex_syslogger": {:hex, :ex_syslogger, "1.5.2", "72b6aa2d47a236e999171f2e1ec18698740f40af0bd02c8c650bf5f1fd1bac79", [:mix], [{:poison, ">= 1.5.0", [hex: :poison, repo: "hexpm", optional: true]}, {:syslog, "~> 1.1.0", [hex: :syslog, repo: "hexpm", optional: false]}], "hexpm", "ab9fab4136dbc62651ec6f16fa4842f10cf02ab4433fa3d0976c01be99398399"}, - "excoveralls": {:hex, :excoveralls, "0.12.3", "2142be7cb978a3ae78385487edda6d1aff0e482ffc6123877bb7270a8ffbcfe0", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "568a3e616c264283f5dea5b020783ae40eef3f7ee2163f7a67cbd7b35bcadada"}, + "excoveralls": {:hex, :excoveralls, "0.15.1", "83c8cf7973dd9d1d853dce37a2fb98aaf29b564bf7d01866e409abf59dac2c0e", [:mix], [{:hackney, "~> 1.16", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "f8416bd90c0082d56a2178cf46c837595a06575f70a5624f164a1ffe37de07e7"}, "fast_html": {:hex, :fast_html, "2.0.5", "c61760340606c1077ff1f196f17834056cb1dd3d5cb92a9f2cabf28bc6221c3c", [:make, :mix], [{:elixir_make, "~> 0.4", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.2.0", [hex: :nimble_pool, repo: "hexpm", optional: false]}], "hexpm", "605f4f4829443c14127694ebabb681778712ceecb4470ec32aa31012330e6506"}, "fast_sanitize": {:hex, :fast_sanitize, "0.2.3", "67b93dfb34e302bef49fec3aaab74951e0f0602fd9fa99085987af05bd91c7a5", [:mix], [{:fast_html, "~> 2.0", [hex: :fast_html, repo: "hexpm", optional: false]}, {:plug, "~> 1.8", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "e8ad286d10d0386e15d67d0ee125245ebcfbc7d7290b08712ba9013c8c5e56e2"}, "file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"}, From f75212642756c89206051caa0e5ea62bc4e6d4c8 Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Sun, 11 Dec 2022 23:22:35 +0000 Subject: [PATCH 126/631] Remove quack, ensure adapter is finch --- config/config.exs | 5 --- config/description.exs | 39 ------------------- docs/docs/configuration/cheatsheet.md | 9 ----- docs/docs/development/API/admin_api.md | 17 -------- lib/pleroma/config/deprecation_warnings.ex | 23 ++++++++++- lib/pleroma/config/transfer_task.ex | 8 +--- lib/pleroma/config_db.ex | 1 - mix.exs | 2 - test/fixtures/config/temp.secret.exs | 2 - test/mix/tasks/pleroma/config_test.exs | 8 ---- .../config/deprecation_warnings_test.exs | 8 ++++ test/pleroma/config/loader_test.exs | 1 - test/pleroma/config/transfer_task_test.exs | 24 ------------ test/pleroma/config_db_test.exs | 22 ----------- test/support/cluster.ex | 6 +-- 15 files changed, 34 insertions(+), 141 deletions(-) diff --git a/config/config.exs b/config/config.exs index bbf3d2072..a0176a72d 100644 --- a/config/config.exs +++ b/config/config.exs @@ -163,11 +163,6 @@ format: "$metadata[$level] $message", metadata: [:request_id] -config :quack, - level: :warn, - meta: [:all], - webhook_url: "https://hooks.slack.com/services/YOUR-KEY-HERE" - config :mime, :types, %{ "application/xml" => ["xml"], "application/xrd+xml" => ["xrd+xml"], diff --git a/config/description.exs b/config/description.exs index a6b7231d0..4d4306fba 100644 --- a/config/description.exs +++ b/config/description.exs @@ -1118,45 +1118,6 @@ } ] }, - %{ - group: :quack, - type: :group, - label: "Quack Logger", - description: "Quack-related settings", - children: [ - %{ - key: :level, - type: {:dropdown, :atom}, - description: "Log level", - suggestions: [:debug, :info, :warn, :error] - }, - %{ - key: :meta, - type: {:list, :atom}, - description: "Configure which metadata you want to report on", - suggestions: [ - :application, - :module, - :file, - :function, - :line, - :pid, - :crash_reason, - :initial_call, - :registered_name, - :all, - :none - ] - }, - %{ - key: :webhook_url, - label: "Webhook URL", - type: :string, - description: "Configure the Slack incoming webhook", - suggestions: ["https://hooks.slack.com/services/YOUR-KEY-HERE"] - } - ] - }, %{ group: :pleroma, key: :frontend_configurations, diff --git a/docs/docs/configuration/cheatsheet.md b/docs/docs/configuration/cheatsheet.md index b956d26e4..d81275043 100644 --- a/docs/docs/configuration/cheatsheet.md +++ b/docs/docs/configuration/cheatsheet.md @@ -785,17 +785,8 @@ config :logger, :ex_syslogger, level: :info, ident: "pleroma", format: "$metadata[$level] $message" - -config :quack, - level: :warn, - meta: [:all], - webhook_url: "https://hooks.slack.com/services/YOUR-API-KEY-HERE" ``` -See the [Quack Github](https://github.com/azohra/quack) for more details - - - ## Database options ### RUM indexing for full text search diff --git a/docs/docs/development/API/admin_api.md b/docs/docs/development/API/admin_api.md index 241e0b95c..211b5e736 100644 --- a/docs/docs/development/API/admin_api.md +++ b/docs/docs/development/API/admin_api.md @@ -1063,7 +1063,6 @@ List of settings which support only full update by key: ```elixir @full_key_update [ {:pleroma, :ecto_repos}, - {:quack, :meta}, {:mime, :types}, {:cors_plug, [:max_age, :methods, :expose, :headers]}, {:auto_linker, :opts}, @@ -1083,22 +1082,6 @@ List of settings which support only full update by subkey: ] ``` -*Settings without explicit key must be sended in separate config object params.* -```elixir -config :quack, - level: :debug, - meta: [:all], - ... -``` -```json -{ - "configs": [ - {"group": ":quack", "key": ":level", "value": ":debug"}, - {"group": ":quack", "key": ":meta", "value": [":all"]}, - ... - ] -} -``` - Request: ```json diff --git a/lib/pleroma/config/deprecation_warnings.ex b/lib/pleroma/config/deprecation_warnings.ex index c213f3ce6..33dc925bb 100644 --- a/lib/pleroma/config/deprecation_warnings.ex +++ b/lib/pleroma/config/deprecation_warnings.ex @@ -181,7 +181,8 @@ def warn do check_uploders_s3_public_endpoint(), check_quarantined_instances_tuples(), check_transparency_exclusions_tuples(), - check_simple_policy_tuples() + check_simple_policy_tuples(), + check_http_adapter() ] |> Enum.reduce(:ok, fn :ok, :ok -> :ok @@ -210,6 +211,26 @@ def check_welcome_message_config do end end + def check_http_adapter do + http_adapter = Application.get_env(:tesla, :adapter) + case http_adapter do + {Tesla.Adapter.Finch, _} -> + :ok + + _anything_else -> + Logger.error(""" + !!!CONFIG ERROR!!! + Your config is using a custom tesla adapter, this was standardised + to finch in 2022.06, and alternate adapters were removed in 2023.02. + Please ensure you either: + \n* do not have any custom value for `:tesla, :adapter`, or + \n* have `config :tesla, :adapter, {Tesla.Adapter.Finch, name: MyFinch}` + """) + + :error + end + end + def check_old_mrf_config do warning_preface = """ !!!DEPRECATION WARNING!!! diff --git a/lib/pleroma/config/transfer_task.ex b/lib/pleroma/config/transfer_task.ex index 81dc847cf..2e4bcb0ee 100644 --- a/lib/pleroma/config/transfer_task.ex +++ b/lib/pleroma/config/transfer_task.ex @@ -41,7 +41,7 @@ def load_and_update_env(deleted_settings \\ [], restart_pleroma? \\ true) do {logger, other} = (Repo.all(ConfigDB) ++ deleted_settings) |> Enum.map(&merge_with_default/1) - |> Enum.split_with(fn {group, _, _, _} -> group in [:logger, :quack] end) + |> Enum.split_with(fn {group, _, _, _} -> group == :logger end) logger |> Enum.sort() @@ -101,12 +101,6 @@ defp merge_with_default(%{group: group, key: key, value: value} = setting) do {group, key, value, merged} end - # change logger configuration in runtime, without restart - defp configure({:quack, key, _, merged}) do - Logger.configure_backend(Quack.Logger, [{key, merged}]) - :ok = update_env(:quack, key, merged) - end - defp configure({_, :backends, _, merged}) do # removing current backends Enum.each(Application.get_env(:logger, :backends), &Logger.remove_backend/1) diff --git a/lib/pleroma/config_db.ex b/lib/pleroma/config_db.ex index cb57673e3..77f2c4e2d 100644 --- a/lib/pleroma/config_db.ex +++ b/lib/pleroma/config_db.ex @@ -163,7 +163,6 @@ defp can_be_partially_updated?(%ConfigDB{} = config), do: not only_full_update?( defp only_full_update?(%ConfigDB{group: group, key: key}) do full_key_update = [ {:pleroma, :ecto_repos}, - {:quack, :meta}, {:mime, :types}, {:cors_plug, [:max_age, :methods, :expose, :headers]}, {:swarm, :node_blacklist}, diff --git a/mix.exs b/mix.exs index 64f96b29c..299d2ad01 100644 --- a/mix.exs +++ b/mix.exs @@ -76,7 +76,6 @@ def application do :logger, :runtime_tools, :comeonin, - :quack, :fast_sanitize, :os_mon, :ssl @@ -164,7 +163,6 @@ defp deps do {:telemetry, "~> 0.3"}, {:poolboy, "~> 1.5"}, {:recon, "~> 2.5"}, - {:quack, "~> 0.1.1"}, {:joken, "~> 2.0"}, {:benchee, "~> 1.0"}, {:pot, "~> 1.0"}, diff --git a/test/fixtures/config/temp.secret.exs b/test/fixtures/config/temp.secret.exs index 9c5c88d98..3a8673679 100644 --- a/test/fixtures/config/temp.secret.exs +++ b/test/fixtures/config/temp.secret.exs @@ -8,8 +8,6 @@ config :pleroma, :second_setting, key: "value2", key2: ["Activity"] -config :quack, level: :info - config :pleroma, Pleroma.Repo, pool: Ecto.Adapters.SQL.Sandbox config :postgrex, :json_library, Poison diff --git a/test/mix/tasks/pleroma/config_test.exs b/test/mix/tasks/pleroma/config_test.exs index d5e038bee..15ffe0ce6 100644 --- a/test/mix/tasks/pleroma/config_test.exs +++ b/test/mix/tasks/pleroma/config_test.exs @@ -49,7 +49,6 @@ test "error if file with custom settings doesn't exist" do describe "migrate_to_db/1" do setup do clear_config(:configurable_from_database, true) - clear_config([:quack, :level]) end @tag capture_log: true @@ -72,14 +71,12 @@ test "filtered settings are migrated to db" do config1 = ConfigDB.get_by_params(%{group: ":pleroma", key: ":first_setting"}) config2 = ConfigDB.get_by_params(%{group: ":pleroma", key: ":second_setting"}) - config3 = ConfigDB.get_by_params(%{group: ":quack", key: ":level"}) refute ConfigDB.get_by_params(%{group: ":pleroma", key: "Pleroma.Repo"}) refute ConfigDB.get_by_params(%{group: ":postgrex", key: ":json_library"}) refute ConfigDB.get_by_params(%{group: ":pleroma", key: ":database"}) assert config1.value == [key: "value", key2: [Repo]] assert config2.value == [key: "value2", key2: ["Activity"]] - assert config3.value == :info end test "config table is truncated before migration" do @@ -108,7 +105,6 @@ test "config table is truncated before migration" do test "settings are migrated to file and deleted from db", %{temp_file: temp_file} do insert_config_record(:pleroma, :setting_first, key: "value", key2: ["Activity"]) insert_config_record(:pleroma, :setting_second, key: "value2", key2: [Repo]) - insert_config_record(:quack, :level, :info) MixTask.run(["migrate_from_db", "--env", "temp", "-d"]) @@ -117,7 +113,6 @@ test "settings are migrated to file and deleted from db", %{temp_file: temp_file file = File.read!(temp_file) assert file =~ "config :pleroma, :setting_first," assert file =~ "config :pleroma, :setting_second," - assert file =~ "config :quack, :level, :info" end test "load a settings with large values and pass to file", %{temp_file: temp_file} do @@ -198,7 +193,6 @@ test "load a settings with large values and pass to file", %{temp_file: temp_fil setup do insert_config_record(:pleroma, :setting_first, key: "value", key2: ["Activity"]) insert_config_record(:pleroma, :setting_second, key: "value2", key2: [Repo]) - insert_config_record(:quack, :level, :info) path = "test/instance_static" file_path = Path.join(path, "temp.exported_from_db.secret.exs") @@ -214,7 +208,6 @@ test "with path parameter", %{file_path: file_path} do file = File.read!(file_path) assert file =~ "config :pleroma, :setting_first," assert file =~ "config :pleroma, :setting_second," - assert file =~ "config :quack, :level, :info" end test "release", %{file_path: file_path} do @@ -226,7 +219,6 @@ test "release", %{file_path: file_path} do file = File.read!(file_path) assert file =~ "config :pleroma, :setting_first," assert file =~ "config :pleroma, :setting_second," - assert file =~ "config :quack, :level, :info" end end diff --git a/test/pleroma/config/deprecation_warnings_test.exs b/test/pleroma/config/deprecation_warnings_test.exs index 053e28207..a56601896 100644 --- a/test/pleroma/config/deprecation_warnings_test.exs +++ b/test/pleroma/config/deprecation_warnings_test.exs @@ -279,4 +279,12 @@ test "check_uploders_s3_public_endpoint/0" do end) =~ "Your config is using the old setting for controlling the URL of media uploaded to your S3 bucket." end + + test "check_http_adapter/0" do + clear_config([:tesla, :adapter], Gun) + + assert capture_log(fn -> + DeprecationWarnings.check_http_adapter() + end) =~ "Your config is using a custom tesla adapter" + end end diff --git a/test/pleroma/config/loader_test.exs b/test/pleroma/config/loader_test.exs index b34fd70da..cef66748f 100644 --- a/test/pleroma/config/loader_test.exs +++ b/test/pleroma/config/loader_test.exs @@ -11,7 +11,6 @@ test "read/1" do config = Loader.read("test/fixtures/config/temp.secret.exs") assert config[:pleroma][:first_setting][:key] == "value" assert config[:pleroma][:first_setting][:key2] == [Pleroma.Repo] - assert config[:quack][:level] == :info end test "filter_group/2" do diff --git a/test/pleroma/config/transfer_task_test.exs b/test/pleroma/config/transfer_task_test.exs index 988214eb1..6491d10fb 100644 --- a/test/pleroma/config/transfer_task_test.exs +++ b/test/pleroma/config/transfer_task_test.exs @@ -17,14 +17,12 @@ defmodule Pleroma.Config.TransferTaskTest do test "transfer config values from db to env" do refute Application.get_env(:pleroma, :test_key) refute Application.get_env(:idna, :test_key) - refute Application.get_env(:quack, :test_key) refute Application.get_env(:postgrex, :test_key) initial = Application.get_env(:logger, :level) insert(:config, key: :test_key, value: [live: 2, com: 3]) insert(:config, group: :idna, key: :test_key, value: [live: 15, com: 35]) - insert(:config, group: :quack, key: :test_key, value: [:test_value1, :test_value2]) insert(:config, group: :postgrex, key: :test_key, value: :value) insert(:config, group: :logger, key: :level, value: :debug) insert(:config, group: :pleroma, key: :instance, value: [static_dir: "static_dir_from_db"]) @@ -32,7 +30,6 @@ test "transfer config values from db to env" do assert Application.get_env(:pleroma, :test_key) == [live: 2, com: 3] assert Application.get_env(:idna, :test_key) == [live: 15, com: 35] - assert Application.get_env(:quack, :test_key) == [:test_value1, :test_value2] assert Application.get_env(:logger, :level) == :debug assert Application.get_env(:postgrex, :test_key) == :value assert Application.get_env(:pleroma, :instance)[:static_dir] == "static_dir_from_db" @@ -40,7 +37,6 @@ test "transfer config values from db to env" do on_exit(fn -> Application.delete_env(:pleroma, :test_key) Application.delete_env(:idna, :test_key) - Application.delete_env(:quack, :test_key) Application.delete_env(:postgrex, :test_key) Application.put_env(:logger, :level, initial) System.delete_env("RELEASE_NAME") @@ -82,26 +78,6 @@ test "transfer task falls back to release defaults if no other values found" do end) end - test "transfer config values for 1 group and some keys" do - level = Application.get_env(:quack, :level) - meta = Application.get_env(:quack, :meta) - - insert(:config, group: :quack, key: :level, value: :info) - insert(:config, group: :quack, key: :meta, value: [:none]) - - TransferTask.start_link([]) - - assert Application.get_env(:quack, :level) == :info - assert Application.get_env(:quack, :meta) == [:none] - default = Pleroma.Config.Holder.default_config(:quack, :webhook_url) - assert Application.get_env(:quack, :webhook_url) == default - - on_exit(fn -> - Application.put_env(:quack, :level, level) - Application.put_env(:quack, :meta, meta) - end) - end - test "transfer config values with full subkey update" do clear_config(:emoji) clear_config(:assets) diff --git a/test/pleroma/config_db_test.exs b/test/pleroma/config_db_test.exs index d42123fb4..e68346ce4 100644 --- a/test/pleroma/config_db_test.exs +++ b/test/pleroma/config_db_test.exs @@ -14,28 +14,6 @@ test "get_by_params/1" do assert config == ConfigDB.get_by_params(%{group: config.group, key: config.key}) end - test "get_all_as_keyword/0" do - saved = insert(:config) - insert(:config, group: ":quack", key: ":level", value: :info) - insert(:config, group: ":quack", key: ":meta", value: [:none]) - - insert(:config, - group: ":quack", - key: ":webhook_url", - value: "https://hooks.slack.com/services/KEY/some_val" - ) - - config = ConfigDB.get_all_as_keyword() - - assert config[:pleroma] == [ - {saved.key, saved.value} - ] - - assert config[:quack][:level] == :info - assert config[:quack][:meta] == [:none] - assert config[:quack][:webhook_url] == "https://hooks.slack.com/services/KEY/some_val" - end - describe "update_or_create/1" do test "common" do config = insert(:config) diff --git a/test/support/cluster.ex b/test/support/cluster.ex index 524194cf4..7e41631c5 100644 --- a/test/support/cluster.ex +++ b/test/support/cluster.ex @@ -96,7 +96,7 @@ def spawn_cluster(node_configs) do silence_logger_warnings(fn -> node_configs - |> Enum.map(&Task.async(fn -> start_slave(&1) end)) + |> Enum.map(&Task.async(fn -> start_peer(&1) end)) |> Enum.map(&Task.await(&1, 90_000)) end) end @@ -121,9 +121,9 @@ def eval_quoted(block, binding) do result end - defp start_slave({node_host, override_configs}) do + defp start_peer({node_host, override_configs}) do log(node_host, "booting federated VM") - {:ok, node} = :slave.start(~c"127.0.0.1", node_name(node_host), vm_args()) + {:ok, node} = :peer.start(%{host: ~c"127.0.0.1", name: node_name(node_host), args: vm_args()}) add_code_paths(node) load_apps_and_transfer_configuration(node, override_configs) ensure_apps_started(node) From 503827a3d9ed6c63f6d26db662c3f270512b720c Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Sun, 11 Dec 2022 23:33:58 +0000 Subject: [PATCH 127/631] Allow mock in http adapter checking --- lib/pleroma/config/deprecation_warnings.ex | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/pleroma/config/deprecation_warnings.ex b/lib/pleroma/config/deprecation_warnings.ex index 33dc925bb..972d1fb96 100644 --- a/lib/pleroma/config/deprecation_warnings.ex +++ b/lib/pleroma/config/deprecation_warnings.ex @@ -217,6 +217,10 @@ def check_http_adapter do {Tesla.Adapter.Finch, _} -> :ok + Tesla.Mock -> + # tests do be testing + :ok + _anything_else -> Logger.error(""" !!!CONFIG ERROR!!! @@ -225,6 +229,7 @@ def check_http_adapter do Please ensure you either: \n* do not have any custom value for `:tesla, :adapter`, or \n* have `config :tesla, :adapter, {Tesla.Adapter.Finch, name: MyFinch}` + (your current value is #{inspect(http_adapter)}) """) :error From 9c7178286116d61a565fcba61ec64b20fec3a28a Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Sun, 11 Dec 2022 23:50:31 +0000 Subject: [PATCH 128/631] Test removed HTTP adapter --- docs/docs/development/API/admin_api.md | 2 +- lib/pleroma/config/deprecation_warnings.ex | 1 + .../20221211234352_remove_unused_indices.exs | 11 +++++++++++ test/pleroma/config/deprecation_warnings_test.exs | 4 +++- 4 files changed, 16 insertions(+), 2 deletions(-) create mode 100644 priv/repo/migrations/20221211234352_remove_unused_indices.exs diff --git a/docs/docs/development/API/admin_api.md b/docs/docs/development/API/admin_api.md index 211b5e736..79cb573ac 100644 --- a/docs/docs/development/API/admin_api.md +++ b/docs/docs/development/API/admin_api.md @@ -1056,7 +1056,7 @@ Most of the settings will be applied in `runtime`, this means that you don't nee Example of setting without keyword in value: ```elixir -config :tesla, :adapter, Tesla.Adapter.Hackney +config :tesla, :adapter, {Tesla.Adapter.Finch, name: MyFinch} ``` List of settings which support only full update by key: diff --git a/lib/pleroma/config/deprecation_warnings.ex b/lib/pleroma/config/deprecation_warnings.ex index 972d1fb96..076b4cbf0 100644 --- a/lib/pleroma/config/deprecation_warnings.ex +++ b/lib/pleroma/config/deprecation_warnings.ex @@ -213,6 +213,7 @@ def check_welcome_message_config do def check_http_adapter do http_adapter = Application.get_env(:tesla, :adapter) + case http_adapter do {Tesla.Adapter.Finch, _} -> :ok diff --git a/priv/repo/migrations/20221211234352_remove_unused_indices.exs b/priv/repo/migrations/20221211234352_remove_unused_indices.exs new file mode 100644 index 000000000..facc85a26 --- /dev/null +++ b/priv/repo/migrations/20221211234352_remove_unused_indices.exs @@ -0,0 +1,11 @@ +defmodule Pleroma.Repo.Migrations.RemoveUnusedIndices do + use Ecto.Migration + + def change do + drop_if_exists( + index(:activities, ["(data->>'actor')", "inserted_at desc"], name: :activities_actor_index) + ) + + drop_if_exists(index(:objects, ["(data->'tag')"], using: :gin, name: :objects_tags)) + end +end diff --git a/test/pleroma/config/deprecation_warnings_test.exs b/test/pleroma/config/deprecation_warnings_test.exs index a56601896..b18267a7f 100644 --- a/test/pleroma/config/deprecation_warnings_test.exs +++ b/test/pleroma/config/deprecation_warnings_test.exs @@ -281,10 +281,12 @@ test "check_uploders_s3_public_endpoint/0" do end test "check_http_adapter/0" do - clear_config([:tesla, :adapter], Gun) + Application.put_env(:tesla, :adapter, Gun) assert capture_log(fn -> DeprecationWarnings.check_http_adapter() end) =~ "Your config is using a custom tesla adapter" + + Application.put_env(:tesla, :adapter, Tesla.Mock) end end From 46c270ead83de020bedad95c4e40004fae45cd28 Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Mon, 12 Dec 2022 02:34:13 +0000 Subject: [PATCH 129/631] Add `mail` to make the gmail adapter in swoosh work --- mix.exs | 2 ++ mix.lock | 1 + 2 files changed, 3 insertions(+) diff --git a/mix.exs b/mix.exs index 299d2ad01..dbfa6263f 100644 --- a/mix.exs +++ b/mix.exs @@ -151,6 +151,8 @@ defp deps do {:cors_plug, "~> 2.0"}, {:web_push_encryption, "~> 0.3.1"}, {:swoosh, "~> 1.0"}, + # for gmail adapter in swoosh + {:mail, ">= 0.0.0"}, {:phoenix_swoosh, "~> 0.3"}, {:gen_smtp, "~> 0.13"}, {:ex_syslogger, "~> 1.4"}, diff --git a/mix.lock b/mix.lock index 605b0235f..e86a58427 100644 --- a/mix.lock +++ b/mix.lock @@ -60,6 +60,7 @@ "jose": {:hex, :jose, "1.11.2", "f4c018ccf4fdce22c71e44d471f15f723cb3efab5d909ab2ba202b5bf35557b3", [:mix, :rebar3], [], "hexpm", "98143fbc48d55f3a18daba82d34fe48959d44538e9697c08f34200fa5f0947d2"}, "jumper": {:hex, :jumper, "1.0.1", "3c00542ef1a83532b72269fab9f0f0c82bf23a35e27d278bfd9ed0865cecabff", [:mix], [], "hexpm", "318c59078ac220e966d27af3646026db9b5a5e6703cb2aa3e26bcfaba65b7433"}, "linkify": {:git, "https://akkoma.dev/AkkomaGang/linkify.git", "2567e2c1073fa371fd26fd66dfa5bc77b6919c16", [branch: "bugfix/line-ending-buffer"]}, + "mail": {:hex, :mail, "0.2.3", "2c6bb5f8a5f74845fa50ecd0fb45ea16b164026f285f45104f1c4c078cd616d4", [:mix], [], "hexpm", "932b398fa9c69fdf290d7ff63175826e0f1e24414d5b0763bb00a2acfc6c6bf5"}, "majic": {:hex, :majic, "1.0.0", "37e50648db5f5c2ff0c9fb46454d034d11596c03683807b9fb3850676ffdaab3", [:make, :mix], [{:elixir_make, "~> 0.6.1", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.2", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "7905858f76650d49695f14ea55cd9aaaee0c6654fa391671d4cf305c275a0a9e"}, "makeup": {:hex, :makeup, "1.1.0", "6b67c8bc2882a6b6a445859952a602afc1a41c2e08379ca057c0f525366fc3ca", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "0a45ed501f4a8897f580eabf99a2e5234ea3e75a4373c8a52824f6e873be57a6"}, "makeup_elixir": {:hex, :makeup_elixir, "0.16.0", "f8c570a0d33f8039513fbccaf7108c5d750f47d8defd44088371191b76492b0b", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "28b2cbdc13960a46ae9a8858c4bebdec3c9a6d7b4b9e7f4ed1502f8159f338e7"}, From df5b3a48dd43e196b3b48377a1af323a9285b47e Mon Sep 17 00:00:00 2001 From: floatingghost Date: Mon, 12 Dec 2022 04:26:24 +0000 Subject: [PATCH 130/631] Update '.gitea/issue_template/bug.yml' --- .gitea/issue_template/bug.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitea/issue_template/bug.yml b/.gitea/issue_template/bug.yml index 6ed1fa1ae..d14f429cd 100644 --- a/.gitea/issue_template/bug.yml +++ b/.gitea/issue_template/bug.yml @@ -1,6 +1,8 @@ name: "Bug report" about: "Something isn't working as expected" title: "[bug] " +labels: +- bug body: - type: markdown attributes: From fd2f03f80a88978048f6ff7d8ede1906c2b078dd Mon Sep 17 00:00:00 2001 From: floatingghost Date: Mon, 12 Dec 2022 04:26:43 +0000 Subject: [PATCH 131/631] Update '.gitea/issue_template/feat.yml' --- .gitea/issue_template/feat.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitea/issue_template/feat.yml b/.gitea/issue_template/feat.yml index fc1adbbc2..260f77ab4 100644 --- a/.gitea/issue_template/feat.yml +++ b/.gitea/issue_template/feat.yml @@ -1,6 +1,9 @@ name: "Feature request" about: "I'd like something to be added to Akkoma" title: "[feat] " +labels: +- "feature request" + body: - type: markdown attributes: From 77e9a52450d897f39a28276694ac175955232d0e Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Mon, 12 Dec 2022 19:06:04 +0000 Subject: [PATCH 132/631] allow http AS profile in ld+json header --- lib/pleroma/object/fetcher.ex | 7 ++- test/pleroma/object/fetcher_test.exs | 71 ++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+), 1 deletion(-) diff --git a/lib/pleroma/object/fetcher.ex b/lib/pleroma/object/fetcher.ex index 8309ef64a..aeaf05986 100644 --- a/lib/pleroma/object/fetcher.ex +++ b/lib/pleroma/object/fetcher.ex @@ -262,7 +262,7 @@ def fetch_and_contain_remote_object_from_id(id) when is_binary(id) do def fetch_and_contain_remote_object_from_id(_id), do: {:error, "id must be a string"} - defp get_object(id) do + def get_object(id) do date = Pleroma.Signature.signed_date() headers = @@ -282,6 +282,11 @@ defp get_object(id) do %{"profile" => "https://www.w3.org/ns/activitystreams"}} -> {:ok, body} + # pixelfed sometimes (and only sometimes) responds with http instead of https + {:ok, "application", "ld+json", + %{"profile" => "http://www.w3.org/ns/activitystreams"}} -> + {:ok, body} + _ -> {:error, {:content_type, content_type}} end diff --git a/test/pleroma/object/fetcher_test.exs b/test/pleroma/object/fetcher_test.exs index c76a09fd7..e26443a81 100644 --- a/test/pleroma/object/fetcher_test.exs +++ b/test/pleroma/object/fetcher_test.exs @@ -572,4 +572,75 @@ test "it gets history", %{object2: object2} do } = object.data end end + + describe "get_object/1" do + test "should return ok if the content type is application/activity+json" do + Tesla.Mock.mock(fn + %{ + method: :get, + url: "https://mastodon.social/2" + } -> + %Tesla.Env{ + status: 200, + headers: [{"content-type", "application/activity+json"}], + body: "{}" + } + end) + + assert {:ok, "{}"} = Fetcher.get_object("https://mastodon.social/2") + end + + test "should return ok if the content type is application/ld+json with a profile" do + Tesla.Mock.mock(fn + %{ + method: :get, + url: "https://mastodon.social/2" + } -> + %Tesla.Env{ + status: 200, + headers: [ + {"content-type", + "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\""} + ], + body: "{}" + } + end) + + assert {:ok, "{}"} = Fetcher.get_object("https://mastodon.social/2") + + Tesla.Mock.mock(fn + %{ + method: :get, + url: "https://mastodon.social/2" + } -> + %Tesla.Env{ + status: 200, + headers: [ + {"content-type", + "application/ld+json; profile=\"http://www.w3.org/ns/activitystreams\""} + ], + body: "{}" + } + end) + + assert {:ok, "{}"} = Fetcher.get_object("https://mastodon.social/2") + end + + test "should not return ok with other content types" do + Tesla.Mock.mock(fn + %{ + method: :get, + url: "https://mastodon.social/2" + } -> + %Tesla.Env{ + status: 200, + headers: [{"content-type", "application/json"}], + body: "{}" + } + end) + + assert {:error, {:content_type, "application/json"}} = + Fetcher.get_object("https://mastodon.social/2") + end + end end From c9304962c3a91f7e38e3d519637b5617a2df4e30 Mon Sep 17 00:00:00 2001 From: duponin Date: Sun, 11 Dec 2022 22:54:47 +0100 Subject: [PATCH 133/631] Uploading an avatar media exceeding max size returns a 413 Until now it was returning a 500 because the upload plug were going through the changeset and ending in the JSON encoder, which raised because struct has to @derive the encoder. --- lib/pleroma/user.ex | 8 +++++- .../api_spec/operations/account_operation.ex | 3 +- .../controllers/account_controller.ex | 6 +++- .../mastodon_api/update_credentials_test.exs | 28 +++++++++++++++++++ 4 files changed, 42 insertions(+), 3 deletions(-) diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index e32dd161e..ba30769bb 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -599,7 +599,13 @@ defp put_change_if_present(changeset, map_field, value_function) do {:ok, new_value} <- value_function.(value) do put_change(changeset, map_field, new_value) else - _ -> changeset + {:error, :file_too_large} -> + Ecto.Changeset.validate_change(changeset, map_field, fn map_field, _value -> + [{map_field, "file is too large"}] + end) + + _ -> + changeset end end diff --git a/lib/pleroma/web/api_spec/operations/account_operation.ex b/lib/pleroma/web/api_spec/operations/account_operation.ex index e20f57fec..a89f9570e 100644 --- a/lib/pleroma/web/api_spec/operations/account_operation.ex +++ b/lib/pleroma/web/api_spec/operations/account_operation.ex @@ -64,7 +64,8 @@ def update_credentials_operation do requestBody: request_body("Parameters", update_credentials_request(), required: true), responses: %{ 200 => Operation.response("Account", "application/json", Account), - 403 => Operation.response("Error", "application/json", ApiError) + 403 => Operation.response("Error", "application/json", ApiError), + 413 => Operation.response("Error", "application/json", ApiError) } } end diff --git a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex index a3648c458..0ec805357 100644 --- a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex @@ -251,7 +251,11 @@ def update_credentials(%{assigns: %{user: user}, body_params: params} = conn, _p with_pleroma_settings: true ) else - _e -> render_error(conn, :forbidden, "Invalid request") + {:error, %Ecto.Changeset{errors: [avatar: {"file is too large", _}]}} -> + render_error(conn, :request_entity_too_large, "File is too large") + + _e -> + render_error(conn, :forbidden, "Invalid request") end end diff --git a/test/pleroma/web/mastodon_api/update_credentials_test.exs b/test/pleroma/web/mastodon_api/update_credentials_test.exs index a5403f360..98fd0ae59 100644 --- a/test/pleroma/web/mastodon_api/update_credentials_test.exs +++ b/test/pleroma/web/mastodon_api/update_credentials_test.exs @@ -272,6 +272,34 @@ test "updates the user's avatar", %{user: user, conn: conn} do assert user.avatar == nil end + test "updates the user's avatar, upload_limit, returns a HTTP 413", %{conn: conn, user: user} do + upload_limit = Config.get([:instance, :upload_limit]) * 8 + 8 + + assert :ok == + File.write(Path.absname("test/tmp/large_binary.data"), <<0::size(upload_limit)>>) + + new_avatar_oversized = %Plug.Upload{ + content_type: nil, + path: Path.absname("test/tmp/large_binary.data"), + filename: "large_binary.data" + } + + assert user.avatar == %{} + + res = + patch(conn, "/api/v1/accounts/update_credentials", %{"avatar" => new_avatar_oversized}) + + assert user_response = json_response_and_validate_schema(res, 413) + assert user_response["avatar"] != User.avatar_url(user) + + user = User.get_by_id(user.id) + assert user.avatar == %{} + + clear_config([:instance, :upload_limit], upload_limit) + + assert :ok == File.rm(Path.absname("test/tmp/large_binary.data")) + end + test "updates the user's banner", %{user: user, conn: conn} do new_header = %Plug.Upload{ content_type: "image/jpeg", From 3e9c0b380a02011770ee28a6938f5bbec05cc093 Mon Sep 17 00:00:00 2001 From: duponin Date: Sun, 11 Dec 2022 23:15:08 +0100 Subject: [PATCH 134/631] Return 413 when an actor's banner or background exceeds the size limit --- .../controllers/account_controller.ex | 6 +++ .../mastodon_api/update_credentials_test.exs | 54 +++++++++++++++++++ 2 files changed, 60 insertions(+) diff --git a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex index 0ec805357..5afbcd0dd 100644 --- a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex @@ -254,6 +254,12 @@ def update_credentials(%{assigns: %{user: user}, body_params: params} = conn, _p {:error, %Ecto.Changeset{errors: [avatar: {"file is too large", _}]}} -> render_error(conn, :request_entity_too_large, "File is too large") + {:error, %Ecto.Changeset{errors: [banner: {"file is too large", _}]}} -> + render_error(conn, :request_entity_too_large, "File is too large") + + {:error, %Ecto.Changeset{errors: [background: {"file is too large", _}]}} -> + render_error(conn, :request_entity_too_large, "File is too large") + _e -> render_error(conn, :forbidden, "Invalid request") end diff --git a/test/pleroma/web/mastodon_api/update_credentials_test.exs b/test/pleroma/web/mastodon_api/update_credentials_test.exs index 98fd0ae59..130cbe8d1 100644 --- a/test/pleroma/web/mastodon_api/update_credentials_test.exs +++ b/test/pleroma/web/mastodon_api/update_credentials_test.exs @@ -319,6 +319,32 @@ test "updates the user's banner", %{user: user, conn: conn} do assert user.banner == nil end + test "updates the user's banner, upload_limit, returns a HTTP 413", %{conn: conn, user: user} do + upload_limit = Config.get([:instance, :upload_limit]) * 8 + 8 + + assert :ok == + File.write(Path.absname("test/tmp/large_binary.data"), <<0::size(upload_limit)>>) + + new_header_oversized = %Plug.Upload{ + content_type: nil, + path: Path.absname("test/tmp/large_binary.data"), + filename: "large_binary.data" + } + + res = + patch(conn, "/api/v1/accounts/update_credentials", %{"header" => new_header_oversized}) + + assert user_response = json_response_and_validate_schema(res, 413) + assert user_response["header"] != User.banner_url(user) + + user = User.get_by_id(user.id) + assert user.banner == %{} + + clear_config([:instance, :upload_limit], upload_limit) + + assert :ok == File.rm(Path.absname("test/tmp/large_binary.data")) + end + test "updates the user's background", %{conn: conn, user: user} do new_header = %Plug.Upload{ content_type: "image/jpeg", @@ -342,6 +368,34 @@ test "updates the user's background", %{conn: conn, user: user} do assert user.background == nil end + test "updates the user's background, upload_limit, returns a HTTP 413", %{ + conn: conn, + user: user + } do + upload_limit = Config.get([:instance, :upload_limit]) * 8 + 8 + + assert :ok == + File.write(Path.absname("test/tmp/large_binary.data"), <<0::size(upload_limit)>>) + + new_background_oversized = %Plug.Upload{ + content_type: nil, + path: Path.absname("test/tmp/large_binary.data"), + filename: "large_binary.data" + } + + res = + patch(conn, "/api/v1/accounts/update_credentials", %{ + "pleroma_background_image" => new_background_oversized + }) + + assert user_response = json_response_and_validate_schema(res, 413) + assert user.background == %{} + + clear_config([:instance, :upload_limit], upload_limit) + + assert :ok == File.rm(Path.absname("test/tmp/large_binary.data")) + end + test "requires 'write:accounts' permission" do token1 = insert(:oauth_token, scopes: ["read"]) token2 = insert(:oauth_token, scopes: ["write", "follow"]) From 8104f460310d371e45835746675debc7fce0f835 Mon Sep 17 00:00:00 2001 From: Norm Date: Sun, 11 Dec 2022 22:57:43 +0000 Subject: [PATCH 135/631] Update 'CHANGELOG.md' --- CHANGELOG.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f1dd50ddc..103b060e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,11 +6,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## Unreleased -## Removed +### Removed - Non-finch HTTP adapters - -## Upgrade notes +### Upgrade notes - Ensure `config :tesla, :adapter` is either unset, or set to `{Tesla.Adapter.Finch, name: MyFinch}` in your .exs config +### Changed +- Return HTTP error 413 when uploading an avatar or banner that's above the configured upload limit instead of a 500. ## 2022.12 From 53f21489a2f9737dc2a7f55417f9d9901f750107 Mon Sep 17 00:00:00 2001 From: Norm Date: Wed, 14 Dec 2022 03:03:08 +0000 Subject: [PATCH 136/631] Update the "Updating your instance" docs (#361) This makes them consistent with the update instructions that are in the release announcements. Also adds in the command to update the frontend as well. Co-authored-by: Francis Dinh Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma/pulls/361 Co-authored-by: Norm Co-committed-by: Norm --- docs/docs/administration/updating.md | 60 ++++++++++++++++++++++------ 1 file changed, 47 insertions(+), 13 deletions(-) diff --git a/docs/docs/administration/updating.md b/docs/docs/administration/updating.md index 2d9e77075..52979a1f5 100644 --- a/docs/docs/administration/updating.md +++ b/docs/docs/administration/updating.md @@ -3,15 +3,34 @@ You should **always check the [release notes/changelog](https://akkoma.dev/AkkomaGang/akkoma/src/branch/develop/CHANGELOG.md)** in case there are config deprecations, special update steps, etc. Besides that, doing the following is generally enough: +## Switch to the akkoma user +```sh +# Using sudo +sudo -su akkoma + +# Using doas +doas -su akkoma + +# Using su +su -s "$SHELL" akkoma +``` ## For OTP installations - ```sh -# Download the new release -su akkoma -s $SHELL -lc "./bin/pleroma_ctl update" +# Download latest stable release +./bin/pleroma_ctl update --branch stable -# Migrate the database, you are advised to stop the instance before doing that -su akkoma -s $SHELL -lc "./bin/pleroma_ctl migrate" +# Stop akkoma +./bin/pleroma stop # or using the system service manager (e.g. systemctl stop akkoma) + +# Run database migrations +./bin/pleroma_ctl migrate + +# Update frontend(s). See Frontend Configuration doc for more information. +./bin/pleroma_ctl frontend install pleroma-fe --ref stable + +# Start akkoma +./bin/pleroma daemon # or using the system service manager (e.g. systemctl start akkoma) ``` If you selected an alternate flavour on installation, @@ -19,13 +38,28 @@ you _may_ need to specify `--flavour`, in the same way as [when installing](../../installation/otp_en#detecting-flavour). ## For from source installations (using git) +Run as the `akkoma` user: -1. Go to the working directory of Akkoma (default is `/opt/akkoma`) -2. Run `git pull` [^1]. This pulls the latest changes from upstream. -3. Run `mix deps.get` [^1]. This pulls in any new dependencies. -4. Stop the Akkoma service. -5. Run `mix ecto.migrate` [^1] [^2]. This task performs database migrations, if there were any. -6. Start the Akkoma service. +```sh +# Pull in new changes +git pull -[^1]: Depending on which install guide you followed (for example on Debian/Ubuntu), you want to run `git` and `mix` tasks as `akkoma` user by adding `sudo -Hu akkoma` before the command. -[^2]: Prefix with `MIX_ENV=prod` to run it using the production config file. +# Run with production configuration +export MIX_ENV=prod + +# Download and compile dependencies +mix deps.get +mix compile + +# Stop akkoma (replace with your system service manager's equivalent if different) +sudo systemctl stop akkoma + +# Run database migrations +mix ecto.migrate + +# Update frontend(s). See Frontend Configration doc for more information. +mix pleroma.frontend install pleroma-fe --ref stable + +# Start akkoma (replace with your system service manager's equivalent if different) +sudo systemctl start akkoma +``` From 07a48b9293e4046c50b5d424d60a1bf16c7cc198 Mon Sep 17 00:00:00 2001 From: floatingghost Date: Wed, 14 Dec 2022 12:38:48 +0000 Subject: [PATCH 137/631] giant massive dep upgrade and dialyxir-found error emporium (#371) Co-authored-by: FloatingGhost Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma/pulls/371 --- CHANGELOG.md | 7 +- lib/mix/tasks/pleroma/activity.ex | 1 + lib/mix/tasks/pleroma/database.ex | 1 - lib/mix/tasks/pleroma/diagnostics.ex | 1 + lib/mix/tasks/pleroma/instance.ex | 12 +- lib/mix/tasks/pleroma/search.ex | 11 +- lib/mix/tasks/pleroma/user.ex | 11 +- lib/pleroma/activity/html.ex | 6 +- .../akkoma/{translators => }/translator.ex | 0 lib/pleroma/announcement.ex | 4 +- lib/pleroma/application.ex | 3 + lib/pleroma/application_requirements.ex | 2 - lib/pleroma/emoji/pack.ex | 8 +- lib/pleroma/following_relationship.ex | 10 +- lib/pleroma/helpers/media_helper.ex | 6 +- lib/pleroma/http/adapter_helper.ex | 8 +- .../migrators/support/base_migrator.ex | 2 +- lib/pleroma/moderation_log.ex | 3 +- lib/pleroma/object.ex | 4 +- lib/pleroma/release_tasks.ex | 3 - lib/pleroma/reverse_proxy/client/tesla.ex | 1 + lib/pleroma/search/elasticsearch.ex | 30 ++-- .../document_mappings/activity.ex | 2 +- lib/pleroma/search/meilisearch.ex | 5 +- lib/pleroma/search/search_backend.ex | 4 +- lib/pleroma/signature.ex | 2 +- lib/pleroma/upload.ex | 2 +- lib/pleroma/upload/filter/analyze_metadata.ex | 1 - lib/pleroma/upload/filter/exiftool.ex | 2 +- lib/pleroma/upload/filter/mogrifun.ex | 2 +- lib/pleroma/user.ex | 37 ++++- lib/pleroma/user/backup.ex | 3 +- lib/pleroma/web.ex | 5 +- lib/pleroma/web/activity_pub/activity_pub.ex | 5 + .../controllers/translation_controller.ex | 10 +- .../pleroma_emoji_pack_operation.ex | 13 +- lib/pleroma/web/auth/pleroma_authenticator.ex | 4 + lib/pleroma/web/controller_helper.ex | 14 +- lib/pleroma/web/endpoint.ex | 2 +- .../legacy_pleroma_api_rerouter_plug.ex | 26 ---- lib/pleroma/web/metadata/utils.ex | 4 + lib/pleroma/web/o_auth/o_auth_controller.ex | 3 +- lib/pleroma/web/plugs/parsers/multipart.ex | 21 +++ lib/pleroma/web/plugs/remote_ip.ex | 26 ++-- lib/pleroma/web/router.ex | 2 - .../controllers/util_controller.ex | 5 +- lib/pleroma/web/web_finger.ex | 1 + .../web/web_finger/web_finger_controller.ex | 2 +- mix.exs | 49 +++---- mix.lock | 21 +-- test/credo/check/consistency/file_location.ex | 4 + test/pleroma/signature_test.exs | 2 +- .../controllers/admin_api_controller_test.exs | 111 +++++++------- .../controllers/frontend_controller_test.exs | 18 +-- .../controllers/instance_controller_test.exs | 14 +- .../instance_document_controller_test.exs | 20 +-- .../controllers/invite_controller_test.exs | 36 ++--- .../media_proxy_cache_controller_test.exs | 20 +-- .../o_auth_app_controller_test.exs | 32 ++-- .../controllers/relay_controller_test.exs | 8 +- .../controllers/report_controller_test.exs | 40 ++--- .../controllers/status_controller_test.exs | 34 ++--- .../controllers/user_controller_test.exs | 110 +++++++------- test/pleroma/web/fallback_test.exs | 6 - .../controllers/status_controller_test.exs | 24 +-- .../controllers/timeline_controller_test.exs | 14 +- .../mastodon_api/update_credentials_test.exs | 32 ++-- .../controllers/account_controller_test.exs | 2 +- .../emoji_file_controller_test.exs | 42 +++--- .../emoji_pack_controller_test.exs | 138 ++++++++++-------- ..._factor_authentication_controller_test.exs | 25 +++- test/pleroma/web/plugs/remote_ip_test.exs | 60 +++++--- .../twitter_api/password_controller_test.exs | 16 +- .../web/twitter_api/util_controller_test.exs | 23 +-- test/support/cluster.ex | 5 +- 75 files changed, 688 insertions(+), 555 deletions(-) rename lib/pleroma/akkoma/{translators => }/translator.ex (100%) delete mode 100644 lib/pleroma/web/fallback/legacy_pleroma_api_rerouter_plug.ex create mode 100644 lib/pleroma/web/plugs/parsers/multipart.ex diff --git a/CHANGELOG.md b/CHANGELOG.md index 103b060e1..0ec7e29b3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,11 +8,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ### Removed - Non-finch HTTP adapters -### Upgrade notes -- Ensure `config :tesla, :adapter` is either unset, or set to `{Tesla.Adapter.Finch, name: MyFinch}` in your .exs config +- Legacy redirect from /api/pleroma/admin to /api/v1/pleroma/admin + ### Changed - Return HTTP error 413 when uploading an avatar or banner that's above the configured upload limit instead of a 500. +### Upgrade notes +- Ensure `config :tesla, :adapter` is either unset, or set to `{Tesla.Adapter.Finch, name: MyFinch}` in your .exs config + ## 2022.12 ## Added diff --git a/lib/mix/tasks/pleroma/activity.ex b/lib/mix/tasks/pleroma/activity.ex index 3a79d8f20..84b9c16f9 100644 --- a/lib/mix/tasks/pleroma/activity.ex +++ b/lib/mix/tasks/pleroma/activity.ex @@ -1,3 +1,4 @@ +# credo:disable-for-this-file # Pleroma: A lightweight social networking server # Copyright © 2017-2018 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only diff --git a/lib/mix/tasks/pleroma/database.ex b/lib/mix/tasks/pleroma/database.ex index 0881974ee..272c9e3e5 100644 --- a/lib/mix/tasks/pleroma/database.ex +++ b/lib/mix/tasks/pleroma/database.ex @@ -115,7 +115,6 @@ def run(["prune_task"]) do nil |> Pleroma.Workers.Cron.PruneDatabaseWorker.perform() - |> IO.inspect() end def run(["fix_likes_collections"]) do diff --git a/lib/mix/tasks/pleroma/diagnostics.ex b/lib/mix/tasks/pleroma/diagnostics.ex index b8d8167bb..3914540ca 100644 --- a/lib/mix/tasks/pleroma/diagnostics.ex +++ b/lib/mix/tasks/pleroma/diagnostics.ex @@ -1,3 +1,4 @@ +# credo:disable-for-this-file defmodule Mix.Tasks.Pleroma.Diagnostics do alias Pleroma.Repo alias Pleroma.User diff --git a/lib/mix/tasks/pleroma/instance.ex b/lib/mix/tasks/pleroma/instance.ex index 0647c330f..52fd184b5 100644 --- a/lib/mix/tasks/pleroma/instance.ex +++ b/lib/mix/tasks/pleroma/instance.ex @@ -247,9 +247,13 @@ def run(["gen" | rest]) do config_dir = Path.dirname(config_path) psql_dir = Path.dirname(psql_path) - [config_dir, psql_dir, static_dir, uploads_dir] - |> Enum.reject(&File.exists?/1) - |> Enum.map(&File.mkdir_p!/1) + to_create = + [config_dir, psql_dir, static_dir, uploads_dir] + |> Enum.reject(&File.exists?/1) + + for dir <- to_create do + File.mkdir_p!(dir) + end shell_info("Writing config to #{config_path}.") @@ -319,6 +323,4 @@ defp upload_filters(filters) when is_map(filters) do enabled_filters end - - defp upload_filters(_), do: [] end diff --git a/lib/mix/tasks/pleroma/search.ex b/lib/mix/tasks/pleroma/search.ex index 67aba79db..102bc5b63 100644 --- a/lib/mix/tasks/pleroma/search.ex +++ b/lib/mix/tasks/pleroma/search.ex @@ -10,14 +10,11 @@ defmodule Mix.Tasks.Pleroma.Search do def run(["import", "activities" | _rest]) do start_pleroma() - IO.inspect(Pleroma.Config.get([Pleroma.Search.Elasticsearch.Cluster, :indexes, :activities])) - IO.inspect( - Elasticsearch.Index.Bulk.upload( - Pleroma.Search.Elasticsearch.Cluster, - "activities", - Pleroma.Config.get([Pleroma.Search.Elasticsearch.Cluster, :indexes, :activities]) - ) + Elasticsearch.Index.Bulk.upload( + Pleroma.Search.Elasticsearch.Cluster, + "activities", + Pleroma.Config.get([Pleroma.Search.Elasticsearch.Cluster, :indexes, :activities]) ) end end diff --git a/lib/mix/tasks/pleroma/user.ex b/lib/mix/tasks/pleroma/user.ex index dd1cdca5b..4ca1c28eb 100644 --- a/lib/mix/tasks/pleroma/user.ex +++ b/lib/mix/tasks/pleroma/user.ex @@ -378,9 +378,11 @@ def run(["change_email", nickname, email]) do def run(["show", nickname]) do start_pleroma() - nickname - |> User.get_cached_by_nickname() - |> IO.inspect() + user = + nickname + |> User.get_cached_by_nickname() + + shell_info("#{inspect(user)}") end def run(["send_confirmation", nickname]) do @@ -389,7 +391,6 @@ def run(["send_confirmation", nickname]) do with %User{} = user <- User.get_cached_by_nickname(nickname) do user |> Pleroma.Emails.UserEmail.account_confirmation_email() - |> IO.inspect() |> Pleroma.Emails.Mailer.deliver!() shell_info("#{nickname}'s email sent") @@ -465,7 +466,7 @@ def run(["blocking", nickname]) do with %User{local: true} = user <- User.get_cached_by_nickname(nickname) do blocks = User.following_ap_ids(user) - IO.inspect(blocks, limit: :infinity) + IO.puts("#{inspect(blocks)}") end end diff --git a/lib/pleroma/activity/html.ex b/lib/pleroma/activity/html.ex index 30409d93d..e4aaad523 100644 --- a/lib/pleroma/activity/html.ex +++ b/lib/pleroma/activity/html.ex @@ -38,7 +38,11 @@ defp add_cache_key_for(activity_id, additional_key) do def invalidate_cache_for(activity_id) do keys = get_cache_keys_for(activity_id) - Enum.map(keys, &@cachex.del(:scrubber_cache, &1)) + + for key <- keys do + @cachex.del(:scrubber_cache, key) + end + @cachex.del(:scrubber_management_cache, activity_id) end diff --git a/lib/pleroma/akkoma/translators/translator.ex b/lib/pleroma/akkoma/translator.ex similarity index 100% rename from lib/pleroma/akkoma/translators/translator.ex rename to lib/pleroma/akkoma/translator.ex diff --git a/lib/pleroma/announcement.ex b/lib/pleroma/announcement.ex index d97c5e728..6dc1a9c7b 100644 --- a/lib/pleroma/announcement.ex +++ b/lib/pleroma/announcement.ex @@ -24,8 +24,10 @@ defmodule Pleroma.Announcement do end def change(struct, params \\ %{}) do + params = validate_params(struct, params) + struct - |> cast(validate_params(struct, params), [:data, :starts_at, :ends_at, :rendered]) + |> cast(params, [:data, :starts_at, :ends_at, :rendered]) |> validate_required([:data]) end diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex index ec8839e0f..48a2623ce 100644 --- a/lib/pleroma/application.ex +++ b/lib/pleroma/application.ex @@ -198,6 +198,8 @@ defp background_migrators do ] end + @spec task_children(atom()) :: [map()] + defp task_children(:test) do [ %{ @@ -223,6 +225,7 @@ defp task_children(_) do ] end + @spec elasticsearch_children :: [Pleroma.Search.Elasticsearch.Cluster] def elasticsearch_children do config = Config.get([Pleroma.Search, :module]) diff --git a/lib/pleroma/application_requirements.ex b/lib/pleroma/application_requirements.ex index a56311a65..19236aaa2 100644 --- a/lib/pleroma/application_requirements.ex +++ b/lib/pleroma/application_requirements.ex @@ -194,8 +194,6 @@ defp check_system_commands!(:ok) do end end - defp check_system_commands!(result), do: result - defp check_repo_pool_size!(:ok) do if Pleroma.Config.get([Pleroma.Repo, :pool_size], 10) != 10 and not Pleroma.Config.get([:dangerzone, :override_repo_pool_size], false) do diff --git a/lib/pleroma/emoji/pack.ex b/lib/pleroma/emoji/pack.ex index 8d233d5e4..2ca174c1f 100644 --- a/lib/pleroma/emoji/pack.ex +++ b/lib/pleroma/emoji/pack.ex @@ -209,7 +209,9 @@ def list_remote(opts) do with :ok <- validate_shareable_packs_available(uri) do uri - |> URI.merge("/api/pleroma/emoji/packs?page=#{opts[:page]}&page_size=#{opts[:page_size]}") + |> URI.merge( + "/api/v1/pleroma/emoji/packs?page=#{opts[:page]}&page_size=#{opts[:page_size]}" + ) |> http_get() end end @@ -250,7 +252,7 @@ def download(name, url, as) do with :ok <- validate_shareable_packs_available(uri), {:ok, remote_pack} <- - uri |> URI.merge("/api/pleroma/emoji/pack?name=#{name}") |> http_get(), + uri |> URI.merge("/api/v1/pleroma/emoji/pack?name=#{name}") |> http_get(), {:ok, %{sha: sha, url: url} = pack_info} <- fetch_pack_info(remote_pack, uri, name), {:ok, archive} <- download_archive(url, sha), pack <- copy_as(remote_pack, as || name), @@ -591,7 +593,7 @@ defp fetch_pack_info(remote_pack, uri, name) do {:ok, %{ sha: sha, - url: URI.merge(uri, "/api/pleroma/emoji/packs/archive?name=#{name}") |> to_string() + url: URI.merge(uri, "/api/v1/pleroma/emoji/packs/archive?name=#{name}") |> to_string() }} %{"fallback-src" => src, "fallback-src-sha256" => sha} when is_binary(src) -> diff --git a/lib/pleroma/following_relationship.ex b/lib/pleroma/following_relationship.ex index 42db9463d..c489ccbbe 100644 --- a/lib/pleroma/following_relationship.ex +++ b/lib/pleroma/following_relationship.ex @@ -14,6 +14,8 @@ defmodule Pleroma.FollowingRelationship do alias Pleroma.Repo alias Pleroma.User + @type follow_state :: :follow_pending | :follow_accept | :follow_reject | :unfollow + schema "following_relationships" do field(:state, State, default: :follow_pending) @@ -72,6 +74,7 @@ def update(%User{} = follower, %User{} = following, state) do end end + @spec follow(User.t(), User.t()) :: {:ok, User.t(), User.t()} | {:error, any} def follow(%User{} = follower, %User{} = following, state \\ :follow_accept) do with {:ok, _following_relationship} <- %__MODULE__{} @@ -81,6 +84,7 @@ def follow(%User{} = follower, %User{} = following, state \\ :follow_accept) do end end + @spec unfollow(User.t(), User.t()) :: {:ok, User.t(), User.t()} | {:error, any} def unfollow(%User{} = follower, %User{} = following) do case get(follower, following) do %__MODULE__{} = following_relationship -> @@ -89,10 +93,12 @@ def unfollow(%User{} = follower, %User{} = following) do end _ -> - {:ok, nil} + {:ok, follower, following} end end + @spec after_update(follow_state(), User.t(), User.t()) :: + {:ok, User.t(), User.t()} | {:error, any()} defp after_update(state, %User{} = follower, %User{} = following) do with {:ok, following} <- User.update_follower_count(following), {:ok, follower} <- User.update_following_count(follower) do @@ -103,6 +109,8 @@ defp after_update(state, %User{} = follower, %User{} = following) do }) {:ok, follower, following} + else + err -> {:error, err} end end diff --git a/lib/pleroma/helpers/media_helper.ex b/lib/pleroma/helpers/media_helper.ex index d0c3ab5cc..cb95d0e68 100644 --- a/lib/pleroma/helpers/media_helper.ex +++ b/lib/pleroma/helpers/media_helper.ex @@ -104,10 +104,10 @@ defp run_fifo(fifo_path, env, executable, args) do args: args ]) - fifo = Port.open(to_charlist(fifo_path), [:eof, :binary, :stream, :out]) + fifo = File.open!(fifo_path, [:append, :binary]) fix = Pleroma.Helpers.QtFastStart.fix(env.body) - true = Port.command(fifo, fix) - :erlang.port_close(fifo) + IO.binwrite(fifo, fix) + File.close(fifo) loop_recv(pid) after File.rm(fifo_path) diff --git a/lib/pleroma/http/adapter_helper.ex b/lib/pleroma/http/adapter_helper.ex index e837ac8d4..77b854b5d 100644 --- a/lib/pleroma/http/adapter_helper.ex +++ b/lib/pleroma/http/adapter_helper.ex @@ -14,9 +14,7 @@ defmodule Pleroma.HTTP.AdapterHelper do alias Pleroma.HTTP.AdapterHelper require Logger - @type proxy :: - {Connection.host(), pos_integer()} - | {Connection.proxy_type(), Connection.host(), pos_integer()} + @type proxy :: {Connection.proxy_type(), Connection.host(), pos_integer(), list()} @callback options(keyword(), URI.t()) :: keyword() @@ -25,7 +23,6 @@ def format_proxy(nil), do: nil def format_proxy(proxy_url) do case parse_proxy(proxy_url) do - {:ok, host, port} -> {:http, host, port, []} {:ok, type, host, port} -> {type, host, port, []} _ -> nil end @@ -94,8 +91,7 @@ defp proxy_type("https"), do: {:ok, :https} defp proxy_type(_), do: {:error, :unknown} @spec parse_proxy(String.t() | tuple() | nil) :: - {:ok, host(), pos_integer()} - | {:ok, proxy_type(), host(), pos_integer()} + {:ok, proxy_type(), host(), pos_integer()} | {:error, atom()} | nil def parse_proxy(nil), do: nil diff --git a/lib/pleroma/migrators/support/base_migrator.ex b/lib/pleroma/migrators/support/base_migrator.ex index 1f8a5402b..2ffb35081 100644 --- a/lib/pleroma/migrators/support/base_migrator.ex +++ b/lib/pleroma/migrators/support/base_migrator.ex @@ -14,7 +14,7 @@ defmodule Pleroma.Migrators.Support.BaseMigrator do @callback fault_rate_allowance() :: integer() | float() defmacro __using__(_opts) do - quote do + quote generated: true do use GenServer require Logger diff --git a/lib/pleroma/moderation_log.ex b/lib/pleroma/moderation_log.ex index 7da8d0c63..b94d53913 100644 --- a/lib/pleroma/moderation_log.ex +++ b/lib/pleroma/moderation_log.ex @@ -237,7 +237,8 @@ def insert_log(%{actor: %User{}, action: action, target: target} = attrs) insert_log_entry_with_message(%ModerationLog{data: data}) end - @spec insert_log_entry_with_message(ModerationLog) :: {:ok, ModerationLog} | {:error, any} + @spec insert_log_entry_with_message(ModerationLog.t()) :: + {:ok, ModerationLog.t()} | {:error, any} defp insert_log_entry_with_message(entry) do entry.data["message"] |> put_in(get_log_entry_message(entry)) diff --git a/lib/pleroma/object.ex b/lib/pleroma/object.ex index a75d85c47..844251a18 100644 --- a/lib/pleroma/object.ex +++ b/lib/pleroma/object.ex @@ -240,7 +240,7 @@ def delete(%Object{data: %{"id" => id}} = object) do {:ok, _} <- invalid_object_cache(object) do cleanup_attachments( Config.get([:instance, :cleanup_attachments]), - %{"object" => object} + %{object: object} ) {:ok, object, deleted_activity} @@ -249,7 +249,7 @@ def delete(%Object{data: %{"id" => id}} = object) do @spec cleanup_attachments(boolean(), %{required(:object) => map()}) :: {:ok, Oban.Job.t() | nil} - def cleanup_attachments(true, %{"object" => _} = params) do + def cleanup_attachments(true, %{object: _} = params) do AttachmentsCleanupWorker.enqueue("cleanup_attachments", params) end diff --git a/lib/pleroma/release_tasks.ex b/lib/pleroma/release_tasks.ex index e43eef070..75c027137 100644 --- a/lib/pleroma/release_tasks.ex +++ b/lib/pleroma/release_tasks.ex @@ -61,9 +61,6 @@ def create do IO.puts("The database for #{inspect(@repo)} has already been created") {:error, term} when is_binary(term) -> - IO.puts(:stderr, "The database for #{inspect(@repo)} couldn't be created: #{term}") - - {:error, term} -> IO.puts( :stderr, "The database for #{inspect(@repo)} couldn't be created: #{inspect(term)}" diff --git a/lib/pleroma/reverse_proxy/client/tesla.ex b/lib/pleroma/reverse_proxy/client/tesla.ex index 59fd5493c..a4fc1ebc2 100644 --- a/lib/pleroma/reverse_proxy/client/tesla.ex +++ b/lib/pleroma/reverse_proxy/client/tesla.ex @@ -66,6 +66,7 @@ defp read_chunk!(%{pid: pid, stream: stream, opts: opts}) do @impl true @spec close(map) :: :ok | no_return() def close(%{pid: _pid}) do + :ok end defp check_adapter do diff --git a/lib/pleroma/search/elasticsearch.ex b/lib/pleroma/search/elasticsearch.ex index 16b01101a..20e03e1f0 100644 --- a/lib/pleroma/search/elasticsearch.ex +++ b/lib/pleroma/search/elasticsearch.ex @@ -13,25 +13,21 @@ defmodule Pleroma.Search.Elasticsearch do def es_query(:activity, query, offset, limit) do must = Parsers.Activity.parse(query) - if must == [] do - :skip - else - %{ - size: limit, - from: offset, - terminate_after: 50, - timeout: "5s", - sort: [ - "_score", - %{"_timestamp" => %{order: "desc", format: "basic_date_time"}} - ], - query: %{ - bool: %{ - must: must - } + %{ + size: limit, + from: offset, + terminate_after: 50, + timeout: "5s", + sort: [ + "_score", + %{"_timestamp" => %{order: "desc", format: "basic_date_time"}} + ], + query: %{ + bool: %{ + must: must } } - end + } end defp maybe_fetch(:activity, search_query) do diff --git a/lib/pleroma/search/elasticsearch/document_mappings/activity.ex b/lib/pleroma/search/elasticsearch/document_mappings/activity.ex index b77c6e0d2..71ef75634 100644 --- a/lib/pleroma/search/elasticsearch/document_mappings/activity.ex +++ b/lib/pleroma/search/elasticsearch/document_mappings/activity.ex @@ -57,5 +57,5 @@ def encode(activity) do defimpl Elasticsearch.Document, for: Pleroma.Object do def id(obj), do: obj.id def routing(_), do: false - def encode(_), do: nil + def encode(_), do: %{} end diff --git a/lib/pleroma/search/meilisearch.ex b/lib/pleroma/search/meilisearch.ex index c36b8f751..8fcf9310a 100644 --- a/lib/pleroma/search/meilisearch.ex +++ b/lib/pleroma/search/meilisearch.ex @@ -154,10 +154,11 @@ def add_to_index(activity) do with {:ok, res} <- result, true <- Map.has_key?(res, "taskUid") do - # Do nothing + {:ok, res} else - _ -> + err -> Logger.error("Failed to add activity #{activity.id} to index: #{inspect(result)}") + {:error, err} end end end diff --git a/lib/pleroma/search/search_backend.ex b/lib/pleroma/search/search_backend.ex index ed6bfd329..56e3b7de5 100644 --- a/lib/pleroma/search/search_backend.ex +++ b/lib/pleroma/search/search_backend.ex @@ -4,7 +4,7 @@ defmodule Pleroma.Search.SearchBackend do The whole activity is passed, to allow filtering on things such as scope. """ - @callback add_to_index(activity :: Pleroma.Activity.t()) :: nil + @callback add_to_index(activity :: Pleroma.Activity.t()) :: {:ok, any()} | {:error, any()} @doc """ Remove the object from the index. @@ -13,5 +13,5 @@ defmodule Pleroma.Search.SearchBackend do is what contains the actual content and there is no need for fitlering when removing from index. """ - @callback remove_from_index(object :: Pleroma.Object.t()) :: nil + @callback remove_from_index(object :: Pleroma.Object.t()) :: {:ok, any()} | {:error, any()} end diff --git a/lib/pleroma/signature.ex b/lib/pleroma/signature.ex index 043a0643e..1c59be9c7 100644 --- a/lib/pleroma/signature.ex +++ b/lib/pleroma/signature.ex @@ -27,7 +27,7 @@ def key_id_to_actor_id(key_id) do _ -> case Pleroma.Web.WebFinger.finger(maybe_ap_id) do - %{"ap_id" => ap_id} -> {:ok, ap_id} + {:ok, %{"ap_id" => ap_id}} -> {:ok, ap_id} _ -> {:error, maybe_ap_id} end end diff --git a/lib/pleroma/upload.ex b/lib/pleroma/upload.ex index 9bf8e03df..3b5419db7 100644 --- a/lib/pleroma/upload.ex +++ b/lib/pleroma/upload.ex @@ -162,7 +162,7 @@ defp prepare_upload(%Plug.Upload{} = file, opts) do defp prepare_upload(%{img: "data:image/" <> image_data}, opts) do parsed = Regex.named_captures(~r/(?jpeg|png|gif);base64,(?.*)/, image_data) data = Base.decode64!(parsed["data"], ignore: :whitespace) - hash = Base.encode16(:crypto.hash(:sha256, data), lower: true) + hash = Base.encode16(:crypto.hash(:sha256, data), case: :lower) with :ok <- check_binary_size(data, opts.size_limit), tmp_path <- tempfile_for_image(data), diff --git a/lib/pleroma/upload/filter/analyze_metadata.ex b/lib/pleroma/upload/filter/analyze_metadata.ex index c89c30fc1..8990e97c0 100644 --- a/lib/pleroma/upload/filter/analyze_metadata.ex +++ b/lib/pleroma/upload/filter/analyze_metadata.ex @@ -77,7 +77,6 @@ defp media_dimensions(file) do %{width: width, height: height} else nil -> {:error, {:ffprobe, :command_not_found}} - {:error, _} = error -> error end end end diff --git a/lib/pleroma/upload/filter/exiftool.ex b/lib/pleroma/upload/filter/exiftool.ex index a2bfbbf61..9e82cf8a7 100644 --- a/lib/pleroma/upload/filter/exiftool.ex +++ b/lib/pleroma/upload/filter/exiftool.ex @@ -9,7 +9,7 @@ defmodule Pleroma.Upload.Filter.Exiftool do """ @behaviour Pleroma.Upload.Filter - @spec filter(Pleroma.Upload.t()) :: {:ok, any()} | {:error, String.t()} + @spec filter(Pleroma.Upload.t()) :: {:ok, :noop} | {:ok, :filtered} | {:error, String.t()} # Formats not compatible with exiftool at this time def filter(%Pleroma.Upload{content_type: "image/heic"}), do: {:ok, :noop} diff --git a/lib/pleroma/upload/filter/mogrifun.ex b/lib/pleroma/upload/filter/mogrifun.ex index 01126aaeb..69885a0bd 100644 --- a/lib/pleroma/upload/filter/mogrifun.ex +++ b/lib/pleroma/upload/filter/mogrifun.ex @@ -38,7 +38,7 @@ defmodule Pleroma.Upload.Filter.Mogrifun do [{"fill", "yellow"}, {"tint", "40"}] ] - @spec filter(Pleroma.Upload.t()) :: {:ok, atom()} | {:error, String.t()} + @spec filter(Pleroma.Upload.t()) :: {:ok, :filtered | :noop} | {:error, String.t()} def filter(%Pleroma.Upload{tempfile: file, content_type: "image" <> _}) do try do Filter.Mogrify.do_filter(file, [Enum.random(@filters)]) diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index ba30769bb..d7c1511ce 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -3,6 +3,10 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.User do + @moduledoc """ + A user, local or remote + """ + use Ecto.Schema import Ecto.Changeset @@ -549,9 +553,17 @@ def update_changeset(struct, params \\ %{}) do end defp put_fields(changeset) do + # These fields are inconsistent in tests when it comes to binary/atom keys if raw_fields = get_change(changeset, :raw_fields) do raw_fields = raw_fields + |> Enum.map(fn + %{name: name, value: value} -> + %{"name" => name, "value" => value} + + %{"name" => _} = field -> + field + end) |> Enum.filter(fn %{"name" => n} -> n != "" end) fields = @@ -705,7 +717,8 @@ def register_changeset_ldap(struct, params = %{password: password}) |> put_private_key() end - def register_changeset(struct, params \\ %{}, opts \\ []) do + @spec register_changeset(User.t(), map(), keyword()) :: Changeset.t() + def register_changeset(%User{} = struct, params \\ %{}, opts \\ []) do bio_limit = Config.get([:instance, :user_bio_length], 5000) name_limit = Config.get([:instance, :user_name_length], 100) reason_limit = Config.get([:instance, :registration_reason_length], 500) @@ -819,12 +832,14 @@ defp autofollowing_users(user) do end @doc "Inserts provided changeset, performs post-registration actions (confirmation email sending etc.)" + @spec register(Changeset.t()) :: {:ok, User.t()} | {:error, any} | nil def register(%Ecto.Changeset{} = changeset) do with {:ok, user} <- Repo.insert(changeset) do post_register_action(user) end end + @spec post_register_action(User.t()) :: {:error, any} | {:ok, User.t()} def post_register_action(%User{is_confirmed: false} = user) do with {:ok, _} <- maybe_send_confirmation_email(user) do {:ok, user} @@ -939,7 +954,8 @@ def needs_update?(%User{local: false} = user) do def needs_update?(_), do: true - @spec maybe_direct_follow(User.t(), User.t()) :: {:ok, User.t()} | {:error, String.t()} + @spec maybe_direct_follow(User.t(), User.t()) :: + {:ok, User.t(), User.t()} | {:error, String.t()} # "Locked" (self-locked) users demand explicit authorization of follow requests def maybe_direct_follow(%User{} = follower, %User{local: true, is_locked: true} = followed) do @@ -1072,6 +1088,11 @@ def get_by_guessed_nickname(ap_id) do get_cached_by_nickname(nickname) end + @spec set_cache( + {:error, any} + | {:ok, User.t()} + | User.t() + ) :: {:ok, User.t()} | {:error, any} def set_cache({:ok, user}), do: set_cache(user) def set_cache({:error, err}), do: {:error, err} @@ -1082,12 +1103,14 @@ def set_cache(%User{} = user) do {:ok, user} end + @spec update_and_set_cache(User.t(), map()) :: {:ok, User.t()} | {:error, any} def update_and_set_cache(struct, params) do struct |> update_changeset(params) |> update_and_set_cache() end + @spec update_and_set_cache(Changeset.t()) :: {:ok, User.t()} | {:error, any} def update_and_set_cache(%{data: %Pleroma.User{} = user} = changeset) do was_superuser_before_update = User.superuser?(user) @@ -1142,6 +1165,7 @@ def get_cached_by_ap_id(ap_id) do end end + @spec get_cached_by_id(String.t()) :: nil | Pleroma.User.t() def get_cached_by_id(id) do key = "id:#{id}" @@ -2302,6 +2326,7 @@ def add_alias(user, new_alias_user) do end end + @spec delete_alias(User.t(), User.t()) :: {:error, :no_such_alias} def delete_alias(user, alias_user) do current_aliases = user.also_known_as || [] alias_ap_id = alias_user.ap_id @@ -2417,7 +2442,7 @@ def confirmation_changeset(user, set_confirmation: confirmed?) do cast(user, params, [:is_confirmed, :confirmation_token]) end - @spec approval_changeset(User.t(), keyword()) :: Changeset.t() + @spec approval_changeset(Changeset.t(), keyword()) :: Changeset.t() def approval_changeset(user, set_approval: approved?) do cast(user, %{is_approved: approved?}, [:is_approved]) end @@ -2492,15 +2517,19 @@ defp add_to_block(%User{} = user, %User{} = blocked) do with {:ok, relationship} <- UserRelationship.create_block(user, blocked) do @cachex.del(:user_cache, "blocked_users_ap_ids:#{user.ap_id}") {:ok, relationship} + else + err -> err end end - @spec add_to_block(User.t(), User.t()) :: + @spec remove_from_block(User.t(), User.t()) :: {:ok, UserRelationship.t()} | {:ok, nil} | {:error, Ecto.Changeset.t()} defp remove_from_block(%User{} = user, %User{} = blocked) do with {:ok, relationship} <- UserRelationship.delete_block(user, blocked) do @cachex.del(:user_cache, "blocked_users_ap_ids:#{user.ap_id}") {:ok, relationship} + else + err -> err end end diff --git a/lib/pleroma/user/backup.ex b/lib/pleroma/user/backup.ex index 2c6378265..63709a484 100644 --- a/lib/pleroma/user/backup.ex +++ b/lib/pleroma/user/backup.ex @@ -130,7 +130,8 @@ def export(%__MODULE__{} = backup) do :ok <- statuses(dir, backup.user), :ok <- likes(dir, backup.user), :ok <- bookmarks(dir, backup.user), - {:ok, zip_path} <- :zip.create(String.to_charlist(dir <> ".zip"), @files, cwd: dir), + {:ok, zip_path} <- + :zip.create(String.to_charlist(dir <> ".zip"), @files, cwd: String.to_charlist(dir)), {:ok, _} <- File.rm_rf(dir) do {:ok, to_string(zip_path)} end diff --git a/lib/pleroma/web.ex b/lib/pleroma/web.ex index 5761e3b38..24560d4a3 100644 --- a/lib/pleroma/web.ex +++ b/lib/pleroma/web.ex @@ -56,7 +56,10 @@ defp skip_plug(conn, plug_modules) do plug_module.skip_plug(conn) rescue UndefinedFunctionError -> - raise "`#{plug_module}` is not skippable. Append `use Pleroma.Web, :plug` to its code." + reraise( + "`#{plug_module}` is not skippable. Append `use Pleroma.Web, :plug` to its code.", + __STACKTRACE__ + ) end end ) diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 3adb4ab54..8e55df0d8 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -1531,6 +1531,10 @@ defp normalize_image(%{"url" => url}) do defp normalize_image(urls) when is_list(urls), do: urls |> List.first() |> normalize_image() defp normalize_image(_), do: nil + defp normalize_also_known_as(aka) when is_list(aka), do: aka + defp normalize_also_known_as(aka) when is_binary(aka), do: [aka] + defp normalize_also_known_as(nil), do: [] + defp object_to_user_data(data, additional) do fields = data @@ -1576,6 +1580,7 @@ defp object_to_user_data(data, additional) do also_known_as = data |> Map.get("alsoKnownAs", []) + |> normalize_also_known_as() |> Enum.filter(fn url -> case URI.parse(url) do %URI{scheme: "http"} -> true diff --git a/lib/pleroma/web/akkoma_api/controllers/translation_controller.ex b/lib/pleroma/web/akkoma_api/controllers/translation_controller.ex index ca9b4b64a..022da3198 100644 --- a/lib/pleroma/web/akkoma_api/controllers/translation_controller.ex +++ b/lib/pleroma/web/akkoma_api/controllers/translation_controller.ex @@ -3,6 +3,8 @@ defmodule Pleroma.Web.AkkomaAPI.TranslationController do alias Pleroma.Web.Plugs.OAuthScopesPlug + require Logger + @cachex Pleroma.Config.get([:cachex, :provider], Cachex) @unauthenticated_access %{fallback: :proceed_unauthenticated, scopes: []} @@ -26,8 +28,12 @@ def languages(conn, _params) do conn |> json(%{source: source_languages, target: dest_languages}) else - {:enabled, false} -> json(conn, %{}) - e -> IO.inspect(e) + {:enabled, false} -> + json(conn, %{}) + + e -> + Logger.error("Translation language list error: #{inspect(e)}") + {:error, e} end end diff --git a/lib/pleroma/web/api_spec/operations/pleroma_emoji_pack_operation.ex b/lib/pleroma/web/api_spec/operations/pleroma_emoji_pack_operation.ex index 49247d9b6..c38349486 100644 --- a/lib/pleroma/web/api_spec/operations/pleroma_emoji_pack_operation.ex +++ b/lib/pleroma/web/api_spec/operations/pleroma_emoji_pack_operation.ex @@ -231,9 +231,18 @@ defp emoji_packs_response do "application/json", %Schema{ type: :object, - additionalProperties: emoji_pack(), + properties: %{ + count: %Schema{type: :integer}, + packs: %Schema{ + type: :object, + additionalProperties: emoji_pack() + } + }, example: %{ - "emojos" => emoji_pack().example + "count" => 4, + "packs" => %{ + "emojos" => emoji_pack().example + } } } ) diff --git a/lib/pleroma/web/auth/pleroma_authenticator.ex b/lib/pleroma/web/auth/pleroma_authenticator.ex index 68472e75f..bb377d686 100644 --- a/lib/pleroma/web/auth/pleroma_authenticator.ex +++ b/lib/pleroma/web/auth/pleroma_authenticator.ex @@ -60,6 +60,8 @@ def get_registration(%Plug.Conn{ def get_registration(%Plug.Conn{} = _conn), do: {:error, :missing_credentials} @doc "Creates Pleroma.User record basing on params and Pleroma.Registration record." + @spec create_from_registration(Plug.Conn.t(), Registration.t()) :: + {:ok, User.t()} | {:error, any()} def create_from_registration( %Plug.Conn{params: %{"authorization" => registration_attrs}}, %Registration{} = registration @@ -89,6 +91,8 @@ def create_from_registration( {:ok, _} <- Registration.changeset(registration, %{user_id: new_user.id}) |> Repo.update() do {:ok, new_user} + else + err -> err end end diff --git a/lib/pleroma/web/controller_helper.ex b/lib/pleroma/web/controller_helper.ex index 7b84b43e4..6acc8f078 100644 --- a/lib/pleroma/web/controller_helper.ex +++ b/lib/pleroma/web/controller_helper.ex @@ -87,16 +87,18 @@ def get_pagination_fields(conn, entries, extra_params \\ %{}) do def assign_account_by_id(conn, _) do case Pleroma.User.get_cached_by_id(conn.params.id) do - %Pleroma.User{} = account -> assign(conn, :account, account) - nil -> Pleroma.Web.MastodonAPI.FallbackController.call(conn, {:error, :not_found}) |> halt() + %Pleroma.User{} = account -> + assign(conn, :account, account) + + nil -> + Pleroma.Web.MastodonAPI.FallbackController.call(conn, {:error, :not_found}) + |> halt() end end + @spec try_render(Plug.Conn.t(), any, any) :: Plug.Conn.t() def try_render(conn, target, params) when is_binary(target) do - case render(conn, target, params) do - nil -> render_error(conn, :not_implemented, "Can't display this activity") - res -> res - end + render(conn, target, params) end def try_render(conn, _, _) do diff --git a/lib/pleroma/web/endpoint.ex b/lib/pleroma/web/endpoint.ex index 6dd66a424..baf0c5651 100644 --- a/lib/pleroma/web/endpoint.ex +++ b/lib/pleroma/web/endpoint.ex @@ -123,7 +123,7 @@ defmodule Pleroma.Web.Endpoint do plug(Plug.Parsers, parsers: [ :urlencoded, - {:multipart, length: {Config, :get, [[:instance, :upload_limit]]}}, + Pleroma.Web.Plugs.Parsers.Multipart, :json ], pass: ["*/*"], diff --git a/lib/pleroma/web/fallback/legacy_pleroma_api_rerouter_plug.ex b/lib/pleroma/web/fallback/legacy_pleroma_api_rerouter_plug.ex deleted file mode 100644 index f86d6b52b..000000000 --- a/lib/pleroma/web/fallback/legacy_pleroma_api_rerouter_plug.ex +++ /dev/null @@ -1,26 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2021 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.Fallback.LegacyPleromaApiRerouterPlug do - alias Pleroma.Web.Endpoint - alias Pleroma.Web.Fallback.RedirectController - - def init(opts), do: opts - - def call(%{path_info: ["api", "pleroma" | path_info_rest]} = conn, _opts) do - new_path_info = ["api", "v1", "pleroma" | path_info_rest] - new_request_path = Enum.join(new_path_info, "/") - - conn - |> Map.merge(%{ - path_info: new_path_info, - request_path: new_request_path - }) - |> Endpoint.call(conn.params) - end - - def call(conn, _opts) do - RedirectController.api_not_implemented(conn, %{}) - end -end diff --git a/lib/pleroma/web/metadata/utils.ex b/lib/pleroma/web/metadata/utils.ex index 8990bef54..7308726f5 100644 --- a/lib/pleroma/web/metadata/utils.ex +++ b/lib/pleroma/web/metadata/utils.ex @@ -30,6 +30,10 @@ def scrub_html_and_truncate(%{data: %{"content" => content}} = object) do |> scrub_html_and_truncate_object_field(object) end + def scrub_html_and_truncate(%{data: _}) do + "" + end + def scrub_html_and_truncate(content, max_length \\ 200) when is_binary(content) do content |> scrub_html diff --git a/lib/pleroma/web/o_auth/o_auth_controller.ex b/lib/pleroma/web/o_auth/o_auth_controller.ex index 455af11d7..8f32e7219 100644 --- a/lib/pleroma/web/o_auth/o_auth_controller.ex +++ b/lib/pleroma/web/o_auth/o_auth_controller.ex @@ -558,10 +558,9 @@ def register(%Plug.Conn{} = conn, %{"authorization" => _, "op" => "register"} = else {:error, changeset} -> message = - Enum.map(changeset.errors, fn {field, {error, _}} -> + Enum.map_join(changeset.errors, "; ", fn {field, {error, _}} -> "#{field} #{error}" end) - |> Enum.join("; ") message = String.replace( diff --git a/lib/pleroma/web/plugs/parsers/multipart.ex b/lib/pleroma/web/plugs/parsers/multipart.ex new file mode 100644 index 000000000..6b5ab6af4 --- /dev/null +++ b/lib/pleroma/web/plugs/parsers/multipart.ex @@ -0,0 +1,21 @@ +defmodule Pleroma.Web.Plugs.Parsers.Multipart do + @multipart Plug.Parsers.MULTIPART + + alias Pleroma.Config + + def init(opts) do + opts + end + + def parse(conn, "multipart", subtype, headers, opts) do + length = Config.get([:instance, :upload_limit]) + + opts = @multipart.init([length: length] ++ opts) + + @multipart.parse(conn, "multipart", subtype, headers, opts) + end + + def parse(conn, _type, _subtype, _headers, _opts) do + {:next, conn} + end +end diff --git a/lib/pleroma/web/plugs/remote_ip.ex b/lib/pleroma/web/plugs/remote_ip.ex index 4d7daca56..d992dea63 100644 --- a/lib/pleroma/web/plugs/remote_ip.ex +++ b/lib/pleroma/web/plugs/remote_ip.ex @@ -8,7 +8,6 @@ defmodule Pleroma.Web.Plugs.RemoteIp do """ alias Pleroma.Config - import Plug.Conn @behaviour Plug @@ -16,15 +15,21 @@ def init(_), do: nil def call(%{remote_ip: original_remote_ip} = conn, _) do if Config.get([__MODULE__, :enabled]) do - %{remote_ip: new_remote_ip} = conn = RemoteIp.call(conn, remote_ip_opts()) - assign(conn, :remote_ip_found, original_remote_ip != new_remote_ip) + {headers, proxies} = remote_ip_opts() + new_remote_ip = RemoteIp.from(conn.req_headers, headers: headers, proxies: proxies) + + if new_remote_ip != original_remote_ip do + Map.put(conn, :remote_ip, new_remote_ip) + else + conn + end else conn end end defp remote_ip_opts do - headers = Config.get([__MODULE__, :headers], []) |> MapSet.new() + headers = Config.get([__MODULE__, :headers], []) reserved = Config.get([__MODULE__, :reserved], []) proxies = @@ -36,13 +41,10 @@ defp remote_ip_opts do end defp maybe_add_cidr(proxy) when is_binary(proxy) do - proxy = - cond do - "/" in String.codepoints(proxy) -> proxy - InetCidr.v4?(InetCidr.parse_address!(proxy)) -> proxy <> "/32" - InetCidr.v6?(InetCidr.parse_address!(proxy)) -> proxy <> "/128" - end - - InetCidr.parse(proxy, true) + cond do + "/" in String.codepoints(proxy) -> proxy + InetCidr.v4?(InetCidr.parse_address!(proxy)) -> proxy <> "/32" + InetCidr.v6?(InetCidr.parse_address!(proxy)) -> proxy <> "/128" + end end end diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index f2ea679a0..e790b1cdb 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -906,8 +906,6 @@ defmodule Pleroma.Web.Router do scope "/", Pleroma.Web.Fallback do get("/registration/:token", RedirectController, :registration_page) get("/:maybe_nickname_or_id", RedirectController, :redirector_with_meta) - match(:*, "/api/pleroma*path", LegacyPleromaApiRerouterPlug, []) - get("/api*path", RedirectController, :api_not_implemented) get("/*path", RedirectController, :redirector_with_preload) options("/*path", RedirectController, :empty) diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex index a0c3e5c52..f2b571fff 100644 --- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex +++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex @@ -150,7 +150,10 @@ def remote_subscribe(conn, %{"status" => %{"status_id" => id, "profile" => profi end end - def remote_interaction(%{body_params: %{ap_id: ap_id, profile: profile}} = conn, _params) do + def remote_interaction( + %Plug.Conn{body_params: %{ap_id: ap_id, profile: profile}} = conn, + _params + ) do with {:ok, %{"subscribe_address" => template}} <- WebFinger.finger(profile) do conn |> json(%{url: String.replace(template, "{uri}", ap_id)}) diff --git a/lib/pleroma/web/web_finger.ex b/lib/pleroma/web/web_finger.ex index f5a46ce25..364d0e0e6 100644 --- a/lib/pleroma/web/web_finger.ex +++ b/lib/pleroma/web/web_finger.ex @@ -100,6 +100,7 @@ defp domain do Pleroma.Config.get([__MODULE__, :domain]) || Pleroma.Web.Endpoint.host() end + @spec webfinger_from_xml(binary()) :: {:ok, map()} | nil defp webfinger_from_xml(body) do with {:ok, doc} <- XML.parse_document(body) do subject = XML.string_from_xpath("//Subject", doc) diff --git a/lib/pleroma/web/web_finger/web_finger_controller.ex b/lib/pleroma/web/web_finger/web_finger_controller.ex index 7944c50ad..f8b3c84a1 100644 --- a/lib/pleroma/web/web_finger/web_finger_controller.ex +++ b/lib/pleroma/web/web_finger/web_finger_controller.ex @@ -36,7 +36,7 @@ def webfinger(%{assigns: %{format: format}} = conn, %{"resource" => resource}) else _e -> conn - |> put_status(404) + |> put_status(:not_found) |> json("Couldn't find user") end end diff --git a/mix.exs b/mix.exs index dbfa6263f..00a250002 100644 --- a/mix.exs +++ b/mix.exs @@ -7,7 +7,7 @@ def project do version: version("3.5.0"), elixir: "~> 1.12", elixirc_paths: elixirc_paths(Mix.env()), - compilers: [:phoenix, :gettext] ++ Mix.compilers(), + compilers: [:phoenix] ++ Mix.compilers(), elixirc_options: [warnings_as_errors: warnings_as_errors()], xref: [exclude: [:eldap]], start_permanent: Mix.env() == :prod, @@ -94,7 +94,8 @@ defp warnings_as_errors, do: System.get_env("CI") == "true" # Specifies OAuth dependencies. defp oauth_deps do oauth_strategy_packages = - System.get_env("OAUTH_CONSUMER_STRATEGIES") + "OAUTH_CONSUMER_STRATEGIES" + |> System.get_env() |> to_string() |> String.split() |> Enum.map(fn strategy_entry -> @@ -113,32 +114,29 @@ defp oauth_deps do # Type `mix help deps` for examples and options. defp deps do [ - {:phoenix, "~> 1.6.11"}, + {:phoenix, "~> 1.6.15"}, {:tzdata, "~> 1.1.1"}, - {:plug_cowboy, "~> 2.5"}, + {:plug_cowboy, "~> 2.6"}, {:phoenix_pubsub, "~> 2.1"}, {:phoenix_ecto, "~> 4.4"}, + {:inet_cidr, "~> 1.0.0"}, {:ecto_enum, "~> 1.4"}, {:ecto_sql, "~> 3.9.0"}, {:postgrex, ">= 0.16.3"}, {:oban, "~> 2.12.1"}, - {:gettext, - git: "https://github.com/tusooa/gettext.git", - ref: "72fb2496b6c5280ed911bdc3756890e7f38a4808", - override: true}, + {:gettext, "~> 0.20.0"}, {:bcrypt_elixir, "~> 2.2"}, - {:trailing_format_plug, "~> 0.0.7"}, {:fast_sanitize, "~> 0.2.3"}, - {:html_entities, "~> 0.5", override: true}, - {:phoenix_html, "~> 3.1", override: true}, + {:html_entities, "~> 0.5"}, + {:phoenix_html, "~> 3.2"}, {:calendar, "~> 1.0"}, {:cachex, "~> 3.4"}, - {:poison, "~> 5.0", override: true}, - {:tesla, "~> 1.4.4", override: true}, + {:tesla, "~> 1.4.4"}, {:castore, "~> 0.1"}, - {:cowlib, "~> 2.9", override: true}, + {:cowlib, "~> 2.9"}, {:finch, "~> 0.14.0"}, {:jason, "~> 1.2"}, + {:trailing_format_plug, "~> 0.0.7"}, {:mogrify, "~> 0.9.1"}, {:ex_aws, "~> 2.1.6"}, {:ex_aws_s3, "~> 2.0"}, @@ -172,39 +170,40 @@ defp deps do {:plug_static_index_html, "~> 1.0.0"}, {:flake_id, "~> 0.1.0"}, {:concurrent_limiter, "~> 0.1.1"}, - {:remote_ip, - git: "https://git.pleroma.social/pleroma/remote_ip.git", - ref: "b647d0deecaa3acb140854fe4bda5b7e1dc6d1c8"}, + {:remote_ip, "~> 1.1.0"}, {:captcha, git: "https://git.pleroma.social/pleroma/elixir-libraries/elixir-captcha.git", ref: "e0f16822d578866e186a0974d65ad58cddc1e2ab"}, {:restarter, path: "./restarter"}, {:majic, "~> 1.0"}, {:eblurhash, "~> 1.2.2"}, - {:open_api_spex, "3.10.0"}, + {:open_api_spex, "~> 3.16.0"}, {:search_parser, git: "https://github.com/FloatingGhost/pleroma-contrib-search-parser.git", ref: "08971a81e68686f9ac465cfb6661d51c5e4e1e7f"}, {:nimble_parsec, "~> 1.0", override: true}, - {:phoenix_live_dashboard, "~> 0.6.2"}, + {:phoenix_live_dashboard, "~> 0.7.2"}, {:ecto_psql_extras, "~> 0.6"}, {:elasticsearch, git: "https://akkoma.dev/AkkomaGang/elasticsearch-elixir.git", ref: "main"}, {:mfm_parser, git: "https://akkoma.dev/AkkomaGang/mfm-parser.git", ref: "912fba81152d4d572e457fd5427f9875b2bc3dbe"}, - - # indirect dependency version override - {:plug, "~> 1.10.4", override: true}, + {:poison, ">= 0.0.0"}, ## dev & test {:ex_doc, "~> 0.22", only: :dev, runtime: false}, {:ex_machina, "~> 2.4", only: :test}, - {:credo, "~> 1.6", only: [:dev, :test], runtime: false}, + {:credo, + git: "https://github.com/rrrene/credo.git", + ref: "1c1b99ea41a457761383d81aaf6a606913996fe7", + only: [:dev, :test], + runtime: false}, {:mock, "~> 0.3.5", only: :test}, {:excoveralls, "0.15.1", only: :test}, {:mox, "~> 1.0", only: :test}, - {:websockex, "~> 0.4.3", only: :test} + {:websockex, "~> 0.4.3", only: :test}, + {:dialyxir, "~> 1.0", only: [:dev], runtime: false} ] ++ oauth_deps() end @@ -336,7 +335,7 @@ defp add_copyright(_) do # Pleroma: A lightweight social networking server # Copyright © 2017-#{year} Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only -# Akkoma: The cooler pleroma +# Akkoma: Magically expressive social media # Copyright © 2022-#{year} Akkoma Authors # SPDX-License-Identifier: AGPL-3.0-only diff --git a/mix.lock b/mix.lock index e86a58427..0e3ac3514 100644 --- a/mix.lock +++ b/mix.lock @@ -17,13 +17,14 @@ "cowboy": {:hex, :cowboy, "2.9.0", "865dd8b6607e14cf03282e10e934023a1bd8be6f6bacf921a7e2a96d800cd452", [:make, :rebar3], [{:cowlib, "2.11.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "2c729f934b4e1aa149aff882f57c6372c15399a20d54f65c8d67bef583021bde"}, "cowboy_telemetry": {:hex, :cowboy_telemetry, "0.3.1", "ebd1a1d7aff97f27c66654e78ece187abdc646992714164380d8a041eda16754", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "3a6efd3366130eab84ca372cbd4a7d3c3a97bdfcfb4911233b035d117063f0af"}, "cowlib": {:hex, :cowlib, "2.11.0", "0b9ff9c346629256c42ebe1eeb769a83c6cb771a6ee5960bd110ab0b9b872063", [:make, :rebar3], [], "hexpm", "2b3e9da0b21c4565751a6d4901c20d1b4cc25cbb7fd50d91d2ab6dd287bc86a9"}, - "credo": {:hex, :credo, "1.6.7", "323f5734350fd23a456f2688b9430e7d517afb313fbd38671b8a4449798a7854", [:mix], [{:bunt, "~> 0.2.1", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2.8", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "41e110bfb007f7eda7f897c10bf019ceab9a0b269ce79f015d54b0dcf4fc7dd3"}, + "credo": {:git, "https://github.com/rrrene/credo.git", "1c1b99ea41a457761383d81aaf6a606913996fe7", [ref: "1c1b99ea41a457761383d81aaf6a606913996fe7"]}, "crypt": {:git, "https://github.com/msantos/crypt.git", "f75cd55325e33cbea198fb41fe41871392f8fb76", [ref: "f75cd55325e33cbea198fb41fe41871392f8fb76"]}, "custom_base": {:hex, :custom_base, "0.2.1", "4a832a42ea0552299d81652aa0b1f775d462175293e99dfbe4d7dbaab785a706", [:mix], [], "hexpm", "8df019facc5ec9603e94f7270f1ac73ddf339f56ade76a721eaa57c1493ba463"}, "db_connection": {:hex, :db_connection, "2.4.3", "3b9aac9f27347ec65b271847e6baeb4443d8474289bd18c1d6f4de655b70c94d", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c127c15b0fa6cfb32eed07465e05da6c815b032508d4ed7c116122871df73c12"}, "decimal": {:hex, :decimal, "2.0.0", "a78296e617b0f5dd4c6caf57c714431347912ffb1d0842e998e9792b5642d697", [:mix], [], "hexpm", "34666e9c55dea81013e77d9d87370fe6cb6291d1ef32f46a1600230b1d44f577"}, "deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm", "ce708e5f094b9cd4e8f2be4f00d2f4250c4095be93f8cd6d018c753894885430"}, - "earmark": {:hex, :earmark, "1.4.33", "2b33a505180583f98bfa17317f03973b52081bdb24a11be05a7f4fa6d64dd8bf", [:mix], [{:earmark_parser, "~> 1.4.29", [hex: :earmark_parser, repo: "hexpm", optional: false]}], "hexpm", "21b31363d6a0a70802cfbaf2de88355778aa76654298a072bce2e01d1858ae06"}, + "dialyxir": {:hex, :dialyxir, "1.2.0", "58344b3e87c2e7095304c81a9ae65cb68b613e28340690dfe1a5597fd08dec37", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "61072136427a851674cab81762be4dbeae7679f85b1272b6d25c3a839aff8463"}, + "earmark": {:hex, :earmark, "1.4.34", "d7f89d3bbd7567a0bffc465e0a949f8f8dcbe43909c3acf96f4761a302cea10c", [:mix], [{:earmark_parser, "~> 1.4.29", [hex: :earmark_parser, repo: "hexpm", optional: false]}], "hexpm", "90b106f3dad85b133b10d7d628167c88246123fd1cecb4557d83d21ec9e65504"}, "earmark_parser": {:hex, :earmark_parser, "1.4.29", "149d50dcb3a93d9f3d6f3ecf18c918fb5a2d3c001b5d3305c926cddfbd33355b", [:mix], [], "hexpm", "4902af1b3eb139016aed210888748db8070b8125c2342ce3dcae4f38dcc63503"}, "eblurhash": {:hex, :eblurhash, "1.2.2", "7da4255aaea984b31bb71155f673257353b0e0554d0d30dcf859547e74602582", [:rebar3], [], "hexpm", "8c20ca00904de023a835a9dcb7b7762fed32264c85a80c3cafa85288e405044c"}, "ecto": {:hex, :ecto, "3.9.2", "017db3bc786ff64271108522c01a5d3f6ba0aea5c84912cfb0dd73bf13684108", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "21466d5177e09e55289ac7eade579a642578242c7a3a9f91ad5c6583337a9d15"}, @@ -32,6 +33,7 @@ "ecto_sql": {:hex, :ecto_sql, "3.9.1", "9bd5894eecc53d5b39d0c95180d4466aff00e10679e13a5cfa725f6f85c03c22", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.9.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.6.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.16.0 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "5fd470a4fff2e829bbf9dcceb7f3f9f6d1e49b4241e802f614de6b8b67c51118"}, "elasticsearch": {:git, "https://akkoma.dev/AkkomaGang/elasticsearch-elixir.git", "6cd946f75f6ab9042521a009d1d32d29a90113ca", [ref: "main"]}, "elixir_make": {:hex, :elixir_make, "0.6.3", "bc07d53221216838d79e03a8019d0839786703129599e9619f4ab74c8c096eac", [:mix], [], "hexpm", "f5cbd651c5678bcaabdbb7857658ee106b12509cd976c2c2fca99688e1daf716"}, + "erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"}, "eternal": {:hex, :eternal, "1.2.2", "d1641c86368de99375b98d183042dd6c2b234262b8d08dfd72b9eeaafc2a1abd", [:mix], [], "hexpm", "2c9fe32b9c3726703ba5e1d43a1d255a4f3f2d8f8f9bc19f094c7cb1a7a9e782"}, "ex_aws": {:hex, :ex_aws, "2.1.9", "dc4865ecc20a05190a34a0ac5213e3e5e2b0a75a0c2835e923ae7bfeac5e3c31", [:mix], [{:configparser_ex, "~> 4.0", [hex: :configparser_ex, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: true]}, {:jsx, "~> 3.0", [hex: :jsx, repo: "hexpm", optional: true]}, {:sweet_xml, "~> 0.6", [hex: :sweet_xml, repo: "hexpm", optional: true]}], "hexpm", "3e6c776703c9076001fbe1f7c049535f042cb2afa0d2cbd3b47cbc4e92ac0d10"}, "ex_aws_s3": {:hex, :ex_aws_s3, "2.3.3", "61412e524616ea31d3f31675d8bc4c73f277e367dee0ae8245610446f9b778aa", [:mix], [{:ex_aws, "~> 2.0", [hex: :ex_aws, repo: "hexpm", optional: false]}, {:sweet_xml, ">= 0.0.0", [hex: :sweet_xml, repo: "hexpm", optional: true]}], "hexpm", "0044f0b6f9ce925666021eafd630de64c2b3404d79c85245cc7c8a9a32d7f104"}, @@ -47,7 +49,7 @@ "flake_id": {:hex, :flake_id, "0.1.0", "7716b086d2e405d09b647121a166498a0d93d1a623bead243e1f74216079ccb3", [:mix], [{:base62, "~> 1.2", [hex: :base62, repo: "hexpm", optional: false]}, {:ecto, ">= 2.0.0", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm", "31fc8090fde1acd267c07c36ea7365b8604055f897d3a53dd967658c691bd827"}, "floki": {:hex, :floki, "0.34.0", "002d0cc194b48794d74711731db004fafeb328fe676976f160685262d43706a8", [:mix], [], "hexpm", "9c3a9f43f40dde00332a589bd9d389b90c1f518aef500364d00636acc5ebc99c"}, "gen_smtp": {:hex, :gen_smtp, "0.15.0", "9f51960c17769b26833b50df0b96123605a8024738b62db747fece14eb2fbfcc", [:rebar3], [], "hexpm", "29bd14a88030980849c7ed2447b8db6d6c9278a28b11a44cafe41b791205440f"}, - "gettext": {:git, "https://github.com/tusooa/gettext.git", "72fb2496b6c5280ed911bdc3756890e7f38a4808", [ref: "72fb2496b6c5280ed911bdc3756890e7f38a4808"]}, + "gettext": {:hex, :gettext, "0.20.0", "75ad71de05f2ef56991dbae224d35c68b098dd0e26918def5bb45591d5c8d429", [:mix], [], "hexpm", "1c03b177435e93a47441d7f681a7040bd2a816ece9e2666d1c9001035121eb3d"}, "hackney": {:hex, :hackney, "1.18.1", "f48bf88f521f2a229fc7bae88cf4f85adc9cd9bcf23b5dc8eb6a1788c662c4f6", [:rebar3], [{:certifi, "~> 2.9.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~> 6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~> 1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~> 1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.3.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "a4ecdaff44297e9b5894ae499e9a070ea1888c84afdd1fd9b7b2bc384950128e"}, "hpax": {:hex, :hpax, "0.1.2", "09a75600d9d8bbd064cdd741f21fc06fc1f4cf3d0fcc335e5aa19be1a7235c84", [:mix], [], "hexpm", "2c87843d5a23f5f16748ebe77969880e29809580efdaccd615cd3bed628a8c13"}, "html_entities": {:hex, :html_entities, "0.5.2", "9e47e70598da7de2a9ff6af8758399251db6dbb7eebe2b013f2bbd2515895c3c", [:mix], [], "hexpm", "c53ba390403485615623b9531e97696f076ed415e8d8058b1dbaa28181f4fdcc"}, @@ -78,18 +80,18 @@ "nimble_parsec": {:hex, :nimble_parsec, "1.2.3", "244836e6e3f1200c7f30cb56733fd808744eca61fd182f731eac4af635cc6d0b", [:mix], [], "hexpm", "c8d789e39b9131acf7b99291e93dae60ab48ef14a7ee9d58c6964f59efb570b0"}, "nimble_pool": {:hex, :nimble_pool, "0.2.6", "91f2f4c357da4c4a0a548286c84a3a28004f68f05609b4534526871a22053cde", [:mix], [], "hexpm", "1c715055095d3f2705c4e236c18b618420a35490da94149ff8b580a2144f653f"}, "oban": {:hex, :oban, "2.12.1", "f604d7e6a8be9fda4a9b0f6cebbd633deba569f85dbff70c4d25d99a6f023177", [:mix], [{:ecto_sql, "~> 3.6", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.16", [hex: :postgrex, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "9b1844c2b74e0d788b73e5144b0c9d5674cb775eae29d88a36f3c3b48d42d058"}, - "open_api_spex": {:hex, :open_api_spex, "3.10.0", "94e9521ad525b3fcf6dc77da7c45f87fdac24756d4de588cb0816b413e7c1844", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}, {:poison, "~> 3.1", [hex: :poison, repo: "hexpm", optional: true]}], "hexpm", "2dbb2bde3d2b821f06936e8dfaf3284331186556291946d84eeba3750ac28765"}, + "open_api_spex": {:hex, :open_api_spex, "3.16.0", "9843af4e87550cd8ac5821b10e4c74f1d51f0d4e3310f824d780614743423b25", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}, {:poison, "~> 3.0 or ~> 4.0 or ~> 5.0", [hex: :poison, repo: "hexpm", optional: true]}, {:ymlr, "~> 2.0 or ~> 3.0", [hex: :ymlr, repo: "hexpm", optional: true]}], "hexpm", "bb0be24a648b73e8fc8cbda17f514b8486262275e8b33e8b5ae66283df972129"}, "parse_trans": {:hex, :parse_trans, "3.3.1", "16328ab840cc09919bd10dab29e431da3af9e9e7e7e6f0089dd5a2d2820011d8", [:rebar3], [], "hexpm", "07cd9577885f56362d414e8c4c4e6bdf10d43a8767abb92d24cbe8b24c54888b"}, "phoenix": {:hex, :phoenix, "1.6.15", "0a1d96bbc10747fd83525370d691953cdb6f3ccbac61aa01b4acb012474b047d", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 1.0 or ~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: false]}, {:plug, "~> 1.10", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.2", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "d70ab9fbf6b394755ea88b644d34d79d8b146e490973151f248cacd122d20672"}, "phoenix_ecto": {:hex, :phoenix_ecto, "4.4.0", "0672ed4e4808b3fbed494dded89958e22fb882de47a97634c0b13e7b0b5f7720", [:mix], [{:ecto, "~> 3.3", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "09864e558ed31ee00bd48fcc1d4fc58ae9678c9e81649075431e69dbabb43cc1"}, "phoenix_html": {:hex, :phoenix_html, "3.2.0", "1c1219d4b6cb22ac72f12f73dc5fad6c7563104d083f711c3fcd8551a1f4ae11", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "36ec97ba56d25c0136ef1992c37957e4246b649d620958a1f9fa86165f8bc54f"}, - "phoenix_live_dashboard": {:hex, :phoenix_live_dashboard, "0.6.5", "1495bb014be12c9a9252eca04b9af54246f6b5c1e4cd1f30210cd00ec540cf8e", [:mix], [{:ecto, "~> 3.6.2 or ~> 3.7", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_mysql_extras, "~> 0.3", [hex: :ecto_mysql_extras, repo: "hexpm", optional: true]}, {:ecto_psql_extras, "~> 0.7", [hex: :ecto_psql_extras, repo: "hexpm", optional: true]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.17.7", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "ef4fa50dd78364409039c99cf6f98ab5209b4c5f8796c17f4db118324f0db852"}, - "phoenix_live_view": {:hex, :phoenix_live_view, "0.17.12", "74f4c0ad02d7deac2d04f50b52827a5efdc5c6e7fac5cede145f5f0e4183aedc", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.0 or ~> 1.7.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.1", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "af6dd5e0aac16ff43571f527a8e0616d62cb80b10eb87aac82170243e50d99c8"}, + "phoenix_live_dashboard": {:hex, :phoenix_live_dashboard, "0.7.2", "97cc4ff2dba1ebe504db72cb45098cb8e91f11160528b980bd282cc45c73b29c", [:mix], [{:ecto, "~> 3.6.2 or ~> 3.7", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_mysql_extras, "~> 0.5", [hex: :ecto_mysql_extras, repo: "hexpm", optional: true]}, {:ecto_psql_extras, "~> 0.7", [hex: :ecto_psql_extras, repo: "hexpm", optional: true]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.18.3", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6 or ~> 1.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "0e5fdf063c7a3b620c566a30fcf68b7ee02e5e46fe48ee46a6ec3ba382dc05b7"}, + "phoenix_live_view": {:hex, :phoenix_live_view, "0.18.3", "2e3d009422addf8b15c3dccc65ce53baccbe26f7cfd21d264680b5867789a9c1", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.15 or ~> 1.7.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.1", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c8845177a866e017dcb7083365393c8f00ab061b8b6b2bda575891079dce81b2"}, "phoenix_pubsub": {:hex, :phoenix_pubsub, "2.1.1", "ba04e489ef03763bf28a17eb2eaddc2c20c6d217e2150a61e3298b0f4c2012b5", [:mix], [], "hexpm", "81367c6d1eea5878ad726be80808eb5a787a23dee699f96e72b1109c57cdd8d9"}, "phoenix_swoosh": {:hex, :phoenix_swoosh, "0.3.4", "615f8f393135de7e0cbb4bd00ba238b1e0cd324b0d90efbaee613c2f02ca5e5c", [:mix], [{:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:swoosh, "~> 1.0", [hex: :swoosh, repo: "hexpm", optional: false]}], "hexpm", "3971221846232021ab5e3c7489fd62ec5bfd6a2e01cae10a317ccf6fb350571c"}, "phoenix_template": {:hex, :phoenix_template, "1.0.0", "c57bc5044f25f007dc86ab21895688c098a9f846a8dda6bc40e2d0ddc146e38f", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "1b066f99a26fd22064c12b2600a9a6e56700f591bf7b20b418054ea38b4d4357"}, "phoenix_view": {:hex, :phoenix_view, "2.0.2", "6bd4d2fd595ef80d33b439ede6a19326b78f0f1d8d62b9a318e3d9c1af351098", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}], "hexpm", "a929e7230ea5c7ee0e149ffcf44ce7cf7f4b6d2bfe1752dd7c084cdff152d36f"}, - "plug": {:hex, :plug, "1.10.4", "41eba7d1a2d671faaf531fa867645bd5a3dce0957d8e2a3f398ccff7d2ef017f", [:mix], [{:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "ad1e233fe73d2eec56616568d260777b67f53148a999dc2d048f4eb9778fe4a0"}, + "plug": {:hex, :plug, "1.14.0", "ba4f558468f69cbd9f6b356d25443d0b796fbdc887e03fa89001384a9cac638f", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "bf020432c7d4feb7b3af16a0c2701455cbbbb95e5b6866132cb09eb0c29adc14"}, "plug_cowboy": {:hex, :plug_cowboy, "2.6.0", "d1cf12ff96a1ca4f52207c5271a6c351a4733f413803488d75b70ccf44aebec2", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "073cf20b753ce6682ed72905cd62a2d4bd9bad1bf9f7feb02a1b8e525bd94fa6"}, "plug_crypto": {:hex, :plug_crypto, "1.2.3", "8f77d13aeb32bfd9e654cb68f0af517b371fb34c56c9f2b58fe3df1235c1251a", [:mix], [], "hexpm", "b5672099c6ad5c202c45f5a403f21a3411247f164e4a8fab056e5cd8a290f4a2"}, "plug_static_index_html": {:hex, :plug_static_index_html, "1.0.0", "840123d4d3975585133485ea86af73cb2600afd7f2a976f9f5fd8b3808e636a0", [:mix], [{:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "79fd4fcf34d110605c26560cbae8f23c603ec4158c08298bd4360fdea90bb5cf"}, @@ -97,16 +99,15 @@ "poolboy": {:hex, :poolboy, "1.5.2", "392b007a1693a64540cead79830443abf5762f5d30cf50bc95cb2c1aaafa006b", [:rebar3], [], "hexpm", "dad79704ce5440f3d5a3681c8590b9dc25d1a561e8f5a9c995281012860901e3"}, "postgrex": {:hex, :postgrex, "0.16.5", "fcc4035cc90e23933c5d69a9cd686e329469446ef7abba2cf70f08e2c4b69810", [:mix], [{:connection, "~> 1.1", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "edead639dc6e882618c01d8fc891214c481ab9a3788dfe38dd5e37fd1d5fb2e8"}, "pot": {:hex, :pot, "1.0.2", "13abb849139fdc04ab8154986abbcb63bdee5de6ed2ba7e1713527e33df923dd", [:rebar3], [], "hexpm", "78fe127f5a4f5f919d6ea5a2a671827bd53eb9d37e5b4128c0ad3df99856c2e0"}, - "quack": {:hex, :quack, "0.1.1", "cca7b4da1a233757fdb44b3334fce80c94785b3ad5a602053b7a002b5a8967bf", [:mix], [{:poison, ">= 1.0.0", [hex: :poison, repo: "hexpm", optional: false]}, {:tesla, "~> 1.2.0", [hex: :tesla, repo: "hexpm", optional: false]}], "hexpm", "d736bfa7444112eb840027bb887832a0e403a4a3437f48028c3b29a2dbbd2543"}, "ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"}, "recon": {:hex, :recon, "2.5.2", "cba53fa8db83ad968c9a652e09c3ed7ddcc4da434f27c3eaa9ca47ffb2b1ff03", [:mix, :rebar3], [], "hexpm", "2c7523c8dee91dff41f6b3d63cba2bd49eb6d2fe5bf1eec0df7f87eb5e230e1c"}, - "remote_ip": {:git, "https://git.pleroma.social/pleroma/remote_ip.git", "b647d0deecaa3acb140854fe4bda5b7e1dc6d1c8", [ref: "b647d0deecaa3acb140854fe4bda5b7e1dc6d1c8"]}, + "remote_ip": {:hex, :remote_ip, "1.1.0", "cb308841595d15df3f9073b7c39243a1dd6ca56e5020295cb012c76fbec50f2d", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "616ffdf66aaad6a72fc546dabf42eed87e2a99e97b09cbd92b10cc180d02ed74"}, "search_parser": {:git, "https://github.com/FloatingGhost/pleroma-contrib-search-parser.git", "08971a81e68686f9ac465cfb6661d51c5e4e1e7f", [ref: "08971a81e68686f9ac465cfb6661d51c5e4e1e7f"]}, "sleeplocks": {:hex, :sleeplocks, "1.1.2", "d45aa1c5513da48c888715e3381211c859af34bee9b8290490e10c90bb6ff0ca", [:rebar3], [], "hexpm", "9fe5d048c5b781d6305c1a3a0f40bb3dfc06f49bf40571f3d2d0c57eaa7f59a5"}, "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.6", "cf344f5692c82d2cd7554f5ec8fd961548d4fd09e7d22f5b62482e5aeaebd4b0", [:make, :mix, :rebar3], [], "hexpm", "bdb0d2471f453c88ff3908e7686f86f9be327d065cc1ec16fa4540197ea04680"}, "statistex": {:hex, :statistex, "1.0.0", "f3dc93f3c0c6c92e5f291704cf62b99b553253d7969e9a5fa713e5481cd858a5", [:mix], [], "hexpm", "ff9d8bee7035028ab4742ff52fc80a2aa35cece833cf5319009b52f1b5a86c27"}, "sweet_xml": {:hex, :sweet_xml, "0.7.3", "debb256781c75ff6a8c5cbf7981146312b66f044a2898f453709a53e5031b45b", [:mix], [], "hexpm", "e110c867a1b3fe74bfc7dd9893aa851f0eed5518d0d7cad76d7baafd30e4f5ba"}, - "swoosh": {:hex, :swoosh, "1.8.2", "af9a22ab2c0d20b266f61acca737fa11a121902de9466a39e91bacdce012101c", [:mix], [{:cowboy, "~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:ex_aws, "~> 2.1", [hex: :ex_aws, repo: "hexpm", optional: true]}, {:finch, "~> 0.6", [hex: :finch, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13 or ~> 1.0", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "d058ba750eafadb6c09a84a352c14c5d1eeeda6e84945fcc95785b7f3067b7db"}, + "swoosh": {:hex, :swoosh, "1.8.3", "733357d9a65da19c162171f08d1e42a6259236cf44d02a64711b776afbbbaa78", [:mix], [{:cowboy, "~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:ex_aws, "~> 2.1", [hex: :ex_aws, repo: "hexpm", optional: true]}, {:finch, "~> 0.6", [hex: :finch, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13 or ~> 1.0", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c699abbac7a296c205055a7501c5d5261320ea1f08bde2392699a9e899815bc7"}, "syslog": {:hex, :syslog, "1.1.0", "6419a232bea84f07b56dc575225007ffe34d9fdc91abe6f1b2f254fd71d8efc2", [:rebar3], [], "hexpm", "4c6a41373c7e20587be33ef841d3de6f3beba08519809329ecc4d27b15b659e1"}, "table_rex": {:hex, :table_rex, "3.1.1", "0c67164d1714b5e806d5067c1e96ff098ba7ae79413cc075973e17c38a587caa", [:mix], [], "hexpm", "678a23aba4d670419c23c17790f9dcd635a4a89022040df7d5d772cb21012490"}, "telemetry": {:hex, :telemetry, "0.4.3", "a06428a514bdbc63293cd9a6263aad00ddeb66f608163bdec7c8995784080818", [:rebar3], [], "hexpm", "eb72b8365ffda5bed68a620d1da88525e326cb82a75ee61354fc24b844768041"}, diff --git a/test/credo/check/consistency/file_location.ex b/test/credo/check/consistency/file_location.ex index abc55fffc..a457c59a6 100644 --- a/test/credo/check/consistency/file_location.ex +++ b/test/credo/check/consistency/file_location.ex @@ -163,4 +163,8 @@ defp error(issue_meta, module, expected_file) do line_no: 1 ) end + + defp append_issues_and_timings(_issues, exec) do + exec + end end diff --git a/test/pleroma/signature_test.exs b/test/pleroma/signature_test.exs index e3ae36b46..59674bbc0 100644 --- a/test/pleroma/signature_test.exs +++ b/test/pleroma/signature_test.exs @@ -116,7 +116,7 @@ test "it deduces the actor id for gotoSocial" do test "it calls webfinger for 'acct:' accounts" do with_mock(Pleroma.Web.WebFinger, - finger: fn _ -> %{"ap_id" => "https://gensokyo.2hu/users/raymoo"} end + finger: fn _ -> {:ok, %{"ap_id" => "https://gensokyo.2hu/users/raymoo"}} end ) do assert Signature.key_id_to_actor_id("acct:raymoo@gensokyo.2hu") == {:ok, "https://gensokyo.2hu/users/raymoo"} diff --git a/test/pleroma/web/admin_api/controllers/admin_api_controller_test.exs b/test/pleroma/web/admin_api/controllers/admin_api_controller_test.exs index 7c001ada3..e423b2311 100644 --- a/test/pleroma/web/admin_api/controllers/admin_api_controller_test.exs +++ b/test/pleroma/web/admin_api/controllers/admin_api_controller_test.exs @@ -41,15 +41,16 @@ test "with valid `admin_token` query parameter, skips OAuth scopes check" do user = insert(:user) - conn = get(build_conn(), "/api/pleroma/admin/users/#{user.nickname}?admin_token=password123") + conn = + get(build_conn(), "/api/v1/pleroma/admin/users/#{user.nickname}?admin_token=password123") assert json_response(conn, 200) end - test "GET /api/pleroma/admin/users/:nickname requires admin:read:accounts or broader scope", + test "GET /api/v1/pleroma/admin/users/:nickname requires admin:read:accounts or broader scope", %{admin: admin} do user = insert(:user) - url = "/api/pleroma/admin/users/#{user.nickname}" + url = "/api/v1/pleroma/admin/users/#{user.nickname}" good_token1 = insert(:oauth_token, user: admin, scopes: ["admin"]) good_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read"]) @@ -90,7 +91,7 @@ test "GET /api/pleroma/admin/users/:nickname requires admin:read:accounts or bro end end - describe "PUT /api/pleroma/admin/users/tag" do + describe "PUT /api/v1/pleroma/admin/users/tag" do setup %{conn: conn} do user1 = insert(:user, %{tags: ["x"]}) user2 = insert(:user, %{tags: ["y"]}) @@ -100,7 +101,7 @@ test "GET /api/pleroma/admin/users/:nickname requires admin:read:accounts or bro conn |> put_req_header("accept", "application/json") |> put( - "/api/pleroma/admin/users/tag?nicknames[]=#{user1.nickname}&nicknames[]=" <> + "/api/v1/pleroma/admin/users/tag?nicknames[]=#{user1.nickname}&nicknames[]=" <> "#{user2.nickname}&tags[]=foo&tags[]=bar" ) @@ -136,7 +137,7 @@ test "it does not modify tags of not specified users", %{conn: conn, user3: user end end - describe "DELETE /api/pleroma/admin/users/tag" do + describe "DELETE /api/v1/pleroma/admin/users/tag" do setup %{conn: conn} do user1 = insert(:user, %{tags: ["x"]}) user2 = insert(:user, %{tags: ["y", "z"]}) @@ -146,7 +147,7 @@ test "it does not modify tags of not specified users", %{conn: conn, user3: user conn |> put_req_header("accept", "application/json") |> delete( - "/api/pleroma/admin/users/tag?nicknames[]=#{user1.nickname}&nicknames[]=" <> + "/api/v1/pleroma/admin/users/tag?nicknames[]=#{user1.nickname}&nicknames[]=" <> "#{user2.nickname}&tags[]=x&tags[]=z" ) @@ -182,12 +183,12 @@ test "it does not modify tags of not specified users", %{conn: conn, user3: user end end - describe "/api/pleroma/admin/users/:nickname/permission_group" do + describe "/api/v1/pleroma/admin/users/:nickname/permission_group" do test "GET is giving user_info", %{admin: admin, conn: conn} do conn = conn |> put_req_header("accept", "application/json") - |> get("/api/pleroma/admin/users/#{admin.nickname}/permission_group/") + |> get("/api/v1/pleroma/admin/users/#{admin.nickname}/permission_group/") assert json_response(conn, 200) == %{ "is_admin" => true, @@ -201,7 +202,7 @@ test "/:right POST, can add to a permission group", %{admin: admin, conn: conn} conn = conn |> put_req_header("accept", "application/json") - |> post("/api/pleroma/admin/users/#{user.nickname}/permission_group/admin") + |> post("/api/v1/pleroma/admin/users/#{user.nickname}/permission_group/admin") assert json_response(conn, 200) == %{ "is_admin" => true @@ -220,7 +221,7 @@ test "/:right POST, can add to a permission group (multiple)", %{admin: admin, c conn = conn |> put_req_header("accept", "application/json") - |> post("/api/pleroma/admin/users/permission_group/admin", %{ + |> post("/api/v1/pleroma/admin/users/permission_group/admin", %{ nicknames: [user_one.nickname, user_two.nickname] }) @@ -238,7 +239,7 @@ test "/:right DELETE, can remove from a permission group", %{admin: admin, conn: conn = conn |> put_req_header("accept", "application/json") - |> delete("/api/pleroma/admin/users/#{user.nickname}/permission_group/admin") + |> delete("/api/v1/pleroma/admin/users/#{user.nickname}/permission_group/admin") assert json_response(conn, 200) == %{"is_admin" => false} @@ -258,7 +259,7 @@ test "/:right DELETE, can remove from a permission group (multiple)", %{ conn = conn |> put_req_header("accept", "application/json") - |> delete("/api/pleroma/admin/users/permission_group/admin", %{ + |> delete("/api/v1/pleroma/admin/users/permission_group/admin", %{ nicknames: [user_one.nickname, user_two.nickname] }) @@ -271,13 +272,13 @@ test "/:right DELETE, can remove from a permission group (multiple)", %{ end end - test "/api/pleroma/admin/users/:nickname/password_reset", %{conn: conn} do + test "/api/v1/pleroma/admin/users/:nickname/password_reset", %{conn: conn} do user = insert(:user) conn = conn |> put_req_header("accept", "application/json") - |> get("/api/pleroma/admin/users/#{user.nickname}/password_reset") + |> get("/api/v1/pleroma/admin/users/#{user.nickname}/password_reset") resp = json_response(conn, 200) @@ -296,7 +297,7 @@ test "returns 200 and disable 2fa", %{conn: conn} do response = conn - |> put("/api/pleroma/admin/users/disable_mfa", %{nickname: user.nickname}) + |> put("/api/v1/pleroma/admin/users/disable_mfa", %{nickname: user.nickname}) |> json_response(200) assert response == user.nickname @@ -309,19 +310,19 @@ test "returns 200 and disable 2fa", %{conn: conn} do test "returns 404 if user not found", %{conn: conn} do response = conn - |> put("/api/pleroma/admin/users/disable_mfa", %{nickname: "nickname"}) + |> put("/api/v1/pleroma/admin/users/disable_mfa", %{nickname: "nickname"}) |> json_response(404) assert response == %{"error" => "Not found"} end end - describe "GET /api/pleroma/admin/restart" do + describe "GET /api/v1/pleroma/admin/restart" do setup do: clear_config(:configurable_from_database, true) test "pleroma restarts", %{conn: conn} do capture_log(fn -> - assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) == %{} + assert conn |> get("/api/v1/pleroma/admin/restart") |> json_response(200) == %{} end) =~ "pleroma restarted" refute Restarter.Pleroma.need_reboot?() @@ -330,19 +331,19 @@ test "pleroma restarts", %{conn: conn} do test "need_reboot flag", %{conn: conn} do assert conn - |> get("/api/pleroma/admin/need_reboot") + |> get("/api/v1/pleroma/admin/need_reboot") |> json_response(200) == %{"need_reboot" => false} Restarter.Pleroma.need_reboot() assert conn - |> get("/api/pleroma/admin/need_reboot") + |> get("/api/v1/pleroma/admin/need_reboot") |> json_response(200) == %{"need_reboot" => true} on_exit(fn -> Restarter.Pleroma.refresh() end) end - describe "GET /api/pleroma/admin/users/:nickname/statuses" do + describe "GET /api/v1/pleroma/admin/users/:nickname/statuses" do setup do user = insert(:user) @@ -354,7 +355,7 @@ test "need_reboot flag", %{conn: conn} do end test "renders user's statuses", %{conn: conn, user: user} do - conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses") + conn = get(conn, "/api/v1/pleroma/admin/users/#{user.nickname}/statuses") assert %{"total" => 3, "activities" => activities} = json_response(conn, 200) assert length(activities) == 3 @@ -363,12 +364,12 @@ test "renders user's statuses", %{conn: conn, user: user} do test "renders user's statuses with pagination", %{conn: conn, user: user} do %{"total" => 3, "activities" => [activity1]} = conn - |> get("/api/pleroma/admin/users/#{user.nickname}/statuses?page_size=1&page=1") + |> get("/api/v1/pleroma/admin/users/#{user.nickname}/statuses?page_size=1&page=1") |> json_response(200) %{"total" => 3, "activities" => [activity2]} = conn - |> get("/api/pleroma/admin/users/#{user.nickname}/statuses?page_size=1&page=2") + |> get("/api/v1/pleroma/admin/users/#{user.nickname}/statuses?page_size=1&page=2") |> json_response(200) refute activity1 == activity2 @@ -381,7 +382,7 @@ test "doesn't return private statuses by default", %{conn: conn, user: user} do %{"total" => 4, "activities" => activities} = conn - |> get("/api/pleroma/admin/users/#{user.nickname}/statuses") + |> get("/api/v1/pleroma/admin/users/#{user.nickname}/statuses") |> json_response(200) assert length(activities) == 4 @@ -394,7 +395,7 @@ test "returns private statuses with godmode on", %{conn: conn, user: user} do %{"total" => 5, "activities" => activities} = conn - |> get("/api/pleroma/admin/users/#{user.nickname}/statuses?godmode=true") + |> get("/api/v1/pleroma/admin/users/#{user.nickname}/statuses?godmode=true") |> json_response(200) assert length(activities) == 5 @@ -407,19 +408,19 @@ test "excludes reblogs by default", %{conn: conn, user: user} do assert %{"total" => 0, "activities" => []} == conn - |> get("/api/pleroma/admin/users/#{other_user.nickname}/statuses") + |> get("/api/v1/pleroma/admin/users/#{other_user.nickname}/statuses") |> json_response(200) assert %{"total" => 1, "activities" => [_]} = conn |> get( - "/api/pleroma/admin/users/#{other_user.nickname}/statuses?with_reblogs=true" + "/api/v1/pleroma/admin/users/#{other_user.nickname}/statuses?with_reblogs=true" ) |> json_response(200) end end - describe "GET /api/pleroma/admin/moderation_log" do + describe "GET /api/v1/pleroma/admin/moderation_log" do setup do moderator = insert(:user, is_moderator: true) @@ -453,7 +454,7 @@ test "returns the log", %{conn: conn, admin: admin} do inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second) }) - conn = get(conn, "/api/pleroma/admin/moderation_log") + conn = get(conn, "/api/v1/pleroma/admin/moderation_log") response = json_response(conn, 200) [first_entry, second_entry] = response["items"] @@ -497,7 +498,7 @@ test "returns the log with pagination", %{conn: conn, admin: admin} do inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second) }) - conn1 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=1") + conn1 = get(conn, "/api/v1/pleroma/admin/moderation_log?page_size=1&page=1") response1 = json_response(conn1, 200) [first_entry] = response1["items"] @@ -509,7 +510,7 @@ test "returns the log with pagination", %{conn: conn, admin: admin} do assert first_entry["message"] == "@#{admin.nickname} unfollowed relay: https://example.org/relay" - conn2 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=2") + conn2 = get(conn, "/api/v1/pleroma/admin/moderation_log?page_size=1&page=2") response2 = json_response(conn2, 200) [second_entry] = response2["items"] @@ -555,7 +556,7 @@ test "filters log by date", %{conn: conn, admin: admin} do conn1 = get( conn, - "/api/pleroma/admin/moderation_log?start_date=#{second_date}" + "/api/v1/pleroma/admin/moderation_log?start_date=#{second_date}" ) response1 = json_response(conn1, 200) @@ -593,7 +594,7 @@ test "returns log filtered by user", %{conn: conn, admin: admin, moderator: mode } }) - conn1 = get(conn, "/api/pleroma/admin/moderation_log?user_id=#{moderator.id}") + conn1 = get(conn, "/api/v1/pleroma/admin/moderation_log?user_id=#{moderator.id}") response1 = json_response(conn1, 200) [first_entry] = response1["items"] @@ -615,7 +616,7 @@ test "returns log filtered by search", %{conn: conn, moderator: moderator} do target: "https://example.org/relay" }) - conn1 = get(conn, "/api/pleroma/admin/moderation_log?search=unfo") + conn1 = get(conn, "/api/v1/pleroma/admin/moderation_log?search=unfo") response1 = json_response(conn1, 200) [first_entry] = response1["items"] @@ -631,7 +632,7 @@ test "gets a remote users when [:instance, :limit_to_local_content] is set to :u %{conn: conn} do clear_config(Pleroma.Config.get([:instance, :limit_to_local_content]), :unauthenticated) user = insert(:user, %{local: false, nickname: "u@peer1.com"}) - conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials") + conn = get(conn, "/api/v1/pleroma/admin/users/#{user.nickname}/credentials") assert json_response(conn, 200) end @@ -639,7 +640,7 @@ test "gets a remote users when [:instance, :limit_to_local_content] is set to :u describe "GET /users/:nickname/credentials" do test "gets the user credentials", %{conn: conn} do user = insert(:user) - conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials") + conn = get(conn, "/api/v1/pleroma/admin/users/#{user.nickname}/credentials") response = assert json_response(conn, 200) assert response["email"] == user.email @@ -651,7 +652,7 @@ test "returns 403 if requested by a non-admin" do conn = build_conn() |> assign(:user, user) - |> get("/api/pleroma/admin/users/#{user.nickname}/credentials") + |> get("/api/v1/pleroma/admin/users/#{user.nickname}/credentials") assert json_response(conn, :forbidden) end @@ -667,7 +668,7 @@ test "changes password and email", %{conn: conn, admin: admin, user: user} do assert user.password_reset_pending == false conn = - patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{ + patch(conn, "/api/v1/pleroma/admin/users/#{user.nickname}/credentials", %{ "password" => "new_password", "email" => "new_email@example.com", "name" => "new_name" @@ -697,7 +698,7 @@ test "returns 403 if requested by a non-admin", %{user: user} do conn = build_conn() |> assign(:user, user) - |> patch("/api/pleroma/admin/users/#{user.nickname}/credentials", %{ + |> patch("/api/v1/pleroma/admin/users/#{user.nickname}/credentials", %{ "password" => "new_password", "email" => "new_email@example.com", "name" => "new_name" @@ -709,7 +710,7 @@ test "returns 403 if requested by a non-admin", %{user: user} do test "changes actor type from permitted list", %{conn: conn, user: user} do assert user.actor_type == "Person" - assert patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{ + assert patch(conn, "/api/v1/pleroma/admin/users/#{user.nickname}/credentials", %{ "actor_type" => "Service" }) |> json_response(200) == %{"status" => "success"} @@ -718,14 +719,14 @@ test "changes actor type from permitted list", %{conn: conn, user: user} do assert updated_user.actor_type == "Service" - assert patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{ + assert patch(conn, "/api/v1/pleroma/admin/users/#{user.nickname}/credentials", %{ "actor_type" => "Application" }) |> json_response(400) == %{"errors" => %{"actor_type" => "is invalid"}} end test "update non existing user", %{conn: conn} do - assert patch(conn, "/api/pleroma/admin/users/non-existing/credentials", %{ + assert patch(conn, "/api/v1/pleroma/admin/users/non-existing/credentials", %{ "password" => "new_password" }) |> json_response(404) == %{"error" => "Not found"} @@ -738,7 +739,9 @@ test "sets password_reset_pending to true", %{conn: conn} do assert user.password_reset_pending == false conn = - patch(conn, "/api/pleroma/admin/users/force_password_reset", %{nicknames: [user.nickname]}) + patch(conn, "/api/v1/pleroma/admin/users/force_password_reset", %{ + nicknames: [user.nickname] + }) assert empty_json_response(conn) == "" @@ -756,7 +759,7 @@ test "it confirms emails of two users", %{conn: conn, admin: admin} do refute second_user.is_confirmed ret_conn = - patch(conn, "/api/pleroma/admin/users/confirm_email", %{ + patch(conn, "/api/v1/pleroma/admin/users/confirm_email", %{ nicknames: [ first_user.nickname, second_user.nickname @@ -783,7 +786,7 @@ test "it resend emails for two users", %{conn: conn, admin: admin} do [first_user, second_user] = insert_pair(:user, is_confirmed: false) ret_conn = - patch(conn, "/api/pleroma/admin/users/resend_confirmation_email", %{ + patch(conn, "/api/v1/pleroma/admin/users/resend_confirmation_email", %{ nicknames: [ first_user.nickname, second_user.nickname @@ -804,7 +807,7 @@ test "it resend emails for two users", %{conn: conn, admin: admin} do end end - describe "/api/pleroma/admin/stats" do + describe "/api/v1/pleroma/admin/stats" do test "status visibility count", %{conn: conn} do user = insert(:user) CommonAPI.post(user, %{visibility: "public", status: "hey"}) @@ -813,7 +816,7 @@ test "status visibility count", %{conn: conn} do response = conn - |> get("/api/pleroma/admin/stats") + |> get("/api/v1/pleroma/admin/stats") |> json_response(200) assert %{"direct" => 0, "private" => 0, "public" => 1, "unlisted" => 2} = @@ -831,7 +834,7 @@ test "by instance", %{conn: conn} do response = conn - |> get("/api/pleroma/admin/stats", instance: instance2) + |> get("/api/v1/pleroma/admin/stats", instance: instance2) |> json_response(200) assert %{"direct" => 0, "private" => 1, "public" => 0, "unlisted" => 1} = @@ -839,7 +842,7 @@ test "by instance", %{conn: conn} do end end - describe "/api/pleroma/backups" do + describe "/api/v1/pleroma/backups" do test "it creates a backup", %{conn: conn} do admin = %{id: admin_id, nickname: admin_nickname} = insert(:user, is_admin: true) token = insert(:oauth_admin_token, user: admin) @@ -849,7 +852,7 @@ test "it creates a backup", %{conn: conn} do conn |> assign(:user, admin) |> assign(:token, token) - |> post("/api/pleroma/admin/backups", %{nickname: user.nickname}) + |> post("/api/v1/pleroma/admin/backups", %{nickname: user.nickname}) |> json_response(200) assert [backup] = Repo.all(Pleroma.User.Backup) @@ -890,7 +893,7 @@ test "it doesn't limit admins", %{conn: conn} do conn |> assign(:user, admin) |> assign(:token, token) - |> post("/api/pleroma/admin/backups", %{nickname: user.nickname}) + |> post("/api/v1/pleroma/admin/backups", %{nickname: user.nickname}) |> json_response(200) assert [_backup] = Repo.all(Pleroma.User.Backup) @@ -899,7 +902,7 @@ test "it doesn't limit admins", %{conn: conn} do conn |> assign(:user, admin) |> assign(:token, token) - |> post("/api/pleroma/admin/backups", %{nickname: user.nickname}) + |> post("/api/v1/pleroma/admin/backups", %{nickname: user.nickname}) |> json_response(200) assert Repo.aggregate(Pleroma.User.Backup, :count) == 2 diff --git a/test/pleroma/web/admin_api/controllers/frontend_controller_test.exs b/test/pleroma/web/admin_api/controllers/frontend_controller_test.exs index 200682ba9..c84624aff 100644 --- a/test/pleroma/web/admin_api/controllers/frontend_controller_test.exs +++ b/test/pleroma/web/admin_api/controllers/frontend_controller_test.exs @@ -30,11 +30,11 @@ defmodule Pleroma.Web.AdminAPI.FrontendControllerTest do {:ok, %{admin: admin, token: token, conn: conn}} end - describe "GET /api/pleroma/admin/frontends" do + describe "GET /api/v1/pleroma/admin/frontends" do test "it lists available frontends", %{conn: conn} do response = conn - |> get("/api/pleroma/admin/frontends") + |> get("/api/v1/pleroma/admin/frontends") |> json_response_and_validate_schema(:ok) assert Enum.map(response, & &1["name"]) == @@ -48,7 +48,7 @@ test "it lists available frontends when no frontend folder was created yet", %{c response = conn - |> get("/api/pleroma/admin/frontends") + |> get("/api/v1/pleroma/admin/frontends") |> json_response_and_validate_schema(:ok) assert Enum.map(response, & &1["name"]) == @@ -58,7 +58,7 @@ test "it lists available frontends when no frontend folder was created yet", %{c end end - describe "POST /api/pleroma/admin/frontends/install" do + describe "POST /api/v1/pleroma/admin/frontends/install" do test "from available frontends", %{conn: conn} do clear_config([:frontends, :available], %{ "pleroma" => %{ @@ -74,14 +74,14 @@ test "from available frontends", %{conn: conn} do conn |> put_req_header("content-type", "application/json") - |> post("/api/pleroma/admin/frontends/install", %{name: "pleroma"}) + |> post("/api/v1/pleroma/admin/frontends/install", %{name: "pleroma"}) |> json_response_and_validate_schema(:ok) assert File.exists?(Path.join([@dir, "frontends", "pleroma", "fantasy", "test.txt"])) response = conn - |> get("/api/pleroma/admin/frontends") + |> get("/api/v1/pleroma/admin/frontends") |> json_response_and_validate_schema(:ok) assert response == [ @@ -106,7 +106,7 @@ test "from a file", %{conn: conn} do conn |> put_req_header("content-type", "application/json") - |> post("/api/pleroma/admin/frontends/install", %{ + |> post("/api/v1/pleroma/admin/frontends/install", %{ name: "pleroma", file: "test/fixtures/tesla_mock/frontend.zip" }) @@ -122,7 +122,7 @@ test "from an URL", %{conn: conn} do conn |> put_req_header("content-type", "application/json") - |> post("/api/pleroma/admin/frontends/install", %{ + |> post("/api/v1/pleroma/admin/frontends/install", %{ name: "unknown", ref: "baka", build_url: "http://gensokyo.2hu/madeup.zip", @@ -141,7 +141,7 @@ test "failing returns an error", %{conn: conn} do result = conn |> put_req_header("content-type", "application/json") - |> post("/api/pleroma/admin/frontends/install", %{ + |> post("/api/v1/pleroma/admin/frontends/install", %{ name: "unknown", ref: "baka", build_url: "http://gensokyo.2hu/madeup.zip", diff --git a/test/pleroma/web/admin_api/controllers/instance_controller_test.exs b/test/pleroma/web/admin_api/controllers/instance_controller_test.exs index c78307fc8..08920a541 100644 --- a/test/pleroma/web/admin_api/controllers/instance_controller_test.exs +++ b/test/pleroma/web/admin_api/controllers/instance_controller_test.exs @@ -37,26 +37,28 @@ test "GET /instances/:instance/statuses", %{conn: conn} do activity = insert(:note_activity, user: user2) %{"total" => 2, "activities" => activities} = - conn |> get("/api/pleroma/admin/instances/archae.me/statuses") |> json_response(200) + conn |> get("/api/v1/pleroma/admin/instances/archae.me/statuses") |> json_response(200) assert length(activities) == 2 %{"total" => 1, "activities" => [_]} = - conn |> get("/api/pleroma/admin/instances/test.com/statuses") |> json_response(200) + conn |> get("/api/v1/pleroma/admin/instances/test.com/statuses") |> json_response(200) %{"total" => 0, "activities" => []} = - conn |> get("/api/pleroma/admin/instances/nonexistent.com/statuses") |> json_response(200) + conn + |> get("/api/v1/pleroma/admin/instances/nonexistent.com/statuses") + |> json_response(200) CommonAPI.repeat(activity.id, user) %{"total" => 2, "activities" => activities} = - conn |> get("/api/pleroma/admin/instances/archae.me/statuses") |> json_response(200) + conn |> get("/api/v1/pleroma/admin/instances/archae.me/statuses") |> json_response(200) assert length(activities) == 2 %{"total" => 3, "activities" => activities} = conn - |> get("/api/pleroma/admin/instances/archae.me/statuses?with_reblogs=true") + |> get("/api/v1/pleroma/admin/instances/archae.me/statuses?with_reblogs=true") |> json_response(200) assert length(activities) == 3 @@ -68,7 +70,7 @@ test "DELETE /instances/:instance", %{conn: conn} do response = conn - |> delete("/api/pleroma/admin/instances/lain.com") + |> delete("/api/v1/pleroma/admin/instances/lain.com") |> json_response(200) [:ok] = ObanHelpers.perform_all() diff --git a/test/pleroma/web/admin_api/controllers/instance_document_controller_test.exs b/test/pleroma/web/admin_api/controllers/instance_document_controller_test.exs index 4d388a1e2..97deb5f82 100644 --- a/test/pleroma/web/admin_api/controllers/instance_document_controller_test.exs +++ b/test/pleroma/web/admin_api/controllers/instance_document_controller_test.exs @@ -28,9 +28,9 @@ defmodule Pleroma.Web.AdminAPI.InstanceDocumentControllerTest do {:ok, %{admin: admin, token: token, conn: conn}} end - describe "GET /api/pleroma/admin/instance_document/:name" do + describe "GET /api/v1/pleroma/admin/instance_document/:name" do test "return the instance document url", %{conn: conn} do - conn = get(conn, "/api/pleroma/admin/instance_document/instance-panel") + conn = get(conn, "/api/v1/pleroma/admin/instance_document/instance-panel") assert content = html_response(conn, 200) assert String.contains?(content, @default_instance_panel) @@ -44,7 +44,7 @@ test "it returns 403 if requested by a non-admin" do build_conn() |> assign(:user, non_admin_user) |> assign(:token, token) - |> get("/api/pleroma/admin/instance_document/instance-panel") + |> get("/api/v1/pleroma/admin/instance_document/instance-panel") assert json_response(conn, :forbidden) end @@ -52,13 +52,13 @@ test "it returns 403 if requested by a non-admin" do test "it returns 404 if the instance document with the given name doesn't exist", %{ conn: conn } do - conn = get(conn, "/api/pleroma/admin/instance_document/1234") + conn = get(conn, "/api/v1/pleroma/admin/instance_document/1234") assert json_response_and_validate_schema(conn, 404) end end - describe "PATCH /api/pleroma/admin/instance_document/:name" do + describe "PATCH /api/v1/pleroma/admin/instance_document/:name" do test "uploads the instance document", %{conn: conn} do image = %Plug.Upload{ content_type: "text/html", @@ -69,7 +69,7 @@ test "uploads the instance document", %{conn: conn} do conn = conn |> put_req_header("content-type", "multipart/form-data") - |> patch("/api/pleroma/admin/instance_document/instance-panel", %{ + |> patch("/api/v1/pleroma/admin/instance_document/instance-panel", %{ "file" => image }) @@ -79,24 +79,24 @@ test "uploads the instance document", %{conn: conn} do end end - describe "DELETE /api/pleroma/admin/instance_document/:name" do + describe "DELETE /api/v1/pleroma/admin/instance_document/:name" do test "deletes the instance document", %{conn: conn} do File.mkdir!(@dir <> "/instance/") File.write!(@dir <> "/instance/panel.html", "Custom instance panel") conn_resp = conn - |> get("/api/pleroma/admin/instance_document/instance-panel") + |> get("/api/v1/pleroma/admin/instance_document/instance-panel") assert html_response(conn_resp, 200) == "Custom instance panel" conn - |> delete("/api/pleroma/admin/instance_document/instance-panel") + |> delete("/api/v1/pleroma/admin/instance_document/instance-panel") |> json_response_and_validate_schema(200) conn_resp = conn - |> get("/api/pleroma/admin/instance_document/instance-panel") + |> get("/api/v1/pleroma/admin/instance_document/instance-panel") assert content = html_response(conn_resp, 200) assert String.contains?(content, @default_instance_panel) diff --git a/test/pleroma/web/admin_api/controllers/invite_controller_test.exs b/test/pleroma/web/admin_api/controllers/invite_controller_test.exs index 6366061c8..d384c3580 100644 --- a/test/pleroma/web/admin_api/controllers/invite_controller_test.exs +++ b/test/pleroma/web/admin_api/controllers/invite_controller_test.exs @@ -22,7 +22,7 @@ defmodule Pleroma.Web.AdminAPI.InviteControllerTest do {:ok, %{admin: admin, token: token, conn: conn}} end - describe "POST /api/pleroma/admin/users/email_invite, with valid config" do + describe "POST /api/v1/pleroma/admin/users/email_invite, with valid config" do setup do: clear_config([:instance, :registrations_open], false) setup do: clear_config([:instance, :invites_enabled], true) @@ -33,7 +33,7 @@ test "sends invitation and returns 204", %{admin: admin, conn: conn} do conn = conn |> put_req_header("content-type", "application/json;charset=utf-8") - |> post("/api/pleroma/admin/users/email_invite", %{ + |> post("/api/v1/pleroma/admin/users/email_invite", %{ email: recipient_email, name: recipient_name }) @@ -71,7 +71,7 @@ test "it returns 403 if requested by a non-admin" do |> assign(:user, non_admin_user) |> assign(:token, token) |> put_req_header("content-type", "application/json;charset=utf-8") - |> post("/api/pleroma/admin/users/email_invite", %{ + |> post("/api/v1/pleroma/admin/users/email_invite", %{ email: "foo@bar.com", name: "JD" }) @@ -84,7 +84,7 @@ test "email with +", %{conn: conn, admin: admin} do conn |> put_req_header("content-type", "application/json;charset=utf-8") - |> post("/api/pleroma/admin/users/email_invite", %{email: recipient_email}) + |> post("/api/v1/pleroma/admin/users/email_invite", %{email: recipient_email}) |> json_response_and_validate_schema(:no_content) token_record = @@ -113,7 +113,7 @@ test "email with +", %{conn: conn, admin: admin} do end end - describe "POST /api/pleroma/admin/users/email_invite, with invalid config" do + describe "POST /api/v1/pleroma/admin/users/email_invite, with invalid config" do setup do: clear_config([:instance, :registrations_open]) setup do: clear_config([:instance, :invites_enabled]) @@ -124,7 +124,7 @@ test "it returns 500 if `invites_enabled` is not enabled", %{conn: conn} do conn = conn |> put_req_header("content-type", "application/json") - |> post("/api/pleroma/admin/users/email_invite", %{ + |> post("/api/v1/pleroma/admin/users/email_invite", %{ email: "foo@bar.com", name: "JD" }) @@ -143,7 +143,7 @@ test "it returns 500 if `registrations_open` is enabled", %{conn: conn} do conn = conn |> put_req_header("content-type", "application/json") - |> post("/api/pleroma/admin/users/email_invite", %{ + |> post("/api/v1/pleroma/admin/users/email_invite", %{ email: "foo@bar.com", name: "JD" }) @@ -156,12 +156,12 @@ test "it returns 500 if `registrations_open` is enabled", %{conn: conn} do end end - describe "POST /api/pleroma/admin/users/invite_token" do + describe "POST /api/v1/pleroma/admin/users/invite_token" do test "without options", %{conn: conn} do conn = conn |> put_req_header("content-type", "application/json") - |> post("/api/pleroma/admin/users/invite_token") + |> post("/api/v1/pleroma/admin/users/invite_token") invite_json = json_response_and_validate_schema(conn, 200) invite = UserInviteToken.find_by_token!(invite_json["token"]) @@ -175,7 +175,7 @@ test "with expires_at", %{conn: conn} do conn = conn |> put_req_header("content-type", "application/json") - |> post("/api/pleroma/admin/users/invite_token", %{ + |> post("/api/v1/pleroma/admin/users/invite_token", %{ "expires_at" => Date.to_string(Date.utc_today()) }) @@ -192,7 +192,7 @@ test "with max_use", %{conn: conn} do conn = conn |> put_req_header("content-type", "application/json") - |> post("/api/pleroma/admin/users/invite_token", %{"max_use" => 150}) + |> post("/api/v1/pleroma/admin/users/invite_token", %{"max_use" => 150}) invite_json = json_response_and_validate_schema(conn, 200) invite = UserInviteToken.find_by_token!(invite_json["token"]) @@ -206,7 +206,7 @@ test "with max use and expires_at", %{conn: conn} do conn = conn |> put_req_header("content-type", "application/json") - |> post("/api/pleroma/admin/users/invite_token", %{ + |> post("/api/v1/pleroma/admin/users/invite_token", %{ "max_use" => 150, "expires_at" => Date.to_string(Date.utc_today()) }) @@ -220,9 +220,9 @@ test "with max use and expires_at", %{conn: conn} do end end - describe "GET /api/pleroma/admin/users/invites" do + describe "GET /api/v1/pleroma/admin/users/invites" do test "no invites", %{conn: conn} do - conn = get(conn, "/api/pleroma/admin/users/invites") + conn = get(conn, "/api/v1/pleroma/admin/users/invites") assert json_response_and_validate_schema(conn, 200) == %{"invites" => []} end @@ -230,7 +230,7 @@ test "no invites", %{conn: conn} do test "with invite", %{conn: conn} do {:ok, invite} = UserInviteToken.create_invite() - conn = get(conn, "/api/pleroma/admin/users/invites") + conn = get(conn, "/api/v1/pleroma/admin/users/invites") assert json_response_and_validate_schema(conn, 200) == %{ "invites" => [ @@ -248,14 +248,14 @@ test "with invite", %{conn: conn} do end end - describe "POST /api/pleroma/admin/users/revoke_invite" do + describe "POST /api/v1/pleroma/admin/users/revoke_invite" do test "with token", %{conn: conn} do {:ok, invite} = UserInviteToken.create_invite() conn = conn |> put_req_header("content-type", "application/json") - |> post("/api/pleroma/admin/users/revoke_invite", %{"token" => invite.token}) + |> post("/api/v1/pleroma/admin/users/revoke_invite", %{"token" => invite.token}) assert json_response_and_validate_schema(conn, 200) == %{ "expires_at" => nil, @@ -272,7 +272,7 @@ test "with invalid token", %{conn: conn} do conn = conn |> put_req_header("content-type", "application/json") - |> post("/api/pleroma/admin/users/revoke_invite", %{"token" => "foo"}) + |> post("/api/v1/pleroma/admin/users/revoke_invite", %{"token" => "foo"}) assert json_response_and_validate_schema(conn, :not_found) == %{"error" => "Not found"} end diff --git a/test/pleroma/web/admin_api/controllers/media_proxy_cache_controller_test.exs b/test/pleroma/web/admin_api/controllers/media_proxy_cache_controller_test.exs index 1818c8a8e..30e941869 100644 --- a/test/pleroma/web/admin_api/controllers/media_proxy_cache_controller_test.exs +++ b/test/pleroma/web/admin_api/controllers/media_proxy_cache_controller_test.exs @@ -28,7 +28,7 @@ defmodule Pleroma.Web.AdminAPI.MediaProxyCacheControllerTest do {:ok, %{admin: admin, token: token, conn: conn}} end - describe "GET /api/pleroma/admin/media_proxy_caches" do + describe "GET /api/v1/pleroma/admin/media_proxy_caches" do test "shows banned MediaProxy URLs", %{conn: conn} do MediaProxy.put_in_banned_urls([ "http://localhost:4001/media/a688346.jpg", @@ -41,7 +41,7 @@ test "shows banned MediaProxy URLs", %{conn: conn} do response = conn - |> get("/api/pleroma/admin/media_proxy_caches?page_size=2") + |> get("/api/v1/pleroma/admin/media_proxy_caches?page_size=2") |> json_response_and_validate_schema(200) assert response["page_size"] == 2 @@ -51,7 +51,7 @@ test "shows banned MediaProxy URLs", %{conn: conn} do response = conn - |> get("/api/pleroma/admin/media_proxy_caches?page_size=2&page=2") + |> get("/api/v1/pleroma/admin/media_proxy_caches?page_size=2&page=2") |> json_response_and_validate_schema(200) assert response["page_size"] == 2 @@ -61,7 +61,7 @@ test "shows banned MediaProxy URLs", %{conn: conn} do response = conn - |> get("/api/pleroma/admin/media_proxy_caches?page_size=2&page=3") + |> get("/api/v1/pleroma/admin/media_proxy_caches?page_size=2&page=3") |> json_response_and_validate_schema(200) results = results ++ response["urls"] @@ -89,7 +89,7 @@ test "search banned MediaProxy URLs", %{conn: conn} do response = conn - |> get("/api/pleroma/admin/media_proxy_caches?page_size=2&query=F44") + |> get("/api/v1/pleroma/admin/media_proxy_caches?page_size=2&query=F44") |> json_response_and_validate_schema(200) assert response["urls"] |> Enum.sort() == [ @@ -102,7 +102,7 @@ test "search banned MediaProxy URLs", %{conn: conn} do end end - describe "POST /api/pleroma/admin/media_proxy_caches/delete" do + describe "POST /api/v1/pleroma/admin/media_proxy_caches/delete" do test "deleted MediaProxy URLs from banned", %{conn: conn} do MediaProxy.put_in_banned_urls([ "http://localhost:4001/media/a688346.jpg", @@ -111,7 +111,7 @@ test "deleted MediaProxy URLs from banned", %{conn: conn} do conn |> put_req_header("content-type", "application/json") - |> post("/api/pleroma/admin/media_proxy_caches/delete", %{ + |> post("/api/v1/pleroma/admin/media_proxy_caches/delete", %{ urls: ["http://localhost:4001/media/a688346.jpg"] }) |> json_response_and_validate_schema(200) @@ -121,7 +121,7 @@ test "deleted MediaProxy URLs from banned", %{conn: conn} do end end - describe "POST /api/pleroma/admin/media_proxy_caches/purge" do + describe "POST /api/v1/pleroma/admin/media_proxy_caches/purge" do test "perform invalidates cache of MediaProxy", %{conn: conn} do urls = [ "http://example.com/media/a688346.jpg", @@ -136,7 +136,7 @@ test "perform invalidates cache of MediaProxy", %{conn: conn} do ] do conn |> put_req_header("content-type", "application/json") - |> post("/api/pleroma/admin/media_proxy_caches/purge", %{urls: urls, ban: false}) + |> post("/api/v1/pleroma/admin/media_proxy_caches/purge", %{urls: urls, ban: false}) |> json_response_and_validate_schema(200) refute MediaProxy.in_banned_urls("http://example.com/media/a688346.jpg") @@ -154,7 +154,7 @@ test "perform invalidates cache of MediaProxy and adds url to banned", %{conn: c conn |> put_req_header("content-type", "application/json") |> post( - "/api/pleroma/admin/media_proxy_caches/purge", + "/api/v1/pleroma/admin/media_proxy_caches/purge", %{urls: urls, ban: true} ) |> json_response_and_validate_schema(200) diff --git a/test/pleroma/web/admin_api/controllers/o_auth_app_controller_test.exs b/test/pleroma/web/admin_api/controllers/o_auth_app_controller_test.exs index d9b25719a..62f156993 100644 --- a/test/pleroma/web/admin_api/controllers/o_auth_app_controller_test.exs +++ b/test/pleroma/web/admin_api/controllers/o_auth_app_controller_test.exs @@ -22,12 +22,12 @@ defmodule Pleroma.Web.AdminAPI.OAuthAppControllerTest do {:ok, %{admin: admin, token: token, conn: conn}} end - describe "POST /api/pleroma/admin/oauth_app" do + describe "POST /api/v1/pleroma/admin/oauth_app" do test "errors", %{conn: conn} do response = conn |> put_req_header("content-type", "application/json") - |> post("/api/pleroma/admin/oauth_app", %{}) + |> post("/api/v1/pleroma/admin/oauth_app", %{}) |> json_response_and_validate_schema(400) assert %{ @@ -42,7 +42,7 @@ test "success", %{conn: conn} do response = conn |> put_req_header("content-type", "application/json") - |> post("/api/pleroma/admin/oauth_app", %{ + |> post("/api/v1/pleroma/admin/oauth_app", %{ name: app_name, redirect_uris: base_url }) @@ -64,7 +64,7 @@ test "with trusted", %{conn: conn} do response = conn |> put_req_header("content-type", "application/json") - |> post("/api/pleroma/admin/oauth_app", %{ + |> post("/api/v1/pleroma/admin/oauth_app", %{ name: app_name, redirect_uris: base_url, trusted: true @@ -81,7 +81,7 @@ test "with trusted", %{conn: conn} do end end - describe "GET /api/pleroma/admin/oauth_app" do + describe "GET /api/v1/pleroma/admin/oauth_app" do setup do app = insert(:oauth_app) {:ok, app: app} @@ -90,7 +90,7 @@ test "with trusted", %{conn: conn} do test "list", %{conn: conn} do response = conn - |> get("/api/pleroma/admin/oauth_app") + |> get("/api/v1/pleroma/admin/oauth_app") |> json_response_and_validate_schema(200) assert %{"apps" => apps, "count" => count, "page_size" => _} = response @@ -104,7 +104,7 @@ test "with page size", %{conn: conn} do response = conn - |> get("/api/pleroma/admin/oauth_app?page_size=#{page_size}") + |> get("/api/v1/pleroma/admin/oauth_app?page_size=#{page_size}") |> json_response_and_validate_schema(200) assert %{"apps" => apps, "count" => _, "page_size" => ^page_size} = response @@ -115,7 +115,7 @@ test "with page size", %{conn: conn} do test "search by client name", %{conn: conn, app: app} do response = conn - |> get("/api/pleroma/admin/oauth_app?name=#{app.client_name}") + |> get("/api/v1/pleroma/admin/oauth_app?name=#{app.client_name}") |> json_response_and_validate_schema(200) assert %{"apps" => [returned], "count" => _, "page_size" => _} = response @@ -127,7 +127,7 @@ test "search by client name", %{conn: conn, app: app} do test "search by client id", %{conn: conn, app: app} do response = conn - |> get("/api/pleroma/admin/oauth_app?client_id=#{app.client_id}") + |> get("/api/v1/pleroma/admin/oauth_app?client_id=#{app.client_id}") |> json_response_and_validate_schema(200) assert %{"apps" => [returned], "count" => _, "page_size" => _} = response @@ -141,7 +141,7 @@ test "only trusted", %{conn: conn} do response = conn - |> get("/api/pleroma/admin/oauth_app?trusted=true") + |> get("/api/v1/pleroma/admin/oauth_app?trusted=true") |> json_response_and_validate_schema(200) assert %{"apps" => [returned], "count" => _, "page_size" => _} = response @@ -151,13 +151,13 @@ test "only trusted", %{conn: conn} do end end - describe "DELETE /api/pleroma/admin/oauth_app/:id" do + describe "DELETE /api/v1/pleroma/admin/oauth_app/:id" do test "with id", %{conn: conn} do app = insert(:oauth_app) response = conn - |> delete("/api/pleroma/admin/oauth_app/" <> to_string(app.id)) + |> delete("/api/v1/pleroma/admin/oauth_app/" <> to_string(app.id)) |> json_response_and_validate_schema(:no_content) assert response == "" @@ -166,14 +166,14 @@ test "with id", %{conn: conn} do test "with non existance id", %{conn: conn} do response = conn - |> delete("/api/pleroma/admin/oauth_app/0") + |> delete("/api/v1/pleroma/admin/oauth_app/0") |> json_response_and_validate_schema(:bad_request) assert response == "" end end - describe "PATCH /api/pleroma/admin/oauth_app/:id" do + describe "PATCH /api/v1/pleroma/admin/oauth_app/:id" do test "with id", %{conn: conn} do app = insert(:oauth_app) @@ -186,7 +186,7 @@ test "with id", %{conn: conn} do response = conn |> put_req_header("content-type", "application/json") - |> patch("/api/pleroma/admin/oauth_app/#{id}", %{ + |> patch("/api/v1/pleroma/admin/oauth_app/#{id}", %{ name: name, trusted: true, redirect_uris: url, @@ -210,7 +210,7 @@ test "without id", %{conn: conn} do response = conn |> put_req_header("content-type", "application/json") - |> patch("/api/pleroma/admin/oauth_app/0") + |> patch("/api/v1/pleroma/admin/oauth_app/0") |> json_response_and_validate_schema(:bad_request) assert response == "" diff --git a/test/pleroma/web/admin_api/controllers/relay_controller_test.exs b/test/pleroma/web/admin_api/controllers/relay_controller_test.exs index 11a480cc0..c86339dbd 100644 --- a/test/pleroma/web/admin_api/controllers/relay_controller_test.exs +++ b/test/pleroma/web/admin_api/controllers/relay_controller_test.exs @@ -34,7 +34,7 @@ test "POST /relay", %{conn: conn, admin: admin} do conn = conn |> put_req_header("content-type", "application/json") - |> post("/api/pleroma/admin/relay", %{ + |> post("/api/v1/pleroma/admin/relay", %{ relay_url: "http://mastodon.example.org/users/admin" }) @@ -58,7 +58,7 @@ test "GET /relay", %{conn: conn} do User.follow(relay_user, user) end) - conn = get(conn, "/api/pleroma/admin/relay") + conn = get(conn, "/api/v1/pleroma/admin/relay") assert json_response_and_validate_schema(conn, 200)["relays"] |> Enum.sort() == [ %{ @@ -72,14 +72,14 @@ test "GET /relay", %{conn: conn} do test "DELETE /relay", %{conn: conn, admin: admin} do conn |> put_req_header("content-type", "application/json") - |> post("/api/pleroma/admin/relay", %{ + |> post("/api/v1/pleroma/admin/relay", %{ relay_url: "http://mastodon.example.org/users/admin" }) conn = conn |> put_req_header("content-type", "application/json") - |> delete("/api/pleroma/admin/relay", %{ + |> delete("/api/v1/pleroma/admin/relay", %{ relay_url: "http://mastodon.example.org/users/admin" }) diff --git a/test/pleroma/web/admin_api/controllers/report_controller_test.exs b/test/pleroma/web/admin_api/controllers/report_controller_test.exs index 2d526527b..dd859f34f 100644 --- a/test/pleroma/web/admin_api/controllers/report_controller_test.exs +++ b/test/pleroma/web/admin_api/controllers/report_controller_test.exs @@ -25,7 +25,7 @@ defmodule Pleroma.Web.AdminAPI.ReportControllerTest do {:ok, %{admin: admin, token: token, conn: conn}} end - describe "GET /api/pleroma/admin/reports/:id" do + describe "GET /api/v1/pleroma/admin/reports/:id" do test "returns report by its id", %{conn: conn} do [reporter, target_user] = insert_pair(:user) activity = insert(:note_activity, user: target_user) @@ -39,13 +39,13 @@ test "returns report by its id", %{conn: conn} do conn |> put_req_header("content-type", "application/json") - |> post("/api/pleroma/admin/reports/#{report_id}/notes", %{ + |> post("/api/v1/pleroma/admin/reports/#{report_id}/notes", %{ content: "this is an admin note" }) response = conn - |> get("/api/pleroma/admin/reports/#{report_id}") + |> get("/api/v1/pleroma/admin/reports/#{report_id}") |> json_response_and_validate_schema(:ok) assert response["id"] == report_id @@ -55,13 +55,13 @@ test "returns report by its id", %{conn: conn} do end test "returns 404 when report id is invalid", %{conn: conn} do - conn = get(conn, "/api/pleroma/admin/reports/test") + conn = get(conn, "/api/v1/pleroma/admin/reports/test") assert json_response_and_validate_schema(conn, :not_found) == %{"error" => "Not found"} end end - describe "PATCH /api/pleroma/admin/reports" do + describe "PATCH /api/v1/pleroma/admin/reports" do setup do [reporter, target_user] = insert_pair(:user) activity = insert(:note_activity, user: target_user) @@ -94,7 +94,7 @@ test "requires admin:write:reports scope", %{conn: conn, id: id, admin: admin} d conn |> assign(:token, read_token) |> put_req_header("content-type", "application/json") - |> patch("/api/pleroma/admin/reports", %{ + |> patch("/api/v1/pleroma/admin/reports", %{ "reports" => [%{"state" => "resolved", "id" => id}] }) |> json_response_and_validate_schema(403) @@ -106,7 +106,7 @@ test "requires admin:write:reports scope", %{conn: conn, id: id, admin: admin} d conn |> assign(:token, write_token) |> put_req_header("content-type", "application/json") - |> patch("/api/pleroma/admin/reports", %{ + |> patch("/api/v1/pleroma/admin/reports", %{ "reports" => [%{"state" => "resolved", "id" => id}] }) |> json_response_and_validate_schema(:no_content) @@ -115,7 +115,7 @@ test "requires admin:write:reports scope", %{conn: conn, id: id, admin: admin} d test "mark report as resolved", %{conn: conn, id: id, admin: admin} do conn |> put_req_header("content-type", "application/json") - |> patch("/api/pleroma/admin/reports", %{ + |> patch("/api/v1/pleroma/admin/reports", %{ "reports" => [ %{"state" => "resolved", "id" => id} ] @@ -134,7 +134,7 @@ test "mark report as resolved", %{conn: conn, id: id, admin: admin} do test "closes report", %{conn: conn, id: id, admin: admin} do conn |> put_req_header("content-type", "application/json") - |> patch("/api/pleroma/admin/reports", %{ + |> patch("/api/v1/pleroma/admin/reports", %{ "reports" => [ %{"state" => "closed", "id" => id} ] @@ -154,7 +154,7 @@ test "returns 400 when state is unknown", %{conn: conn, id: id} do conn = conn |> put_req_header("content-type", "application/json") - |> patch("/api/pleroma/admin/reports", %{ + |> patch("/api/v1/pleroma/admin/reports", %{ "reports" => [ %{"state" => "test", "id" => id} ] @@ -168,7 +168,7 @@ test "returns 404 when report is not exist", %{conn: conn} do conn = conn |> put_req_header("content-type", "application/json") - |> patch("/api/pleroma/admin/reports", %{ + |> patch("/api/v1/pleroma/admin/reports", %{ "reports" => [ %{"state" => "closed", "id" => "test"} ] @@ -185,7 +185,7 @@ test "updates state of multiple reports", %{ } do conn |> put_req_header("content-type", "application/json") - |> patch("/api/pleroma/admin/reports", %{ + |> patch("/api/v1/pleroma/admin/reports", %{ "reports" => [ %{"state" => "resolved", "id" => id}, %{"state" => "closed", "id" => second_report_id} @@ -208,7 +208,7 @@ test "updates state of multiple reports", %{ end end - describe "GET /api/pleroma/admin/reports" do + describe "GET /api/v1/pleroma/admin/reports" do test "returns empty response when no reports created", %{conn: conn} do response = conn @@ -300,14 +300,14 @@ test "returns 403 when requested by a non-admin" do build_conn() |> assign(:user, user) |> assign(:token, token) - |> get("/api/pleroma/admin/reports") + |> get("/api/v1/pleroma/admin/reports") assert json_response(conn, :forbidden) == %{"error" => "User is not a staff member."} end test "returns 403 when requested by anonymous" do - conn = get(build_conn(), "/api/pleroma/admin/reports") + conn = get(build_conn(), "/api/v1/pleroma/admin/reports") assert json_response(conn, :forbidden) == %{ "error" => "Invalid credentials." @@ -315,7 +315,7 @@ test "returns 403 when requested by anonymous" do end end - describe "POST /api/pleroma/admin/reports/:id/notes" do + describe "POST /api/v1/pleroma/admin/reports/:id/notes" do setup %{conn: conn, admin: admin} do [reporter, target_user] = insert_pair(:user) activity = insert(:note_activity, user: target_user) @@ -329,13 +329,13 @@ test "returns 403 when requested by anonymous" do conn |> put_req_header("content-type", "application/json") - |> post("/api/pleroma/admin/reports/#{report_id}/notes", %{ + |> post("/api/v1/pleroma/admin/reports/#{report_id}/notes", %{ content: "this is disgusting!" }) conn |> put_req_header("content-type", "application/json") - |> post("/api/pleroma/admin/reports/#{report_id}/notes", %{ + |> post("/api/v1/pleroma/admin/reports/#{report_id}/notes", %{ content: "this is disgusting2!" }) @@ -356,7 +356,7 @@ test "it creates report note", %{admin_id: admin_id, report_id: report_id} do end test "it returns reports with notes", %{conn: conn, admin: admin} do - conn = get(conn, "/api/pleroma/admin/reports") + conn = get(conn, "/api/v1/pleroma/admin/reports") response = json_response_and_validate_schema(conn, 200) notes = hd(response["reports"])["notes"] @@ -379,7 +379,7 @@ test "it deletes the note", %{conn: conn, report_id: report_id} do assert ReportNote |> Repo.all() |> length() == 2 assert [note, _] = Repo.all(ReportNote) - delete(conn, "/api/pleroma/admin/reports/#{report_id}/notes/#{note.id}") + delete(conn, "/api/v1/pleroma/admin/reports/#{report_id}/notes/#{note.id}") assert ReportNote |> Repo.all() |> length() == 1 end diff --git a/test/pleroma/web/admin_api/controllers/status_controller_test.exs b/test/pleroma/web/admin_api/controllers/status_controller_test.exs index 3fdf23ba2..370a4953f 100644 --- a/test/pleroma/web/admin_api/controllers/status_controller_test.exs +++ b/test/pleroma/web/admin_api/controllers/status_controller_test.exs @@ -25,10 +25,10 @@ defmodule Pleroma.Web.AdminAPI.StatusControllerTest do {:ok, %{admin: admin, token: token, conn: conn}} end - describe "GET /api/pleroma/admin/statuses/:id" do + describe "GET /api/v1/pleroma/admin/statuses/:id" do test "not found", %{conn: conn} do assert conn - |> get("/api/pleroma/admin/statuses/not_found") + |> get("/api/v1/pleroma/admin/statuses/not_found") |> json_response_and_validate_schema(:not_found) end @@ -37,7 +37,7 @@ test "shows activity", %{conn: conn} do response = conn - |> get("/api/pleroma/admin/statuses/#{activity.id}") + |> get("/api/v1/pleroma/admin/statuses/#{activity.id}") |> json_response_and_validate_schema(200) assert response["id"] == activity.id @@ -52,7 +52,7 @@ test "shows activity", %{conn: conn} do end end - describe "PUT /api/pleroma/admin/statuses/:id" do + describe "PUT /api/v1/pleroma/admin/statuses/:id" do setup do activity = insert(:note_activity) @@ -63,7 +63,7 @@ test "toggle sensitive flag", %{conn: conn, id: id, admin: admin} do response = conn |> put_req_header("content-type", "application/json") - |> put("/api/pleroma/admin/statuses/#{id}", %{"sensitive" => "true"}) + |> put("/api/v1/pleroma/admin/statuses/#{id}", %{"sensitive" => "true"}) |> json_response_and_validate_schema(:ok) assert response["sensitive"] @@ -76,7 +76,7 @@ test "toggle sensitive flag", %{conn: conn, id: id, admin: admin} do response = conn |> put_req_header("content-type", "application/json") - |> put("/api/pleroma/admin/statuses/#{id}", %{"sensitive" => "false"}) + |> put("/api/v1/pleroma/admin/statuses/#{id}", %{"sensitive" => "false"}) |> json_response_and_validate_schema(:ok) refute response["sensitive"] @@ -86,7 +86,7 @@ test "change visibility flag", %{conn: conn, id: id, admin: admin} do response = conn |> put_req_header("content-type", "application/json") - |> put("/api/pleroma/admin/statuses/#{id}", %{visibility: "public"}) + |> put("/api/v1/pleroma/admin/statuses/#{id}", %{visibility: "public"}) |> json_response_and_validate_schema(:ok) assert response["visibility"] == "public" @@ -99,7 +99,7 @@ test "change visibility flag", %{conn: conn, id: id, admin: admin} do response = conn |> put_req_header("content-type", "application/json") - |> put("/api/pleroma/admin/statuses/#{id}", %{visibility: "private"}) + |> put("/api/v1/pleroma/admin/statuses/#{id}", %{visibility: "private"}) |> json_response_and_validate_schema(:ok) assert response["visibility"] == "private" @@ -107,7 +107,7 @@ test "change visibility flag", %{conn: conn, id: id, admin: admin} do response = conn |> put_req_header("content-type", "application/json") - |> put("/api/pleroma/admin/statuses/#{id}", %{visibility: "unlisted"}) + |> put("/api/v1/pleroma/admin/statuses/#{id}", %{visibility: "unlisted"}) |> json_response_and_validate_schema(:ok) assert response["visibility"] == "unlisted" @@ -117,14 +117,14 @@ test "returns 400 when visibility is unknown", %{conn: conn, id: id} do conn = conn |> put_req_header("content-type", "application/json") - |> put("/api/pleroma/admin/statuses/#{id}", %{visibility: "test"}) + |> put("/api/v1/pleroma/admin/statuses/#{id}", %{visibility: "test"}) assert %{"error" => "test - Invalid value for enum."} = json_response_and_validate_schema(conn, :bad_request) end end - describe "DELETE /api/pleroma/admin/statuses/:id" do + describe "DELETE /api/v1/pleroma/admin/statuses/:id" do setup do activity = insert(:note_activity) @@ -133,7 +133,7 @@ test "returns 400 when visibility is unknown", %{conn: conn, id: id} do test "deletes status", %{conn: conn, id: id, admin: admin} do conn - |> delete("/api/pleroma/admin/statuses/#{id}") + |> delete("/api/v1/pleroma/admin/statuses/#{id}") |> json_response_and_validate_schema(:ok) refute Activity.get_by_id(id) @@ -145,13 +145,13 @@ test "deletes status", %{conn: conn, id: id, admin: admin} do end test "returns 404 when the status does not exist", %{conn: conn} do - conn = delete(conn, "/api/pleroma/admin/statuses/test") + conn = delete(conn, "/api/v1/pleroma/admin/statuses/test") assert json_response_and_validate_schema(conn, :not_found) == %{"error" => "Not found"} end end - describe "GET /api/pleroma/admin/statuses" do + describe "GET /api/v1/pleroma/admin/statuses" do test "returns all public and unlisted statuses", %{conn: conn, admin: admin} do blocked = insert(:user) user = insert(:user) @@ -166,7 +166,7 @@ test "returns all public and unlisted statuses", %{conn: conn, admin: admin} do response = conn - |> get("/api/pleroma/admin/statuses") + |> get("/api/v1/pleroma/admin/statuses") |> json_response_and_validate_schema(200) refute "private" in Enum.map(response, & &1["visibility"]) @@ -181,7 +181,7 @@ test "returns only local statuses with local_only on", %{conn: conn} do response = conn - |> get("/api/pleroma/admin/statuses?local_only=true") + |> get("/api/v1/pleroma/admin/statuses?local_only=true") |> json_response_and_validate_schema(200) assert length(response) == 1 @@ -194,7 +194,7 @@ test "returns private and direct statuses with godmode on", %{conn: conn, admin: {:ok, _} = CommonAPI.post(user, %{status: ".", visibility: "private"}) {:ok, _} = CommonAPI.post(user, %{status: ".", visibility: "public"}) - conn = get(conn, "/api/pleroma/admin/statuses?godmode=true") + conn = get(conn, "/api/v1/pleroma/admin/statuses?godmode=true") assert json_response_and_validate_schema(conn, 200) |> length() == 3 end end diff --git a/test/pleroma/web/admin_api/controllers/user_controller_test.exs b/test/pleroma/web/admin_api/controllers/user_controller_test.exs index b199fa704..68876078d 100644 --- a/test/pleroma/web/admin_api/controllers/user_controller_test.exs +++ b/test/pleroma/web/admin_api/controllers/user_controller_test.exs @@ -42,15 +42,16 @@ test "with valid `admin_token` query parameter, skips OAuth scopes check" do user = insert(:user) - conn = get(build_conn(), "/api/pleroma/admin/users/#{user.nickname}?admin_token=password123") + conn = + get(build_conn(), "/api/v1/pleroma/admin/users/#{user.nickname}?admin_token=password123") assert json_response_and_validate_schema(conn, 200) end - test "GET /api/pleroma/admin/users/:nickname requires admin:read:accounts or broader scope", + test "GET /api/v1/pleroma/admin/users/:nickname requires admin:read:accounts or broader scope", %{admin: admin} do user = insert(:user) - url = "/api/pleroma/admin/users/#{user.nickname}" + url = "/api/v1/pleroma/admin/users/#{user.nickname}" good_token1 = insert(:oauth_token, user: admin, scopes: ["admin"]) good_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read"]) @@ -91,7 +92,7 @@ test "GET /api/pleroma/admin/users/:nickname requires admin:read:accounts or bro end end - describe "DELETE /api/pleroma/admin/users" do + describe "DELETE /api/v1/pleroma/admin/users" do test "single user", %{admin: admin, conn: conn} do clear_config([:instance, :federating], true) @@ -120,7 +121,7 @@ test "single user", %{admin: admin, conn: conn} do conn = conn |> put_req_header("accept", "application/json") - |> delete("/api/pleroma/admin/users?nickname=#{user.nickname}") + |> delete("/api/v1/pleroma/admin/users?nickname=#{user.nickname}") ObanHelpers.perform_all() @@ -156,7 +157,7 @@ test "multiple users", %{admin: admin, conn: conn} do conn |> put_req_header("accept", "application/json") |> put_req_header("content-type", "application/json") - |> delete("/api/pleroma/admin/users", %{ + |> delete("/api/v1/pleroma/admin/users", %{ nicknames: [user_one.nickname, user_two.nickname] }) |> json_response_and_validate_schema(200) @@ -170,13 +171,13 @@ test "multiple users", %{admin: admin, conn: conn} do end end - describe "/api/pleroma/admin/users" do + describe "/api/v1/pleroma/admin/users" do test "Create", %{conn: conn} do response = conn |> put_req_header("accept", "application/json") |> put_req_header("content-type", "application/json") - |> post("/api/pleroma/admin/users", %{ + |> post("/api/v1/pleroma/admin/users", %{ "users" => [ %{ "nickname" => "lain", @@ -207,7 +208,7 @@ test "Cannot create user with existing email", %{conn: conn} do conn |> put_req_header("accept", "application/json") |> put_req_header("content-type", "application/json") - |> post("/api/pleroma/admin/users", %{ + |> post("/api/v1/pleroma/admin/users", %{ "users" => [ %{ "nickname" => "lain", @@ -237,7 +238,7 @@ test "Cannot create user with existing nickname", %{conn: conn} do conn |> put_req_header("accept", "application/json") |> put_req_header("content-type", "application/json") - |> post("/api/pleroma/admin/users", %{ + |> post("/api/v1/pleroma/admin/users", %{ "users" => [ %{ "nickname" => user.nickname, @@ -267,7 +268,7 @@ test "Multiple user creation works in transaction", %{conn: conn} do conn |> put_req_header("accept", "application/json") |> put_req_header("content-type", "application/json") - |> post("/api/pleroma/admin/users", %{ + |> post("/api/v1/pleroma/admin/users", %{ "users" => [ %{ "nickname" => "newuser", @@ -307,11 +308,11 @@ test "Multiple user creation works in transaction", %{conn: conn} do end end - describe "/api/pleroma/admin/users/:nickname" do + describe "/api/v1/pleroma/admin/users/:nickname" do test "Show", %{conn: conn} do user = insert(:user) - conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}") + conn = get(conn, "/api/v1/pleroma/admin/users/#{user.nickname}") assert user_response(user) == json_response_and_validate_schema(conn, 200) end @@ -319,13 +320,13 @@ test "Show", %{conn: conn} do test "when the user doesn't exist", %{conn: conn} do user = build(:user) - conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}") + conn = get(conn, "/api/v1/pleroma/admin/users/#{user.nickname}") assert %{"error" => "Not found"} == json_response_and_validate_schema(conn, 404) end end - describe "/api/pleroma/admin/users/follow" do + describe "/api/v1/pleroma/admin/users/follow" do test "allows to force-follow another user", %{admin: admin, conn: conn} do user = insert(:user) follower = insert(:user) @@ -333,7 +334,7 @@ test "allows to force-follow another user", %{admin: admin, conn: conn} do conn |> put_req_header("accept", "application/json") |> put_req_header("content-type", "application/json") - |> post("/api/pleroma/admin/users/follow", %{ + |> post("/api/v1/pleroma/admin/users/follow", %{ "follower" => follower.nickname, "followed" => user.nickname }) @@ -350,7 +351,7 @@ test "allows to force-follow another user", %{admin: admin, conn: conn} do end end - describe "/api/pleroma/admin/users/unfollow" do + describe "/api/v1/pleroma/admin/users/unfollow" do test "allows to force-unfollow another user", %{admin: admin, conn: conn} do user = insert(:user) follower = insert(:user) @@ -360,7 +361,7 @@ test "allows to force-unfollow another user", %{admin: admin, conn: conn} do conn |> put_req_header("accept", "application/json") |> put_req_header("content-type", "application/json") - |> post("/api/pleroma/admin/users/unfollow", %{ + |> post("/api/v1/pleroma/admin/users/unfollow", %{ "follower" => follower.nickname, "followed" => user.nickname }) @@ -377,12 +378,12 @@ test "allows to force-unfollow another user", %{admin: admin, conn: conn} do end end - describe "GET /api/pleroma/admin/users" do + describe "GET /api/v1/pleroma/admin/users" do test "renders users array for the first page", %{conn: conn, admin: admin} do user = insert(:user, local: false, tags: ["foo", "bar"]) user2 = insert(:user, is_approved: false, registration_reason: "I'm a chill dude") - conn = get(conn, "/api/pleroma/admin/users?page=1") + conn = get(conn, "/api/v1/pleroma/admin/users?page=1") users = [ user_response( @@ -415,7 +416,7 @@ test "pagination works correctly with service users", %{conn: conn} do assert %{"count" => 26, "page_size" => 10, "users" => users1} = conn - |> get("/api/pleroma/admin/users?page=1&filters=", %{page_size: "10"}) + |> get("/api/v1/pleroma/admin/users?page=1&filters=", %{page_size: "10"}) |> json_response_and_validate_schema(200) assert Enum.count(users1) == 10 @@ -423,7 +424,7 @@ test "pagination works correctly with service users", %{conn: conn} do assert %{"count" => 26, "page_size" => 10, "users" => users2} = conn - |> get("/api/pleroma/admin/users?page=2&filters=", %{page_size: "10"}) + |> get("/api/v1/pleroma/admin/users?page=2&filters=", %{page_size: "10"}) |> json_response_and_validate_schema(200) assert Enum.count(users2) == 10 @@ -431,7 +432,7 @@ test "pagination works correctly with service users", %{conn: conn} do assert %{"count" => 26, "page_size" => 10, "users" => users3} = conn - |> get("/api/pleroma/admin/users?page=3&filters=", %{page_size: "10"}) + |> get("/api/v1/pleroma/admin/users?page=3&filters=", %{page_size: "10"}) |> json_response_and_validate_schema(200) assert Enum.count(users3) == 6 @@ -441,7 +442,7 @@ test "pagination works correctly with service users", %{conn: conn} do test "renders empty array for the second page", %{conn: conn} do insert(:user) - conn = get(conn, "/api/pleroma/admin/users?page=2") + conn = get(conn, "/api/v1/pleroma/admin/users?page=2") assert json_response_and_validate_schema(conn, 200) == %{ "count" => 2, @@ -453,7 +454,7 @@ test "renders empty array for the second page", %{conn: conn} do test "regular search", %{conn: conn} do user = insert(:user, nickname: "bob") - conn = get(conn, "/api/pleroma/admin/users?query=bo") + conn = get(conn, "/api/v1/pleroma/admin/users?query=bo") assert json_response_and_validate_schema(conn, 200) == %{ "count" => 1, @@ -466,7 +467,7 @@ test "search by domain", %{conn: conn} do user = insert(:user, nickname: "nickname@domain.com") insert(:user) - conn = get(conn, "/api/pleroma/admin/users?query=domain.com") + conn = get(conn, "/api/v1/pleroma/admin/users?query=domain.com") assert json_response_and_validate_schema(conn, 200) == %{ "count" => 1, @@ -479,7 +480,7 @@ test "search by full nickname", %{conn: conn} do user = insert(:user, nickname: "nickname@domain.com") insert(:user) - conn = get(conn, "/api/pleroma/admin/users?query=nickname@domain.com") + conn = get(conn, "/api/v1/pleroma/admin/users?query=nickname@domain.com") assert json_response_and_validate_schema(conn, 200) == %{ "count" => 1, @@ -492,7 +493,7 @@ test "search by display name", %{conn: conn} do user = insert(:user, name: "Display name") insert(:user) - conn = get(conn, "/api/pleroma/admin/users?name=display") + conn = get(conn, "/api/v1/pleroma/admin/users?name=display") assert json_response_and_validate_schema(conn, 200) == %{ "count" => 1, @@ -505,7 +506,7 @@ test "search by email", %{conn: conn} do user = insert(:user, email: "email@example.com") insert(:user) - conn = get(conn, "/api/pleroma/admin/users?email=email@example.com") + conn = get(conn, "/api/v1/pleroma/admin/users?email=email@example.com") assert json_response_and_validate_schema(conn, 200) == %{ "count" => 1, @@ -518,7 +519,7 @@ test "regular search with page size", %{conn: conn} do user = insert(:user, nickname: "aalice") user2 = insert(:user, nickname: "alice") - conn1 = get(conn, "/api/pleroma/admin/users?query=a&page_size=1&page=1") + conn1 = get(conn, "/api/v1/pleroma/admin/users?query=a&page_size=1&page=1") assert json_response_and_validate_schema(conn1, 200) == %{ "count" => 2, @@ -526,7 +527,7 @@ test "regular search with page size", %{conn: conn} do "users" => [user_response(user2)] } - conn2 = get(conn, "/api/pleroma/admin/users?query=a&page_size=1&page=2") + conn2 = get(conn, "/api/v1/pleroma/admin/users?query=a&page_size=1&page=2") assert json_response_and_validate_schema(conn2, 200) == %{ "count" => 2, @@ -546,7 +547,7 @@ test "only local users" do build_conn() |> assign(:user, admin) |> assign(:token, token) - |> get("/api/pleroma/admin/users?query=bo&filters=local") + |> get("/api/v1/pleroma/admin/users?query=bo&filters=local") assert json_response_and_validate_schema(conn, 200) == %{ "count" => 1, @@ -561,7 +562,7 @@ test "only local users with no query", %{conn: conn, admin: old_admin} do insert(:user, nickname: "bobb", local: false) - conn = get(conn, "/api/pleroma/admin/users?filters=local") + conn = get(conn, "/api/v1/pleroma/admin/users?filters=local") users = [ user_response(user), @@ -590,7 +591,7 @@ test "only unconfirmed users", %{conn: conn} do result = conn - |> get("/api/pleroma/admin/users?filters=unconfirmed") + |> get("/api/v1/pleroma/admin/users?filters=unconfirmed") |> json_response_and_validate_schema(200) users = @@ -614,7 +615,7 @@ test "only unapproved users", %{conn: conn} do insert(:user, nickname: "happyboy", is_approved: true) - conn = get(conn, "/api/pleroma/admin/users?filters=need_approval") + conn = get(conn, "/api/v1/pleroma/admin/users?filters=need_approval") users = [ user_response( @@ -635,7 +636,7 @@ test "load only admins", %{conn: conn, admin: admin} do insert(:user) insert(:user) - conn = get(conn, "/api/pleroma/admin/users?filters=is_admin") + conn = get(conn, "/api/v1/pleroma/admin/users?filters=is_admin") users = [ user_response(second_admin, %{ @@ -660,7 +661,7 @@ test "load only moderators", %{conn: conn} do insert(:user) insert(:user) - conn = get(conn, "/api/pleroma/admin/users?filters=is_moderator") + conn = get(conn, "/api/v1/pleroma/admin/users?filters=is_moderator") assert json_response_and_validate_schema(conn, 200) == %{ "count" => 1, @@ -739,7 +740,7 @@ test "load users with tags list", %{conn: conn} do insert(:user) insert(:user) - conn = get(conn, "/api/pleroma/admin/users?tags[]=first&tags[]=second") + conn = get(conn, "/api/v1/pleroma/admin/users?tags[]=first&tags[]=second") users = [ user_response(user2, %{"tags" => ["second"]}), @@ -762,7 +763,7 @@ test "`active` filters out users pending approval", %{token: token} do build_conn() |> assign(:user, token.user) |> assign(:token, token) - |> get("/api/pleroma/admin/users?filters=active") + |> get("/api/v1/pleroma/admin/users?filters=active") assert %{ "count" => 2, @@ -786,7 +787,7 @@ test "it works with multiple filters" do build_conn() |> assign(:user, admin) |> assign(:token, token) - |> get("/api/pleroma/admin/users?filters=deactivated,external") + |> get("/api/v1/pleroma/admin/users?filters=deactivated,external") assert json_response_and_validate_schema(conn, 200) == %{ "count" => 1, @@ -798,7 +799,7 @@ test "it works with multiple filters" do test "it omits relay user", %{admin: admin, conn: conn} do assert %User{} = Relay.get_actor() - conn = get(conn, "/api/pleroma/admin/users") + conn = get(conn, "/api/v1/pleroma/admin/users") assert json_response_and_validate_schema(conn, 200) == %{ "count" => 1, @@ -810,7 +811,7 @@ test "it omits relay user", %{admin: admin, conn: conn} do end end - test "PATCH /api/pleroma/admin/users/activate", %{admin: admin, conn: conn} do + test "PATCH /api/v1/pleroma/admin/users/activate", %{admin: admin, conn: conn} do user_one = insert(:user, is_active: false) user_two = insert(:user, is_active: false) @@ -818,7 +819,7 @@ test "PATCH /api/pleroma/admin/users/activate", %{admin: admin, conn: conn} do conn |> put_req_header("content-type", "application/json") |> patch( - "/api/pleroma/admin/users/activate", + "/api/v1/pleroma/admin/users/activate", %{nicknames: [user_one.nickname, user_two.nickname]} ) @@ -831,7 +832,7 @@ test "PATCH /api/pleroma/admin/users/activate", %{admin: admin, conn: conn} do "@#{admin.nickname} activated users: @#{user_one.nickname}, @#{user_two.nickname}" end - test "PATCH /api/pleroma/admin/users/deactivate", %{admin: admin, conn: conn} do + test "PATCH /api/v1/pleroma/admin/users/deactivate", %{admin: admin, conn: conn} do user_one = insert(:user, is_active: true) user_two = insert(:user, is_active: true) @@ -839,7 +840,7 @@ test "PATCH /api/pleroma/admin/users/deactivate", %{admin: admin, conn: conn} do conn |> put_req_header("content-type", "application/json") |> patch( - "/api/pleroma/admin/users/deactivate", + "/api/v1/pleroma/admin/users/deactivate", %{nicknames: [user_one.nickname, user_two.nickname]} ) @@ -852,7 +853,7 @@ test "PATCH /api/pleroma/admin/users/deactivate", %{admin: admin, conn: conn} do "@#{admin.nickname} deactivated users: @#{user_one.nickname}, @#{user_two.nickname}" end - test "PATCH /api/pleroma/admin/users/approve", %{admin: admin, conn: conn} do + test "PATCH /api/v1/pleroma/admin/users/approve", %{admin: admin, conn: conn} do user_one = insert(:user, is_approved: false) user_two = insert(:user, is_approved: false) @@ -860,7 +861,7 @@ test "PATCH /api/pleroma/admin/users/approve", %{admin: admin, conn: conn} do conn |> put_req_header("content-type", "application/json") |> patch( - "/api/pleroma/admin/users/approve", + "/api/v1/pleroma/admin/users/approve", %{nicknames: [user_one.nickname, user_two.nickname]} ) @@ -873,7 +874,7 @@ test "PATCH /api/pleroma/admin/users/approve", %{admin: admin, conn: conn} do "@#{admin.nickname} approved users: @#{user_one.nickname}, @#{user_two.nickname}" end - test "PATCH /api/pleroma/admin/users/suggest", %{admin: admin, conn: conn} do + test "PATCH /api/v1/pleroma/admin/users/suggest", %{admin: admin, conn: conn} do user1 = insert(:user, is_suggested: false) user2 = insert(:user, is_suggested: false) @@ -881,7 +882,7 @@ test "PATCH /api/pleroma/admin/users/suggest", %{admin: admin, conn: conn} do conn |> put_req_header("content-type", "application/json") |> patch( - "/api/pleroma/admin/users/suggest", + "/api/v1/pleroma/admin/users/suggest", %{nicknames: [user1.nickname, user2.nickname]} ) |> json_response_and_validate_schema(200) @@ -898,7 +899,7 @@ test "PATCH /api/pleroma/admin/users/suggest", %{admin: admin, conn: conn} do "@#{admin.nickname} added suggested users: @#{user1.nickname}, @#{user2.nickname}" end - test "PATCH /api/pleroma/admin/users/unsuggest", %{admin: admin, conn: conn} do + test "PATCH /api/v1/pleroma/admin/users/unsuggest", %{admin: admin, conn: conn} do user1 = insert(:user, is_suggested: true) user2 = insert(:user, is_suggested: true) @@ -906,7 +907,7 @@ test "PATCH /api/pleroma/admin/users/unsuggest", %{admin: admin, conn: conn} do conn |> put_req_header("content-type", "application/json") |> patch( - "/api/pleroma/admin/users/unsuggest", + "/api/v1/pleroma/admin/users/unsuggest", %{nicknames: [user1.nickname, user2.nickname]} ) |> json_response_and_validate_schema(200) @@ -923,13 +924,16 @@ test "PATCH /api/pleroma/admin/users/unsuggest", %{admin: admin, conn: conn} do "@#{admin.nickname} removed suggested users: @#{user1.nickname}, @#{user2.nickname}" end - test "PATCH /api/pleroma/admin/users/:nickname/toggle_activation", %{admin: admin, conn: conn} do + test "PATCH /api/v1/pleroma/admin/users/:nickname/toggle_activation", %{ + admin: admin, + conn: conn + } do user = insert(:user) conn = conn |> put_req_header("content-type", "application/json") - |> patch("/api/pleroma/admin/users/#{user.nickname}/toggle_activation") + |> patch("/api/v1/pleroma/admin/users/#{user.nickname}/toggle_activation") assert json_response_and_validate_schema(conn, 200) == user_response( diff --git a/test/pleroma/web/fallback_test.exs b/test/pleroma/web/fallback_test.exs index 512baf813..cf573cd00 100644 --- a/test/pleroma/web/fallback_test.exs +++ b/test/pleroma/web/fallback_test.exs @@ -72,12 +72,6 @@ test "GET /main/all", %{conn: conn} do end end - test "GET /api*path", %{conn: conn} do - assert conn - |> get("/api/foo") - |> json_response(404) == %{"error" => "Not implemented"} - end - test "GET /pleroma/admin -> /pleroma/admin/", %{conn: conn} do assert redirected_to(get(conn, "/pleroma/admin")) =~ "/pleroma/admin/" end diff --git a/test/pleroma/web/mastodon_api/controllers/status_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/status_controller_test.exs index cda4c9e03..d76db0c0d 100644 --- a/test/pleroma/web/mastodon_api/controllers/status_controller_test.exs +++ b/test/pleroma/web/mastodon_api/controllers/status_controller_test.exs @@ -38,7 +38,7 @@ test "posting a status does not increment reblog_count when relaying", %{conn: c response = conn |> put_req_header("content-type", "application/json") - |> post("api/v1/statuses", %{ + |> post("/api/v1/statuses", %{ "content_type" => "text/plain", "source" => "Pleroma FE", "status" => "Hello world", @@ -51,7 +51,7 @@ test "posting a status does not increment reblog_count when relaying", %{conn: c response = conn - |> get("api/v1/statuses/#{response["id"]}", %{}) + |> get("/api/v1/statuses/#{response["id"]}", %{}) |> json_response_and_validate_schema(200) assert response["reblogs_count"] == 0 @@ -110,7 +110,7 @@ test "posting a status", %{conn: conn} do conn_four = conn |> put_req_header("content-type", "application/json") - |> post("api/v1/statuses", %{ + |> post("/api/v1/statuses", %{ "status" => "oolong", "expires_in" => expires_in }) @@ -133,7 +133,7 @@ test "automatically setting a post expiry if status_ttl_days is set" do conn = conn |> put_req_header("content-type", "application/json") - |> post("api/v1/statuses", %{ + |> post("/api/v1/statuses", %{ "status" => "aa chikichiki banban" }) @@ -164,7 +164,7 @@ test "it fails to create a status if `expires_in` is less or equal than an hour" assert %{"error" => "Expiry date is too soon"} = conn |> put_req_header("content-type", "application/json") - |> post("api/v1/statuses", %{ + |> post("/api/v1/statuses", %{ "status" => "oolong", "expires_in" => expires_in }) @@ -176,7 +176,7 @@ test "it fails to create a status if `expires_in` is less or equal than an hour" assert %{"error" => "Expiry date is too soon"} = conn |> put_req_header("content-type", "application/json") - |> post("api/v1/statuses", %{ + |> post("/api/v1/statuses", %{ "status" => "oolong", "expires_in" => expires_in }) @@ -190,7 +190,7 @@ test "Get MRF reason when posting a status is rejected by one", %{conn: conn} do assert %{"error" => "[KeywordPolicy] Matches with rejected keyword"} = conn |> put_req_header("content-type", "application/json") - |> post("api/v1/statuses", %{"status" => "GNO/Linux"}) + |> post("/api/v1/statuses", %{"status" => "GNO/Linux"}) |> json_response_and_validate_schema(422) end @@ -383,7 +383,7 @@ test "posting a direct status", %{conn: conn} do conn = conn |> put_req_header("content-type", "application/json") - |> post("api/v1/statuses", %{"status" => content, "visibility" => "direct"}) + |> post("/api/v1/statuses", %{"status" => content, "visibility" => "direct"}) assert %{"id" => id} = response = json_response_and_validate_schema(conn, 200) assert response["visibility"] == "direct" @@ -420,7 +420,7 @@ test "discloses application metadata when enabled" do result = conn - |> get("api/v1/statuses/#{activity}") + |> get("/api/v1/statuses/#{activity}") assert %{ "content" => "cofe is my copilot", @@ -449,7 +449,7 @@ test "hides application metadata when disabled" do result = conn - |> get("api/v1/statuses/#{activity}") + |> get("/api/v1/statuses/#{activity}") assert %{ "content" => "club mate is my wingman", @@ -1342,7 +1342,7 @@ test "on pin removes deletion job, on unpin reschedule deletion" do assert %{"id" => id} = conn |> put_req_header("content-type", "application/json") - |> post("api/v1/statuses", %{ + |> post("/api/v1/statuses", %{ "status" => "oolong", "expires_in" => expires_in }) @@ -1511,7 +1511,7 @@ test "Repeated posts that are replies incorrectly have in_reply_to_id null", %{c conn |> assign(:user, user3) |> assign(:token, insert(:oauth_token, user: user3, scopes: ["read:statuses"])) - |> get("api/v1/timelines/home") + |> get("/api/v1/timelines/home") [reblogged_activity] = json_response_and_validate_schema(conn3, 200) diff --git a/test/pleroma/web/mastodon_api/controllers/timeline_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/timeline_controller_test.exs index f609db7a4..aa9006681 100644 --- a/test/pleroma/web/mastodon_api/controllers/timeline_controller_test.exs +++ b/test/pleroma/web/mastodon_api/controllers/timeline_controller_test.exs @@ -288,7 +288,7 @@ test "doesn't return posts from users who blocked you when :blockers_visible is get(conn, "/api/v1/timelines/public") |> json_response_and_validate_schema(200) - assert length(response) == 0 + assert response == [] end test "doesn't return replies if follow is posting with users from blocked domain" do @@ -527,7 +527,7 @@ test "direct timeline", %{conn: conn} do |> assign(:token, insert(:oauth_token, user: user_two, scopes: ["read:statuses"])) # Only direct should be visible here - res_conn = get(conn_user_two, "api/v1/timelines/direct") + res_conn = get(conn_user_two, "/api/v1/timelines/direct") assert [status] = json_response_and_validate_schema(res_conn, :ok) @@ -539,14 +539,14 @@ test "direct timeline", %{conn: conn} do build_conn() |> assign(:user, user_one) |> assign(:token, insert(:oauth_token, user: user_one, scopes: ["read:statuses"])) - |> get("api/v1/timelines/direct") + |> get("/api/v1/timelines/direct") [status] = json_response_and_validate_schema(res_conn, :ok) assert %{"visibility" => "direct"} = status # Both should be visible here - res_conn = get(conn_user_two, "api/v1/timelines/home") + res_conn = get(conn_user_two, "/api/v1/timelines/home") [_s1, _s2] = json_response_and_validate_schema(res_conn, :ok) @@ -559,14 +559,14 @@ test "direct timeline", %{conn: conn} do }) end) - res_conn = get(conn_user_two, "api/v1/timelines/direct") + res_conn = get(conn_user_two, "/api/v1/timelines/direct") statuses = json_response_and_validate_schema(res_conn, :ok) assert length(statuses) == 20 max_id = List.last(statuses)["id"] - res_conn = get(conn_user_two, "api/v1/timelines/direct?max_id=#{max_id}") + res_conn = get(conn_user_two, "/api/v1/timelines/direct?max_id=#{max_id}") assert [status] = json_response_and_validate_schema(res_conn, :ok) @@ -591,7 +591,7 @@ test "doesn't include DMs from blocked users" do visibility: "direct" }) - res_conn = get(conn, "api/v1/timelines/direct") + res_conn = get(conn, "/api/v1/timelines/direct") [status] = json_response_and_validate_schema(res_conn, :ok) assert status["id"] == direct.id diff --git a/test/pleroma/web/mastodon_api/update_credentials_test.exs b/test/pleroma/web/mastodon_api/update_credentials_test.exs index 130cbe8d1..2ba909dad 100644 --- a/test/pleroma/web/mastodon_api/update_credentials_test.exs +++ b/test/pleroma/web/mastodon_api/update_credentials_test.exs @@ -388,7 +388,7 @@ test "updates the user's background, upload_limit, returns a HTTP 413", %{ "pleroma_background_image" => new_background_oversized }) - assert user_response = json_response_and_validate_schema(res, 413) + assert json_response_and_validate_schema(res, 413) assert user.background == %{} clear_config([:instance, :upload_limit], upload_limit) @@ -439,13 +439,13 @@ test "updates profile emojos", %{user: user, conn: conn} do test "update fields", %{conn: conn} do fields = [ - %{"name" => "foo", "value" => ""}, - %{"name" => "link.io", "value" => "cofe.io"} + %{name: "foo", value: ""}, + %{name: "link.io", value: "cofe.io"} ] account_data = conn - |> patch("/api/v1/accounts/update_credentials", %{"fields_attributes" => fields}) + |> patch("/api/v1/accounts/update_credentials", %{fields_attributes: fields}) |> json_response_and_validate_schema(200) assert account_data["fields"] == [ @@ -467,13 +467,13 @@ test "update fields", %{conn: conn} do test "emojis in fields labels", %{conn: conn} do fields = [ - %{"name" => ":firefox:", "value" => "is best 2hu"}, - %{"name" => "they wins", "value" => ":blank:"} + %{name: ":firefox:", value: "is best 2hu"}, + %{name: "they wins", value: ":blank:"} ] account_data = conn - |> patch("/api/v1/accounts/update_credentials", %{"fields_attributes" => fields}) + |> patch("/api/v1/accounts/update_credentials", %{fields_attributes: fields}) |> json_response_and_validate_schema(200) assert account_data["fields"] == [ @@ -521,13 +521,13 @@ test "update fields via x-www-form-urlencoded", %{conn: conn} do test "update fields with empty name", %{conn: conn} do fields = [ - %{"name" => "foo", "value" => ""}, - %{"name" => "", "value" => "bar"} + %{name: "foo", value: ""}, + %{name: "", value: "bar"} ] account = conn - |> patch("/api/v1/accounts/update_credentials", %{"fields_attributes" => fields}) + |> patch("/api/v1/accounts/update_credentials", %{fields_attributes: fields}) |> json_response_and_validate_schema(200) assert account["fields"] == [ @@ -542,30 +542,30 @@ test "update fields when invalid request", %{conn: conn} do long_name = Enum.map(0..name_limit, fn _ -> "x" end) |> Enum.join() long_value = Enum.map(0..value_limit, fn _ -> "x" end) |> Enum.join() - fields = [%{"name" => "foo", "value" => long_value}] + fields = [%{name: "foo", value: long_value}] assert %{"error" => "Invalid request"} == conn - |> patch("/api/v1/accounts/update_credentials", %{"fields_attributes" => fields}) + |> patch("/api/v1/accounts/update_credentials", %{fields_attributes: fields}) |> json_response_and_validate_schema(403) - fields = [%{"name" => long_name, "value" => "bar"}] + fields = [%{name: long_name, value: "bar"}] assert %{"error" => "Invalid request"} == conn - |> patch("/api/v1/accounts/update_credentials", %{"fields_attributes" => fields}) + |> patch("/api/v1/accounts/update_credentials", %{fields_attributes: fields}) |> json_response_and_validate_schema(403) clear_config([:instance, :max_account_fields], 1) fields = [ - %{"name" => "foo", "value" => "bar"}, + %{name: "foo", value: "bar"}, %{"name" => "link", "value" => "cofe.io"} ] assert %{"error" => "Invalid request"} == conn - |> patch("/api/v1/accounts/update_credentials", %{"fields_attributes" => fields}) + |> patch("/api/v1/accounts/update_credentials", %{fields_attributes: fields}) |> json_response_and_validate_schema(403) end end diff --git a/test/pleroma/web/pleroma_api/controllers/account_controller_test.exs b/test/pleroma/web/pleroma_api/controllers/account_controller_test.exs index ad271c31b..89a2cf634 100644 --- a/test/pleroma/web/pleroma_api/controllers/account_controller_test.exs +++ b/test/pleroma/web/pleroma_api/controllers/account_controller_test.exs @@ -133,7 +133,7 @@ test "returns favorited DM only when user is logged in and he is one of recipien |> get("/api/v1/pleroma/accounts/#{user.id}/favourites") |> json_response_and_validate_schema(200) - assert length(response) == 0 + assert response == [] end test "does not return others' favorited DM when user is not one of recipients", %{ diff --git a/test/pleroma/web/pleroma_api/controllers/emoji_file_controller_test.exs b/test/pleroma/web/pleroma_api/controllers/emoji_file_controller_test.exs index 61a44b8ba..0d3d38b33 100644 --- a/test/pleroma/web/pleroma_api/controllers/emoji_file_controller_test.exs +++ b/test/pleroma/web/pleroma_api/controllers/emoji_file_controller_test.exs @@ -28,7 +28,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiFileControllerTest do {:ok, %{admin_conn: admin_conn}} end - describe "POST/PATCH/DELETE /api/pleroma/emoji/packs/files?name=:name" do + describe "POST/PATCH/DELETE /api/v1/pleroma/emoji/packs/files?name=:name" do setup do pack_file = "#{@emoji_path}/test_pack/pack.json" original_content = File.read!(pack_file) @@ -55,7 +55,7 @@ test "upload zip file with emojies", %{admin_conn: admin_conn} do resp = admin_conn |> put_req_header("content-type", "multipart/form-data") - |> post("/api/pleroma/emoji/packs/files?name=test_pack", %{ + |> post("/api/v1/pleroma/emoji/packs/files?name=test_pack", %{ file: %Plug.Upload{ content_type: "application/zip", filename: "emojis.zip", @@ -82,7 +82,7 @@ test "upload zip file with emojies", %{admin_conn: admin_conn} do test "create shortcode exists", %{admin_conn: admin_conn} do assert admin_conn |> put_req_header("content-type", "multipart/form-data") - |> post("/api/pleroma/emoji/packs/files?name=test_pack", %{ + |> post("/api/v1/pleroma/emoji/packs/files?name=test_pack", %{ shortcode: "blank", filename: "dir/blank.png", file: %Plug.Upload{ @@ -100,7 +100,7 @@ test "don't rewrite old emoji", %{admin_conn: admin_conn} do assert admin_conn |> put_req_header("content-type", "multipart/form-data") - |> post("/api/pleroma/emoji/packs/files?name=test_pack", %{ + |> post("/api/v1/pleroma/emoji/packs/files?name=test_pack", %{ shortcode: "blank3", filename: "dir/blank.png", file: %Plug.Upload{ @@ -118,7 +118,7 @@ test "don't rewrite old emoji", %{admin_conn: admin_conn} do assert admin_conn |> put_req_header("content-type", "multipart/form-data") - |> patch("/api/pleroma/emoji/packs/files?name=test_pack", %{ + |> patch("/api/v1/pleroma/emoji/packs/files?name=test_pack", %{ shortcode: "blank", new_shortcode: "blank2", new_filename: "dir_2/blank_3.png" @@ -134,7 +134,7 @@ test "rewrite old emoji with force option", %{admin_conn: admin_conn} do assert admin_conn |> put_req_header("content-type", "multipart/form-data") - |> post("/api/pleroma/emoji/packs/files?name=test_pack", %{ + |> post("/api/v1/pleroma/emoji/packs/files?name=test_pack", %{ shortcode: "blank3", filename: "dir/blank.png", file: %Plug.Upload{ @@ -152,7 +152,7 @@ test "rewrite old emoji with force option", %{admin_conn: admin_conn} do assert admin_conn |> put_req_header("content-type", "multipart/form-data") - |> patch("/api/pleroma/emoji/packs/files?name=test_pack", %{ + |> patch("/api/v1/pleroma/emoji/packs/files?name=test_pack", %{ shortcode: "blank3", new_shortcode: "blank4", new_filename: "dir_2/blank_3.png", @@ -170,7 +170,7 @@ test "rewrite old emoji with force option", %{admin_conn: admin_conn} do test "with empty filename", %{admin_conn: admin_conn} do assert admin_conn |> put_req_header("content-type", "multipart/form-data") - |> post("/api/pleroma/emoji/packs/files?name=test_pack", %{ + |> post("/api/v1/pleroma/emoji/packs/files?name=test_pack", %{ shortcode: "blank2", filename: "", file: %Plug.Upload{ @@ -186,7 +186,7 @@ test "with empty filename", %{admin_conn: admin_conn} do test "add file with not loaded pack", %{admin_conn: admin_conn} do assert admin_conn |> put_req_header("content-type", "multipart/form-data") - |> post("/api/pleroma/emoji/packs/files?name=not_loaded", %{ + |> post("/api/v1/pleroma/emoji/packs/files?name=not_loaded", %{ shortcode: "blank3", filename: "dir/blank.png", file: %Plug.Upload{ @@ -209,7 +209,7 @@ test "returns an error on add file when file system is not writable", %{ ]) do assert admin_conn |> put_req_header("content-type", "multipart/form-data") - |> post("/api/pleroma/emoji/packs/files?name=not_loaded", %{ + |> post("/api/v1/pleroma/emoji/packs/files?name=not_loaded", %{ shortcode: "blank3", filename: "dir/blank.png", file: %Plug.Upload{ @@ -226,7 +226,7 @@ test "returns an error on add file when file system is not writable", %{ test "remove file with not loaded pack", %{admin_conn: admin_conn} do assert admin_conn - |> delete("/api/pleroma/emoji/packs/files?name=not_loaded&shortcode=blank3") + |> delete("/api/v1/pleroma/emoji/packs/files?name=not_loaded&shortcode=blank3") |> json_response_and_validate_schema(:not_found) == %{ "error" => "pack \"not_loaded\" is not found" } @@ -234,7 +234,7 @@ test "remove file with not loaded pack", %{admin_conn: admin_conn} do test "remove file with empty shortcode", %{admin_conn: admin_conn} do assert admin_conn - |> delete("/api/pleroma/emoji/packs/files?name=not_loaded&shortcode=") + |> delete("/api/v1/pleroma/emoji/packs/files?name=not_loaded&shortcode=") |> json_response_and_validate_schema(:not_found) == %{ "error" => "pack \"not_loaded\" is not found" } @@ -243,7 +243,7 @@ test "remove file with empty shortcode", %{admin_conn: admin_conn} do test "update file with not loaded pack", %{admin_conn: admin_conn} do assert admin_conn |> put_req_header("content-type", "multipart/form-data") - |> patch("/api/pleroma/emoji/packs/files?name=not_loaded", %{ + |> patch("/api/v1/pleroma/emoji/packs/files?name=not_loaded", %{ shortcode: "blank4", new_shortcode: "blank3", new_filename: "dir_2/blank_3.png" @@ -256,7 +256,7 @@ test "update file with not loaded pack", %{admin_conn: admin_conn} do test "new with shortcode as file with update", %{admin_conn: admin_conn} do assert admin_conn |> put_req_header("content-type", "multipart/form-data") - |> post("/api/pleroma/emoji/packs/files?name=test_pack", %{ + |> post("/api/v1/pleroma/emoji/packs/files?name=test_pack", %{ shortcode: "blank4", filename: "dir/blank.png", file: %Plug.Upload{ @@ -274,7 +274,7 @@ test "new with shortcode as file with update", %{admin_conn: admin_conn} do assert admin_conn |> put_req_header("content-type", "multipart/form-data") - |> patch("/api/pleroma/emoji/packs/files?name=test_pack", %{ + |> patch("/api/v1/pleroma/emoji/packs/files?name=test_pack", %{ shortcode: "blank4", new_shortcode: "blank3", new_filename: "dir_2/blank_3.png" @@ -289,7 +289,7 @@ test "new with shortcode as file with update", %{admin_conn: admin_conn} do assert File.exists?("#{@emoji_path}/test_pack/dir_2/blank_3.png") assert admin_conn - |> delete("/api/pleroma/emoji/packs/files?name=test_pack&shortcode=blank3") + |> delete("/api/v1/pleroma/emoji/packs/files?name=test_pack&shortcode=blank3") |> json_response_and_validate_schema(200) == %{ "blank" => "blank.png", "blank2" => "blank2.png" @@ -311,7 +311,7 @@ test "new with shortcode from url", %{admin_conn: admin_conn} do assert admin_conn |> put_req_header("content-type", "multipart/form-data") - |> post("/api/pleroma/emoji/packs/files?name=test_pack", %{ + |> post("/api/v1/pleroma/emoji/packs/files?name=test_pack", %{ shortcode: "blank_url", file: "https://test-blank/blank_url.png" }) @@ -331,7 +331,7 @@ test "new without shortcode", %{admin_conn: admin_conn} do assert admin_conn |> put_req_header("content-type", "multipart/form-data") - |> post("/api/pleroma/emoji/packs/files?name=test_pack", %{ + |> post("/api/v1/pleroma/emoji/packs/files?name=test_pack", %{ file: %Plug.Upload{ filename: "shortcode.png", path: "#{Pleroma.Config.get([:instance, :static_dir])}/add/shortcode.png" @@ -346,7 +346,7 @@ test "new without shortcode", %{admin_conn: admin_conn} do test "remove non existing shortcode in pack.json", %{admin_conn: admin_conn} do assert admin_conn - |> delete("/api/pleroma/emoji/packs/files?name=test_pack&shortcode=blank3") + |> delete("/api/v1/pleroma/emoji/packs/files?name=test_pack&shortcode=blank3") |> json_response_and_validate_schema(:bad_request) == %{ "error" => "Emoji \"blank3\" does not exist" } @@ -355,7 +355,7 @@ test "remove non existing shortcode in pack.json", %{admin_conn: admin_conn} do test "update non existing emoji", %{admin_conn: admin_conn} do assert admin_conn |> put_req_header("content-type", "multipart/form-data") - |> patch("/api/pleroma/emoji/packs/files?name=test_pack", %{ + |> patch("/api/v1/pleroma/emoji/packs/files?name=test_pack", %{ shortcode: "blank3", new_shortcode: "blank4", new_filename: "dir_2/blank_3.png" @@ -371,7 +371,7 @@ test "update with empty shortcode", %{admin_conn: admin_conn} do } = admin_conn |> put_req_header("content-type", "multipart/form-data") - |> patch("/api/pleroma/emoji/packs/files?name=test_pack", %{ + |> patch("/api/v1/pleroma/emoji/packs/files?name=test_pack", %{ shortcode: "blank", new_filename: "dir_2/blank_3.png" }) diff --git a/test/pleroma/web/pleroma_api/controllers/emoji_pack_controller_test.exs b/test/pleroma/web/pleroma_api/controllers/emoji_pack_controller_test.exs index d1ba067b8..b86418196 100644 --- a/test/pleroma/web/pleroma_api/controllers/emoji_pack_controller_test.exs +++ b/test/pleroma/web/pleroma_api/controllers/emoji_pack_controller_test.exs @@ -29,13 +29,16 @@ defmodule Pleroma.Web.PleromaAPI.EmojiPackControllerTest do {:ok, %{admin_conn: admin_conn}} end - test "GET /api/pleroma/emoji/packs when :public: false", %{conn: conn} do + test "GET /api/v1/pleroma/emoji/packs when :public: false", %{conn: conn} do clear_config([:instance, :public], false) - conn |> get("/api/pleroma/emoji/packs") |> json_response_and_validate_schema(200) + conn |> get("/api/v1/pleroma/emoji/packs") |> json_response_and_validate_schema(200) end - test "GET /api/pleroma/emoji/packs", %{conn: conn} do - resp = conn |> get("/api/pleroma/emoji/packs") |> json_response_and_validate_schema(200) + test "GET /api/v1/pleroma/emoji/packs", %{conn: conn} do + resp = + conn + |> get("/api/v1/pleroma/emoji/packs") + |> json_response_and_validate_schema(200) assert resp["count"] == 4 @@ -55,7 +58,7 @@ test "GET /api/pleroma/emoji/packs", %{conn: conn} do resp = conn - |> get("/api/pleroma/emoji/packs?page_size=1") + |> get("/api/v1/pleroma/emoji/packs?page_size=1") |> json_response_and_validate_schema(200) assert resp["count"] == 4 @@ -68,7 +71,7 @@ test "GET /api/pleroma/emoji/packs", %{conn: conn} do resp = conn - |> get("/api/pleroma/emoji/packs?page_size=1&page=2") + |> get("/api/v1/pleroma/emoji/packs?page_size=1&page=2") |> json_response_and_validate_schema(200) assert resp["count"] == 4 @@ -78,7 +81,7 @@ test "GET /api/pleroma/emoji/packs", %{conn: conn} do resp = conn - |> get("/api/pleroma/emoji/packs?page_size=1&page=3") + |> get("/api/v1/pleroma/emoji/packs?page_size=1&page=3") |> json_response_and_validate_schema(200) assert resp["count"] == 4 @@ -88,7 +91,7 @@ test "GET /api/pleroma/emoji/packs", %{conn: conn} do resp = conn - |> get("/api/pleroma/emoji/packs?page_size=1&page=4") + |> get("/api/v1/pleroma/emoji/packs?page_size=1&page=4") |> json_response_and_validate_schema(200) assert resp["count"] == 4 @@ -98,11 +101,11 @@ test "GET /api/pleroma/emoji/packs", %{conn: conn} do assert [pack1, pack2, pack3, pack4] |> Enum.uniq() |> length() == 4 end - describe "GET /api/pleroma/emoji/packs/remote" do + describe "GET /api/v1/pleroma/emoji/packs/remote" do test "shareable instance", %{admin_conn: admin_conn, conn: conn} do resp = conn - |> get("/api/pleroma/emoji/packs?page=2&page_size=1") + |> get("/api/v1/pleroma/emoji/packs?page=2&page_size=1") |> json_response_and_validate_schema(200) mock(fn @@ -112,12 +115,17 @@ test "shareable instance", %{admin_conn: admin_conn, conn: conn} do %{method: :get, url: "https://example.com/nodeinfo/2.1.json"} -> json(%{metadata: %{features: ["shareable_emoji_packs"]}}) - %{method: :get, url: "https://example.com/api/pleroma/emoji/packs?page=2&page_size=1"} -> + %{ + method: :get, + url: "https://example.com/api/v1/pleroma/emoji/packs?page=2&page_size=1" + } -> json(resp) end) assert admin_conn - |> get("/api/pleroma/emoji/packs/remote?url=https://example.com&page=2&page_size=1") + |> get( + "/api/v1/pleroma/emoji/packs/remote?url=https://example.com&page=2&page_size=1" + ) |> json_response_and_validate_schema(200) == resp end @@ -131,18 +139,18 @@ test "non shareable instance", %{admin_conn: admin_conn} do end) assert admin_conn - |> get("/api/pleroma/emoji/packs/remote?url=https://example.com") + |> get("/api/v1/pleroma/emoji/packs/remote?url=https://example.com") |> json_response_and_validate_schema(500) == %{ "error" => "The requested instance does not support sharing emoji packs" } end end - describe "GET /api/pleroma/emoji/packs/archive?name=:name" do + describe "GET /api/v1/pleroma/emoji/packs/archive?name=:name" do test "download shared pack", %{conn: conn} do resp = conn - |> get("/api/pleroma/emoji/packs/archive?name=test_pack") + |> get("/api/v1/pleroma/emoji/packs/archive?name=test_pack") |> response(200) {:ok, arch} = :zip.unzip(resp, [:memory]) @@ -153,7 +161,7 @@ test "download shared pack", %{conn: conn} do test "non existing pack", %{conn: conn} do assert conn - |> get("/api/pleroma/emoji/packs/archive?name=test_pack_for_import") + |> get("/api/v1/pleroma/emoji/packs/archive?name=test_pack_for_import") |> json_response_and_validate_schema(:not_found) == %{ "error" => "Pack test_pack_for_import does not exist" } @@ -161,7 +169,7 @@ test "non existing pack", %{conn: conn} do test "non downloadable pack", %{conn: conn} do assert conn - |> get("/api/pleroma/emoji/packs/archive?name=test_pack_nonshared") + |> get("/api/v1/pleroma/emoji/packs/archive?name=test_pack_nonshared") |> json_response_and_validate_schema(:forbidden) == %{ "error" => "Pack test_pack_nonshared cannot be downloaded from this instance, either pack sharing was disabled for this pack or some files are missing" @@ -169,7 +177,7 @@ test "non downloadable pack", %{conn: conn} do end end - describe "POST /api/pleroma/emoji/packs/download" do + describe "POST /api/v1/pleroma/emoji/packs/download" do test "shared pack from remote and non shared from fallback-src", %{ admin_conn: admin_conn, conn: conn @@ -183,28 +191,28 @@ test "shared pack from remote and non shared from fallback-src", %{ %{ method: :get, - url: "https://example.com/api/pleroma/emoji/pack?name=test_pack" + url: "https://example.com/api/v1/pleroma/emoji/pack?name=test_pack" } -> conn - |> get("/api/pleroma/emoji/pack?name=test_pack") + |> get("/api/v1/pleroma/emoji/pack?name=test_pack") |> json_response_and_validate_schema(200) |> json() %{ method: :get, - url: "https://example.com/api/pleroma/emoji/packs/archive?name=test_pack" + url: "https://example.com/api/v1/pleroma/emoji/packs/archive?name=test_pack" } -> conn - |> get("/api/pleroma/emoji/packs/archive?name=test_pack") + |> get("/api/v1/pleroma/emoji/packs/archive?name=test_pack") |> response(200) |> text() %{ method: :get, - url: "https://example.com/api/pleroma/emoji/pack?name=test_pack_nonshared" + url: "https://example.com/api/v1/pleroma/emoji/pack?name=test_pack_nonshared" } -> conn - |> get("/api/pleroma/emoji/pack?name=test_pack_nonshared") + |> get("/api/v1/pleroma/emoji/pack?name=test_pack_nonshared") |> json_response_and_validate_schema(200) |> json() @@ -217,7 +225,7 @@ test "shared pack from remote and non shared from fallback-src", %{ assert admin_conn |> put_req_header("content-type", "multipart/form-data") - |> post("/api/pleroma/emoji/packs/download", %{ + |> post("/api/v1/pleroma/emoji/packs/download", %{ url: "https://example.com", name: "test_pack", as: "test_pack2" @@ -228,7 +236,7 @@ test "shared pack from remote and non shared from fallback-src", %{ assert File.exists?("#{@emoji_path}/test_pack2/blank.png") assert admin_conn - |> delete("/api/pleroma/emoji/pack?name=test_pack2") + |> delete("/api/v1/pleroma/emoji/pack?name=test_pack2") |> json_response_and_validate_schema(200) == "ok" refute File.exists?("#{@emoji_path}/test_pack2") @@ -236,7 +244,7 @@ test "shared pack from remote and non shared from fallback-src", %{ assert admin_conn |> put_req_header("content-type", "multipart/form-data") |> post( - "/api/pleroma/emoji/packs/download", + "/api/v1/pleroma/emoji/packs/download", %{ url: "https://example.com", name: "test_pack_nonshared", @@ -249,7 +257,7 @@ test "shared pack from remote and non shared from fallback-src", %{ assert File.exists?("#{@emoji_path}/test_pack_nonshared2/blank.png") assert admin_conn - |> delete("/api/pleroma/emoji/pack?name=test_pack_nonshared2") + |> delete("/api/v1/pleroma/emoji/pack?name=test_pack_nonshared2") |> json_response_and_validate_schema(200) == "ok" refute File.exists?("#{@emoji_path}/test_pack_nonshared2") @@ -267,7 +275,7 @@ test "nonshareable instance", %{admin_conn: admin_conn} do assert admin_conn |> put_req_header("content-type", "multipart/form-data") |> post( - "/api/pleroma/emoji/packs/download", + "/api/v1/pleroma/emoji/packs/download", %{ url: "https://old-instance", name: "test_pack", @@ -289,14 +297,14 @@ test "checksum fail", %{admin_conn: admin_conn} do %{ method: :get, - url: "https://example.com/api/pleroma/emoji/pack?name=pack_bad_sha" + url: "https://example.com/api/v1/pleroma/emoji/pack?name=pack_bad_sha" } -> {:ok, pack} = Pleroma.Emoji.Pack.load_pack("pack_bad_sha") %Tesla.Env{status: 200, body: Jason.encode!(pack)} %{ method: :get, - url: "https://example.com/api/pleroma/emoji/packs/archive?name=pack_bad_sha" + url: "https://example.com/api/v1/pleroma/emoji/packs/archive?name=pack_bad_sha" } -> %Tesla.Env{ status: 200, @@ -306,7 +314,7 @@ test "checksum fail", %{admin_conn: admin_conn} do assert admin_conn |> put_req_header("content-type", "multipart/form-data") - |> post("/api/pleroma/emoji/packs/download", %{ + |> post("/api/v1/pleroma/emoji/packs/download", %{ url: "https://example.com", name: "pack_bad_sha", as: "pack_bad_sha2" @@ -326,7 +334,7 @@ test "other error", %{admin_conn: admin_conn} do %{ method: :get, - url: "https://example.com/api/pleroma/emoji/pack?name=test_pack" + url: "https://example.com/api/v1/pleroma/emoji/pack?name=test_pack" } -> {:ok, pack} = Pleroma.Emoji.Pack.load_pack("test_pack") %Tesla.Env{status: 200, body: Jason.encode!(pack)} @@ -334,7 +342,7 @@ test "other error", %{admin_conn: admin_conn} do assert admin_conn |> put_req_header("content-type", "multipart/form-data") - |> post("/api/pleroma/emoji/packs/download", %{ + |> post("/api/v1/pleroma/emoji/packs/download", %{ url: "https://example.com", name: "test_pack", as: "test_pack2" @@ -346,7 +354,7 @@ test "other error", %{admin_conn: admin_conn} do end end - describe "PATCH/update /api/pleroma/emoji/pack?name=:name" do + describe "PATCH/update /api/v1/pleroma/emoji/pack?name=:name" do setup do pack_file = "#{@emoji_path}/test_pack/pack.json" original_content = File.read!(pack_file) @@ -372,7 +380,7 @@ test "returns error when file system not writable", %{admin_conn: conn} = ctx do assert conn |> put_req_header("content-type", "multipart/form-data") |> patch( - "/api/pleroma/emoji/pack?name=test_pack", + "/api/v1/pleroma/emoji/pack?name=test_pack", %{"metadata" => ctx[:new_data]} ) |> json_response_and_validate_schema(500) @@ -382,7 +390,7 @@ test "returns error when file system not writable", %{admin_conn: conn} = ctx do test "for a pack without a fallback source", ctx do assert ctx[:admin_conn] |> put_req_header("content-type", "multipart/form-data") - |> patch("/api/pleroma/emoji/pack?name=test_pack", %{ + |> patch("/api/v1/pleroma/emoji/pack?name=test_pack", %{ "metadata" => ctx[:new_data] }) |> json_response_and_validate_schema(200) == ctx[:new_data] @@ -410,7 +418,7 @@ test "for a pack with a fallback source", ctx do assert ctx[:admin_conn] |> put_req_header("content-type", "multipart/form-data") - |> patch("/api/pleroma/emoji/pack?name=test_pack", %{metadata: new_data}) + |> patch("/api/v1/pleroma/emoji/pack?name=test_pack", %{metadata: new_data}) |> json_response_and_validate_schema(200) == new_data_with_sha assert Jason.decode!(File.read!(ctx[:pack_file]))["pack"] == new_data_with_sha @@ -430,14 +438,14 @@ test "when the fallback source doesn't have all the files", ctx do assert ctx[:admin_conn] |> put_req_header("content-type", "multipart/form-data") - |> patch("/api/pleroma/emoji/pack?name=test_pack", %{metadata: new_data}) + |> patch("/api/v1/pleroma/emoji/pack?name=test_pack", %{metadata: new_data}) |> json_response_and_validate_schema(:bad_request) == %{ "error" => "The fallback archive does not have all files specified in pack.json" } end end - describe "POST/DELETE /api/pleroma/emoji/pack?name=:name" do + describe "POST/DELETE /api/v1/pleroma/emoji/pack?name=:name" do test "returns an error on creates pack when file system not writable", %{ admin_conn: admin_conn } do @@ -447,7 +455,7 @@ test "returns an error on creates pack when file system not writable", %{ {File, [:passthrough], [mkdir: fn ^path_pack -> {:error, :eacces} end]} ]) do assert admin_conn - |> post("/api/pleroma/emoji/pack?name=test_pack") + |> post("/api/v1/pleroma/emoji/pack?name=test_pack") |> json_response_and_validate_schema(500) == %{ "error" => "Unexpected error occurred while creating pack. (POSIX error: Permission denied)" @@ -467,7 +475,7 @@ test "returns an error on deletes pack when the file system is not writable", %{ {File, [:passthrough], [rm_rf: fn ^path_pack -> {:error, :eacces, path_pack} end]} ]) do assert admin_conn - |> delete("/api/pleroma/emoji/pack?name=test_emoji_pack") + |> delete("/api/v1/pleroma/emoji/pack?name=test_emoji_pack") |> json_response_and_validate_schema(500) == %{ "error" => "Couldn't delete the `test_emoji_pack` pack (POSIX error: Permission denied)" @@ -480,7 +488,7 @@ test "returns an error on deletes pack when the file system is not writable", %{ test "creating and deleting a pack", %{admin_conn: admin_conn} do assert admin_conn - |> post("/api/pleroma/emoji/pack?name=test_created") + |> post("/api/v1/pleroma/emoji/pack?name=test_created") |> json_response_and_validate_schema(200) == "ok" assert File.exists?("#{@emoji_path}/test_created/pack.json") @@ -492,7 +500,7 @@ test "creating and deleting a pack", %{admin_conn: admin_conn} do } assert admin_conn - |> delete("/api/pleroma/emoji/pack?name=test_created") + |> delete("/api/v1/pleroma/emoji/pack?name=test_created") |> json_response_and_validate_schema(200) == "ok" refute File.exists?("#{@emoji_path}/test_created/pack.json") @@ -505,7 +513,7 @@ test "if pack exists", %{admin_conn: admin_conn} do File.write!(Path.join(path, "pack.json"), pack_file) assert admin_conn - |> post("/api/pleroma/emoji/pack?name=test_created") + |> post("/api/v1/pleroma/emoji/pack?name=test_created") |> json_response_and_validate_schema(:conflict) == %{ "error" => "A pack named \"test_created\" already exists" } @@ -515,7 +523,7 @@ test "if pack exists", %{admin_conn: admin_conn} do test "with empty name", %{admin_conn: admin_conn} do assert admin_conn - |> post("/api/pleroma/emoji/pack?name= ") + |> post("/api/v1/pleroma/emoji/pack?name= ") |> json_response_and_validate_schema(:bad_request) == %{ "error" => "pack name cannot be empty" } @@ -524,7 +532,7 @@ test "with empty name", %{admin_conn: admin_conn} do test "deleting nonexisting pack", %{admin_conn: admin_conn} do assert admin_conn - |> delete("/api/pleroma/emoji/pack?name=non_existing") + |> delete("/api/v1/pleroma/emoji/pack?name=non_existing") |> json_response_and_validate_schema(:not_found) == %{ "error" => "Pack non_existing does not exist" } @@ -532,7 +540,7 @@ test "deleting nonexisting pack", %{admin_conn: admin_conn} do test "deleting with empty name", %{admin_conn: admin_conn} do assert admin_conn - |> delete("/api/pleroma/emoji/pack?name= ") + |> delete("/api/v1/pleroma/emoji/pack?name= ") |> json_response_and_validate_schema(:bad_request) == %{ "error" => "pack name cannot be empty" } @@ -544,15 +552,22 @@ test "filesystem import", %{admin_conn: admin_conn, conn: conn} do File.rm!("#{@emoji_path}/test_pack_for_import/pack.json") end) - resp = conn |> get("/api/pleroma/emoji/packs") |> json_response_and_validate_schema(200) + resp = + conn + |> get("/api/v1/pleroma/emoji/packs") + |> json_response_and_validate_schema(200) refute Map.has_key?(resp["packs"], "test_pack_for_import") assert admin_conn - |> get("/api/pleroma/emoji/packs/import") + |> get("/api/v1/pleroma/emoji/packs/import") |> json_response_and_validate_schema(200) == ["test_pack_for_import"] - resp = conn |> get("/api/pleroma/emoji/packs") |> json_response_and_validate_schema(200) + resp = + conn + |> get("/api/v1/pleroma/emoji/packs") + |> json_response_and_validate_schema(200) + assert resp["packs"]["test_pack_for_import"]["files"] == %{"blank" => "blank.png"} File.rm!("#{@emoji_path}/test_pack_for_import/pack.json") @@ -568,10 +583,13 @@ test "filesystem import", %{admin_conn: admin_conn, conn: conn} do File.write!("#{@emoji_path}/test_pack_for_import/emoji.txt", emoji_txt_content) assert admin_conn - |> get("/api/pleroma/emoji/packs/import") + |> get("/api/v1/pleroma/emoji/packs/import") |> json_response_and_validate_schema(200) == ["test_pack_for_import"] - resp = conn |> get("/api/pleroma/emoji/packs") |> json_response_and_validate_schema(200) + resp = + conn + |> get("/api/v1/pleroma/emoji/packs") + |> json_response_and_validate_schema(200) assert resp["packs"]["test_pack_for_import"]["files"] == %{ "blank" => "blank.png", @@ -580,7 +598,7 @@ test "filesystem import", %{admin_conn: admin_conn, conn: conn} do } end - describe "GET /api/pleroma/emoji/pack?name=:name" do + describe "GET /api/v1/pleroma/emoji/pack?name=:name" do test "shows pack.json", %{conn: conn} do assert %{ "files" => files, @@ -595,7 +613,7 @@ test "shows pack.json", %{conn: conn} do } } = conn - |> get("/api/pleroma/emoji/pack?name=test_pack") + |> get("/api/v1/pleroma/emoji/pack?name=test_pack") |> json_response_and_validate_schema(200) assert files == %{"blank" => "blank.png", "blank2" => "blank2.png"} @@ -605,7 +623,7 @@ test "shows pack.json", %{conn: conn} do "files_count" => 2 } = conn - |> get("/api/pleroma/emoji/pack?name=test_pack&page_size=1") + |> get("/api/v1/pleroma/emoji/pack?name=test_pack&page_size=1") |> json_response_and_validate_schema(200) assert files |> Map.keys() |> length() == 1 @@ -615,7 +633,7 @@ test "shows pack.json", %{conn: conn} do "files_count" => 2 } = conn - |> get("/api/pleroma/emoji/pack?name=test_pack&page_size=1&page=2") + |> get("/api/v1/pleroma/emoji/pack?name=test_pack&page_size=1&page=2") |> json_response_and_validate_schema(200) assert files |> Map.keys() |> length() == 1 @@ -635,13 +653,13 @@ test "for pack name with special chars", %{conn: conn} do } } = conn - |> get("/api/pleroma/emoji/pack?name=blobs.gg") + |> get("/api/v1/pleroma/emoji/pack?name=blobs.gg") |> json_response_and_validate_schema(200) end test "non existing pack", %{conn: conn} do assert conn - |> get("/api/pleroma/emoji/pack?name=non_existing") + |> get("/api/v1/pleroma/emoji/pack?name=non_existing") |> json_response_and_validate_schema(:not_found) == %{ "error" => "Pack non_existing does not exist" } @@ -649,7 +667,7 @@ test "non existing pack", %{conn: conn} do test "error name", %{conn: conn} do assert conn - |> get("/api/pleroma/emoji/pack?name= ") + |> get("/api/v1/pleroma/emoji/pack?name= ") |> json_response_and_validate_schema(:bad_request) == %{ "error" => "pack name cannot be empty" } diff --git a/test/pleroma/web/pleroma_api/controllers/two_factor_authentication_controller_test.exs b/test/pleroma/web/pleroma_api/controllers/two_factor_authentication_controller_test.exs index 24074f4e5..3716fcdec 100644 --- a/test/pleroma/web/pleroma_api/controllers/two_factor_authentication_controller_test.exs +++ b/test/pleroma/web/pleroma_api/controllers/two_factor_authentication_controller_test.exs @@ -151,7 +151,10 @@ test "returns success result", %{conn: conn} do assert conn |> put_req_header("authorization", "Bearer #{token.token}") - |> post("/api/pleroma/accounts/mfa/confirm/totp", %{password: "test", code: code}) + |> post("/api/pleroma/accounts/mfa/confirm/totp", %{ + password: "test", + code: code + }) |> json_response(:ok) settings = refresh_record(user).multi_factor_authentication_settings @@ -162,7 +165,10 @@ test "returns success result", %{conn: conn} do assert conn |> put_req_header("authorization", "Bearer #{token2.token}") - |> post("/api/pleroma/accounts/mfa/confirm/totp", %{password: "test", code: code}) + |> post("/api/pleroma/accounts/mfa/confirm/totp", %{ + password: "test", + code: code + }) |> json_response(403) == %{ "error" => "Insufficient permissions: write:security." } @@ -185,7 +191,10 @@ test "returns error if password incorrect", %{conn: conn} do response = conn |> put_req_header("authorization", "Bearer #{token.token}") - |> post("/api/pleroma/accounts/mfa/confirm/totp", %{password: "xxx", code: code}) + |> post("/api/pleroma/accounts/mfa/confirm/totp", %{ + password: "xxx", + code: code + }) |> json_response(422) settings = refresh_record(user).multi_factor_authentication_settings @@ -212,7 +221,10 @@ test "returns error if code incorrect", %{conn: conn} do response = conn |> put_req_header("authorization", "Bearer #{token.token}") - |> post("/api/pleroma/accounts/mfa/confirm/totp", %{password: "test", code: "code"}) + |> post("/api/pleroma/accounts/mfa/confirm/totp", %{ + password: "test", + code: "code" + }) |> json_response(422) settings = refresh_record(user).multi_factor_authentication_settings @@ -223,7 +235,10 @@ test "returns error if code incorrect", %{conn: conn} do assert conn |> put_req_header("authorization", "Bearer #{token2.token}") - |> post("/api/pleroma/accounts/mfa/confirm/totp", %{password: "test", code: "code"}) + |> post("/api/pleroma/accounts/mfa/confirm/totp", %{ + password: "test", + code: "code" + }) |> json_response(403) == %{ "error" => "Insufficient permissions: write:security." } diff --git a/test/pleroma/web/plugs/remote_ip_test.exs b/test/pleroma/web/plugs/remote_ip_test.exs index 4d98de2bd..b77fa25f2 100644 --- a/test/pleroma/web/plugs/remote_ip_test.exs +++ b/test/pleroma/web/plugs/remote_ip_test.exs @@ -10,28 +10,32 @@ defmodule Pleroma.Web.Plugs.RemoteIpTest do import Pleroma.Tests.Helpers, only: [clear_config: 2] - setup do: - clear_config(RemoteIp, - enabled: true, - headers: ["x-forwarded-for"], - proxies: [], - reserved: [ - "127.0.0.0/8", - "::1/128", - "fc00::/7", - "10.0.0.0/8", - "172.16.0.0/12", - "192.168.0.0/16" - ] - ) + setup do + clear_config([RemoteIp, :enabled], true) + clear_config([RemoteIp, :headers], ["x-forwarded-for"]) + clear_config([RemoteIp, :proxies], []) + + clear_config( + [RemoteIp, :reserved], + [ + "127.0.0.0/8", + "::1/128", + "fc00::/7", + "10.0.0.0/8", + "172.16.0.0/12", + "192.168.0.0/16" + ] + ) + end test "disabled" do - clear_config(RemoteIp, enabled: false) + clear_config([RemoteIp, :enabled], false) %{remote_ip: remote_ip} = conn(:get, "/") conn = - conn(:get, "/") + :get + |> conn("/") |> put_req_header("x-forwarded-for", "1.1.1.1") |> RemoteIp.call(nil) @@ -40,7 +44,8 @@ test "disabled" do test "enabled" do conn = - conn(:get, "/") + :get + |> conn("/") |> put_req_header("x-forwarded-for", "1.1.1.1") |> RemoteIp.call(nil) @@ -48,17 +53,20 @@ test "enabled" do end test "custom headers" do - clear_config(RemoteIp, enabled: true, headers: ["cf-connecting-ip"]) + clear_config([RemoteIp, :enabled], true) + clear_config([RemoteIp, :headers], ["cf-connecting-ip"]) conn = - conn(:get, "/") + :get + |> conn("/") |> put_req_header("x-forwarded-for", "1.1.1.1") |> RemoteIp.call(nil) refute conn.remote_ip == {1, 1, 1, 1} conn = - conn(:get, "/") + :get + |> conn("/") |> put_req_header("cf-connecting-ip", "1.1.1.1") |> RemoteIp.call(nil) @@ -67,7 +75,8 @@ test "custom headers" do test "custom proxies" do conn = - conn(:get, "/") + :get + |> conn("/") |> put_req_header("x-forwarded-for", "173.245.48.1, 1.1.1.1, 173.245.48.2") |> RemoteIp.call(nil) @@ -76,7 +85,8 @@ test "custom proxies" do clear_config([RemoteIp, :proxies], ["173.245.48.0/20"]) conn = - conn(:get, "/") + :get + |> conn("/") |> put_req_header("x-forwarded-for", "173.245.48.1, 1.1.1.1, 173.245.48.2") |> RemoteIp.call(nil) @@ -87,7 +97,8 @@ test "proxies set without CIDR format" do clear_config([RemoteIp, :proxies], ["173.245.48.1"]) conn = - conn(:get, "/") + :get + |> conn("/") |> put_req_header("x-forwarded-for", "173.245.48.1, 1.1.1.1") |> RemoteIp.call(nil) @@ -99,7 +110,8 @@ test "proxies set `nonsensical` CIDR" do clear_config([RemoteIp, :proxies], ["10.0.0.3/24"]) conn = - conn(:get, "/") + :get + |> conn("/") |> put_req_header("x-forwarded-for", "10.0.0.3, 1.1.1.1") |> RemoteIp.call(nil) diff --git a/test/pleroma/web/twitter_api/password_controller_test.exs b/test/pleroma/web/twitter_api/password_controller_test.exs index 45ab10a8a..05c3561bf 100644 --- a/test/pleroma/web/twitter_api/password_controller_test.exs +++ b/test/pleroma/web/twitter_api/password_controller_test.exs @@ -14,11 +14,11 @@ defmodule Pleroma.Web.TwitterAPI.PasswordControllerTest do import Pleroma.Factory import Swoosh.TestAssertions - describe "GET /api/pleroma/password_reset/token" do + describe "GET /api/v1/pleroma/password_reset/token" do test "it returns error when token invalid", %{conn: conn} do response = conn - |> get("/api/pleroma/password_reset/token") + |> get("/api/v1/pleroma/password_reset/token") |> html_response(:ok) assert response =~ "

Invalid Token

" @@ -30,7 +30,7 @@ test "it shows password reset form", %{conn: conn} do response = conn - |> get("/api/pleroma/password_reset/#{token.token}") + |> get("/api/v1/pleroma/password_reset/#{token.token}") |> html_response(:ok) assert response =~ "

Password Reset for #{user.nickname}

" @@ -45,14 +45,14 @@ test "it returns an error when the token has expired", %{conn: conn} do response = conn - |> get("/api/pleroma/password_reset/#{token.token}") + |> get("/api/v1/pleroma/password_reset/#{token.token}") |> html_response(:ok) assert response =~ "

Invalid Token

" end end - describe "POST /api/pleroma/password_reset" do + describe "POST /api/v1/pleroma/password_reset" do test "it fails for an expired token", %{conn: conn} do clear_config([:instance, :password_reset_token_validity], 0) @@ -70,7 +70,7 @@ test "it fails for an expired token", %{conn: conn} do response = conn |> assign(:user, user) - |> post("/api/pleroma/password_reset", %{data: params}) + |> post("/api/v1/pleroma/password_reset", %{data: params}) |> html_response(:ok) refute response =~ "

Password changed!

" @@ -90,7 +90,7 @@ test "it returns HTTP 200", %{conn: conn} do response = conn |> assign(:user, user) - |> post("/api/pleroma/password_reset", %{data: params}) + |> post("/api/v1/pleroma/password_reset", %{data: params}) |> html_response(:ok) assert response =~ "

Password changed!

" @@ -114,7 +114,7 @@ test "it sets password_reset_pending to false", %{conn: conn} do conn |> assign(:user, user) - |> post("/api/pleroma/password_reset", %{data: params}) + |> post("/api/v1/pleroma/password_reset", %{data: params}) |> html_response(:ok) assert User.get_by_id(user.id).password_reset_pending == false diff --git a/test/pleroma/web/twitter_api/util_controller_test.exs b/test/pleroma/web/twitter_api/util_controller_test.exs index d669cd0fe..3f839568d 100644 --- a/test/pleroma/web/twitter_api/util_controller_test.exs +++ b/test/pleroma/web/twitter_api/util_controller_test.exs @@ -77,11 +77,11 @@ test "returns everything in :pleroma, :frontend_configurations", %{conn: conn} d end end - describe "/api/pleroma/emoji" do + describe "/api/v1/pleroma/emoji" do test "returns json with custom emoji with tags", %{conn: conn} do emoji = conn - |> get("/api/pleroma/emoji") + |> get("/api/v1/pleroma/emoji") |> json_response_and_validate_schema(200) assert Enum.all?(emoji, fn @@ -95,7 +95,7 @@ test "returns json with custom emoji with tags", %{conn: conn} do end end - describe "GET /api/pleroma/healthcheck" do + describe "GET /api/v1/pleroma/healthcheck" do setup do: clear_config([:instance, :healthcheck]) test "returns 503 when healthcheck disabled", %{conn: conn} do @@ -103,7 +103,7 @@ test "returns 503 when healthcheck disabled", %{conn: conn} do response = conn - |> get("/api/pleroma/healthcheck") + |> get("/api/v1/pleroma/healthcheck") |> json_response_and_validate_schema(503) assert response == %{} @@ -116,7 +116,7 @@ test "returns 200 when healthcheck enabled and all ok", %{conn: conn} do system_info: fn -> %Pleroma.Healthcheck{healthy: true} end do response = conn - |> get("/api/pleroma/healthcheck") + |> get("/api/v1/pleroma/healthcheck") |> json_response_and_validate_schema(200) assert %{ @@ -136,7 +136,7 @@ test "returns 503 when healthcheck enabled and health is false", %{conn: conn} d system_info: fn -> %Pleroma.Healthcheck{healthy: false} end do response = conn - |> get("/api/pleroma/healthcheck") + |> get("/api/v1/pleroma/healthcheck") |> json_response_and_validate_schema(503) assert %{ @@ -334,7 +334,7 @@ test "it returns new captcha", %{conn: conn} do new: fn -> "test_captcha" end do resp = conn - |> get("/api/pleroma/captcha") + |> get("/api/v1/pleroma/captcha") |> response(200) assert resp == "\"test_captcha\"" @@ -459,7 +459,10 @@ test "with proper permissions, valid password and valid email", %{ conn = conn |> put_req_header("content-type", "multipart/form-data") - |> post("/api/pleroma/change_email", %{password: "test", email: "cofe@foobar.com"}) + |> post("/api/pleroma/change_email", %{ + password: "test", + email: "cofe@foobar.com" + }) assert json_response_and_validate_schema(conn, 200) == %{"status" => "success"} end @@ -961,7 +964,9 @@ test "with permissions, account does not have such alias", %{ conn = conn |> put_req_header("content-type", "application/json") - |> delete("/api/pleroma/aliases", %{alias: non_alias_user |> User.full_nickname()}) + |> delete("/api/pleroma/aliases", %{ + alias: non_alias_user |> User.full_nickname() + }) assert %{"error" => "Account has no such alias."} = json_response_and_validate_schema(conn, 404) diff --git a/test/support/cluster.ex b/test/support/cluster.ex index 7e41631c5..682643988 100644 --- a/test/support/cluster.ex +++ b/test/support/cluster.ex @@ -123,7 +123,10 @@ def eval_quoted(block, binding) do defp start_peer({node_host, override_configs}) do log(node_host, "booting federated VM") - {:ok, node} = :peer.start(%{host: ~c"127.0.0.1", name: node_name(node_host), args: vm_args()}) + + {:ok, _pid, node} = + :peer.start(%{host: ~c"127.0.0.1", name: node_name(node_host), args: vm_args()}) + add_code_paths(node) load_apps_and_transfer_configuration(node, override_configs) ensure_apps_started(node) From 33243c56e5560f99bd886ed44bcb50c9f679ccc2 Mon Sep 17 00:00:00 2001 From: Tim Buchwaldt Date: Sat, 12 Nov 2022 11:14:16 +0100 Subject: [PATCH 138/631] Start adding telemetry --- lib/pleroma/application.ex | 1 + lib/pleroma/web/router.ex | 2 +- lib/pleroma/web/telemetry.ex | 90 ++++++++++++++++++++++++++++++++++++ mix.exs | 3 ++ mix.lock | 5 +- 5 files changed, 99 insertions(+), 2 deletions(-) create mode 100644 lib/pleroma/web/telemetry.ex diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex index 48a2623ce..ad768b0e0 100644 --- a/lib/pleroma/application.ex +++ b/lib/pleroma/application.ex @@ -64,6 +64,7 @@ def start(_type, _args) do Config.TransferTask, Pleroma.Emoji, Pleroma.Web.Plugs.RateLimiter.Supervisor, + Pleroma.Web.Telemetry, {Task.Supervisor, name: Pleroma.TaskSupervisor} ] ++ cachex_children() ++ diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index e790b1cdb..bcb5fb15e 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -867,7 +867,7 @@ defmodule Pleroma.Web.Router do scope "/" do pipe_through([:pleroma_html, :authenticate, :require_admin]) - live_dashboard("/phoenix/live_dashboard") + live_dashboard("/phoenix/live_dashboard", metrics: Pleroma.Web.Telemetry) end # Test-only routes needed to test action dispatching and plug chain execution diff --git a/lib/pleroma/web/telemetry.ex b/lib/pleroma/web/telemetry.ex new file mode 100644 index 000000000..f7e9d5ca7 --- /dev/null +++ b/lib/pleroma/web/telemetry.ex @@ -0,0 +1,90 @@ +defmodule Pleroma.Web.Telemetry do + use Supervisor + import Telemetry.Metrics + + def start_link(arg) do + Supervisor.start_link(__MODULE__, arg, name: __MODULE__) + end + + @impl true + def init(_arg) do + children = [ + # Telemetry poller will execute the given period measurements + # every 10_000ms. Learn more here: https://hexdocs.pm/telemetry_metrics + {:telemetry_poller, measurements: periodic_measurements(), period: 10_000}, + # Add reporters as children of your supervision tree. + # {Telemetry.Metrics.ConsoleReporter, metrics: metrics()}, + {TelemetryMetricsPrometheus, metrics: metrics()} + ] + + Supervisor.init(children, strategy: :one_for_one) + end + + def metrics do + [ + # Phoenix Metrics + summary("phoenix.endpoint.stop.duration", + unit: {:native, :millisecond} + ), + summary("phoenix.router_dispatch.stop.duration", + tags: [:route], + unit: {:native, :millisecond} + ), + distribution( + "phoenix.router_dispatch.stop.duration", + # event_name: [:pleroma, :repo, :query, :total_time], + measurement: :duration, + unit: {:native, :second}, + tags: [:route], + reporter_options: [ + buckets: [0.01, 0.025, 0.05, 0.1, 0.2, 0.5, 1, 2.5, 5, 10] + ] + ), + + # Database Time Metrics + distribution( + "pleroma.repo.query.total_time", + # event_name: [:pleroma, :repo, :query, :total_time], + measurement: :total_time, + unit: {:native, :millisecond}, + reporter_options: [ + buckets: [0.01, 0.025, 0.05, 0.1, 0.2, 0.5, 1, 2.5, 5, 10] + ] + ), + distribution( + "pleroma.repo.query.queue_time", + # event_name: [:pleroma, :repo, :query, :total_time], + measurement: :queue_time, + unit: {:native, :millisecond}, + reporter_options: [ + buckets: [0.01, 0.025, 0.05, 0.1, 0.2, 0.5, 1, 2.5, 5, 10] + ] + ), + summary("pleroma.repo.query.total_time", unit: {:native, :millisecond}), + summary("pleroma.repo.query.decode_time", unit: {:native, :millisecond}), + summary("pleroma.repo.query.query_time", unit: {:native, :millisecond}), + summary("pleroma.repo.query.queue_time", unit: {:native, :millisecond}), + summary("pleroma.repo.query.idle_time", unit: {:native, :millisecond}), + + # VM Metrics + summary("vm.memory.total", unit: {:byte, :kilobyte}), + summary("vm.total_run_queue_lengths.total"), + summary("vm.total_run_queue_lengths.cpu"), + summary("vm.total_run_queue_lengths.io"), + distribution( + "oban.job.stop", + event_name: [:oban, :job, :stop], + measurement: :duration, + tags: [:job], + unit: {:native, :second}, + reporter_options: [ + buckets: [0.01, 0.025, 0.05, 0.1, 0.2, 0.5, 1, 2.5, 5, 10] + ] + ) + ] + end + + defp periodic_measurements do + [] + end +end diff --git a/mix.exs b/mix.exs index 00a250002..b5b7efd0c 100644 --- a/mix.exs +++ b/mix.exs @@ -161,6 +161,9 @@ defp deps do git: "https://akkoma.dev/AkkomaGang/linkify.git", branch: "bugfix/line-ending-buffer"}, {:http_signatures, "~> 0.1.1"}, {:telemetry, "~> 0.3"}, + {:telemetry_poller, "~> 0.4"}, + {:telemetry_metrics, "~> 0.4"}, + {:telemetry_metrics_prometheus, "~> 1.1.0"}, {:poolboy, "~> 1.5"}, {:recon, "~> 2.5"}, {:joken, "~> 2.0"}, diff --git a/mix.lock b/mix.lock index 0e3ac3514..01c628c29 100644 --- a/mix.lock +++ b/mix.lock @@ -17,7 +17,7 @@ "cowboy": {:hex, :cowboy, "2.9.0", "865dd8b6607e14cf03282e10e934023a1bd8be6f6bacf921a7e2a96d800cd452", [:make, :rebar3], [{:cowlib, "2.11.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "2c729f934b4e1aa149aff882f57c6372c15399a20d54f65c8d67bef583021bde"}, "cowboy_telemetry": {:hex, :cowboy_telemetry, "0.3.1", "ebd1a1d7aff97f27c66654e78ece187abdc646992714164380d8a041eda16754", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "3a6efd3366130eab84ca372cbd4a7d3c3a97bdfcfb4911233b035d117063f0af"}, "cowlib": {:hex, :cowlib, "2.11.0", "0b9ff9c346629256c42ebe1eeb769a83c6cb771a6ee5960bd110ab0b9b872063", [:make, :rebar3], [], "hexpm", "2b3e9da0b21c4565751a6d4901c20d1b4cc25cbb7fd50d91d2ab6dd287bc86a9"}, - "credo": {:git, "https://github.com/rrrene/credo.git", "1c1b99ea41a457761383d81aaf6a606913996fe7", [ref: "1c1b99ea41a457761383d81aaf6a606913996fe7"]}, + "credo": {:hex, :credo, "1.6.7", "323f5734350fd23a456f2688b9430e7d517afb313fbd38671b8a4449798a7854", [:mix], [{:bunt, "~> 0.2.1", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2.8", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "41e110bfb007f7eda7f897c10bf019ceab9a0b269ce79f015d54b0dcf4fc7dd3"}, "crypt": {:git, "https://github.com/msantos/crypt.git", "f75cd55325e33cbea198fb41fe41871392f8fb76", [ref: "f75cd55325e33cbea198fb41fe41871392f8fb76"]}, "custom_base": {:hex, :custom_base, "0.2.1", "4a832a42ea0552299d81652aa0b1f775d462175293e99dfbe4d7dbaab785a706", [:mix], [], "hexpm", "8df019facc5ec9603e94f7270f1ac73ddf339f56ade76a721eaa57c1493ba463"}, "db_connection": {:hex, :db_connection, "2.4.3", "3b9aac9f27347ec65b271847e6baeb4443d8474289bd18c1d6f4de655b70c94d", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c127c15b0fa6cfb32eed07465e05da6c815b032508d4ed7c116122871df73c12"}, @@ -112,6 +112,9 @@ "table_rex": {:hex, :table_rex, "3.1.1", "0c67164d1714b5e806d5067c1e96ff098ba7ae79413cc075973e17c38a587caa", [:mix], [], "hexpm", "678a23aba4d670419c23c17790f9dcd635a4a89022040df7d5d772cb21012490"}, "telemetry": {:hex, :telemetry, "0.4.3", "a06428a514bdbc63293cd9a6263aad00ddeb66f608163bdec7c8995784080818", [:rebar3], [], "hexpm", "eb72b8365ffda5bed68a620d1da88525e326cb82a75ee61354fc24b844768041"}, "telemetry_metrics": {:hex, :telemetry_metrics, "0.6.1", "315d9163a1d4660aedc3fee73f33f1d355dcc76c5c3ab3d59e76e3edf80eef1f", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7be9e0871c41732c233be71e4be11b96e56177bf15dde64a8ac9ce72ac9834c6"}, + "telemetry_metrics_prometheus": {:hex, :telemetry_metrics_prometheus, "1.1.0", "1cc23e932c1ef9aa3b91db257ead31ea58d53229d407e059b29bb962c1505a13", [:mix], [{:plug_cowboy, "~> 2.1", [hex: :plug_cowboy, repo: "hexpm", optional: false]}, {:telemetry_metrics_prometheus_core, "~> 1.0", [hex: :telemetry_metrics_prometheus_core, repo: "hexpm", optional: false]}], "hexpm", "d43b3659b3244da44fe0275b717701542365d4519b79d9ce895b9719c1ce4d26"}, + "telemetry_metrics_prometheus_core": {:hex, :telemetry_metrics_prometheus_core, "1.1.0", "4e15f6d7dbedb3a4e3aed2262b7e1407f166fcb9c30ca3f96635dfbbef99965c", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "0dd10e7fe8070095df063798f82709b0a1224c31b8baf6278b423898d591a069"}, + "telemetry_poller": {:hex, :telemetry_poller, "0.5.1", "21071cc2e536810bac5628b935521ff3e28f0303e770951158c73eaaa01e962a", [:rebar3], [{:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "4cab72069210bc6e7a080cec9afffad1b33370149ed5d379b81c7c5f0c663fd4"}, "temple": {:git, "https://akkoma.dev/AkkomaGang/temple.git", "066a699ade472d8fa42a9d730b29a61af9bc8b59", [ref: "066a699ade472d8fa42a9d730b29a61af9bc8b59"]}, "tesla": {:hex, :tesla, "1.4.4", "bb89aa0c9745190930366f6a2ac612cdf2d0e4d7fff449861baa7875afd797b2", [:mix], [{:castore, "~> 0.1", [hex: :castore, repo: "hexpm", optional: true]}, {:exjsx, ">= 3.0.0", [hex: :exjsx, repo: "hexpm", optional: true]}, {:finch, "~> 0.3", [hex: :finch, repo: "hexpm", optional: true]}, {:fuse, "~> 2.4", [hex: :fuse, repo: "hexpm", optional: true]}, {:gun, "~> 1.3", [hex: :gun, repo: "hexpm", optional: true]}, {:hackney, "~> 1.6", [hex: :hackney, repo: "hexpm", optional: true]}, {:ibrowse, "4.4.0", [hex: :ibrowse, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: true]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.0", [hex: :mint, repo: "hexpm", optional: true]}, {:poison, ">= 1.0.0", [hex: :poison, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "d5503a49f9dec1b287567ea8712d085947e247cb11b06bc54adb05bfde466457"}, "timex": {:hex, :timex, "3.7.9", "790cdfc4acfce434e442f98c02ea6d84d0239073bfd668968f82ac63e9a6788d", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.10", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 1.1", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm", "64691582e5bb87130f721fc709acfb70f24405833998fabf35be968984860ce1"}, From 1e9c2cd8ef1da5cf6803d690b14e4b956b0b2c38 Mon Sep 17 00:00:00 2001 From: Tim Buchwaldt Date: Sat, 12 Nov 2022 11:23:44 +0100 Subject: [PATCH 139/631] Fix buckets for query timing --- lib/pleroma/web/telemetry.ex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pleroma/web/telemetry.ex b/lib/pleroma/web/telemetry.ex index f7e9d5ca7..546c39f05 100644 --- a/lib/pleroma/web/telemetry.ex +++ b/lib/pleroma/web/telemetry.ex @@ -37,7 +37,7 @@ def metrics do unit: {:native, :second}, tags: [:route], reporter_options: [ - buckets: [0.01, 0.025, 0.05, 0.1, 0.2, 0.5, 1, 2.5, 5, 10] + buckets: [0.1, 0.2, 0.5, 1, 2.5, 5, 10, 25, 50, 100, 250, 500, 1000] ] ), @@ -48,7 +48,7 @@ def metrics do measurement: :total_time, unit: {:native, :millisecond}, reporter_options: [ - buckets: [0.01, 0.025, 0.05, 0.1, 0.2, 0.5, 1, 2.5, 5, 10] + buckets: [0.1, 0.2, 0.5, 1, 2.5, 5, 10, 25, 50, 100, 250, 500, 1000] ] ), distribution( From a06bb694c1776a9144746237991a43f53c63e634 Mon Sep 17 00:00:00 2001 From: Tim Buchwaldt Date: Sat, 12 Nov 2022 11:31:03 +0100 Subject: [PATCH 140/631] Listen to loopback --- lib/pleroma/web/telemetry.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pleroma/web/telemetry.ex b/lib/pleroma/web/telemetry.ex index 546c39f05..2ca188e1a 100644 --- a/lib/pleroma/web/telemetry.ex +++ b/lib/pleroma/web/telemetry.ex @@ -14,7 +14,7 @@ def init(_arg) do {:telemetry_poller, measurements: periodic_measurements(), period: 10_000}, # Add reporters as children of your supervision tree. # {Telemetry.Metrics.ConsoleReporter, metrics: metrics()}, - {TelemetryMetricsPrometheus, metrics: metrics()} + {TelemetryMetricsPrometheus, metrics: metrics(), plug_cowboy_opts: [ip: {127, 0, 0, 1}]} ] Supervisor.init(children, strategy: :one_for_one) From f8d338317918cd62ebe45c3ea6433425b1cb1b28 Mon Sep 17 00:00:00 2001 From: Tim Buchwaldt Date: Sat, 12 Nov 2022 11:54:35 +0100 Subject: [PATCH 141/631] Fix oban tags --- lib/pleroma/web/telemetry.ex | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/pleroma/web/telemetry.ex b/lib/pleroma/web/telemetry.ex index 2ca188e1a..505ee382c 100644 --- a/lib/pleroma/web/telemetry.ex +++ b/lib/pleroma/web/telemetry.ex @@ -75,7 +75,8 @@ def metrics do "oban.job.stop", event_name: [:oban, :job, :stop], measurement: :duration, - tags: [:job], + tags: [:worker], + tag_values: fn tags -> Map.put(tags, :worker, tags.job.worker) end, unit: {:native, :second}, reporter_options: [ buckets: [0.01, 0.025, 0.05, 0.1, 0.2, 0.5, 1, 2.5, 5, 10] From 8f58eb4a183e97e28850d7030beeb7b13294d318 Mon Sep 17 00:00:00 2001 From: Tim Buchwaldt Date: Sat, 12 Nov 2022 12:38:25 +0100 Subject: [PATCH 142/631] Revert "Bump live-dashboard" This reverts commit c196d79aafd51b671aa19032b32e4cd416dab720. --- mix.exs | 2 +- mix.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mix.exs b/mix.exs index b5b7efd0c..cb46e8da3 100644 --- a/mix.exs +++ b/mix.exs @@ -185,7 +185,7 @@ defp deps do git: "https://github.com/FloatingGhost/pleroma-contrib-search-parser.git", ref: "08971a81e68686f9ac465cfb6661d51c5e4e1e7f"}, {:nimble_parsec, "~> 1.0", override: true}, - {:phoenix_live_dashboard, "~> 0.7.2"}, + {:phoenix_live_dashboard, "~> 0.6.2"}, {:ecto_psql_extras, "~> 0.6"}, {:elasticsearch, git: "https://akkoma.dev/AkkomaGang/elasticsearch-elixir.git", ref: "main"}, diff --git a/mix.lock b/mix.lock index 01c628c29..62f481d83 100644 --- a/mix.lock +++ b/mix.lock @@ -85,8 +85,8 @@ "phoenix": {:hex, :phoenix, "1.6.15", "0a1d96bbc10747fd83525370d691953cdb6f3ccbac61aa01b4acb012474b047d", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 1.0 or ~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: false]}, {:plug, "~> 1.10", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.2", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "d70ab9fbf6b394755ea88b644d34d79d8b146e490973151f248cacd122d20672"}, "phoenix_ecto": {:hex, :phoenix_ecto, "4.4.0", "0672ed4e4808b3fbed494dded89958e22fb882de47a97634c0b13e7b0b5f7720", [:mix], [{:ecto, "~> 3.3", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "09864e558ed31ee00bd48fcc1d4fc58ae9678c9e81649075431e69dbabb43cc1"}, "phoenix_html": {:hex, :phoenix_html, "3.2.0", "1c1219d4b6cb22ac72f12f73dc5fad6c7563104d083f711c3fcd8551a1f4ae11", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "36ec97ba56d25c0136ef1992c37957e4246b649d620958a1f9fa86165f8bc54f"}, - "phoenix_live_dashboard": {:hex, :phoenix_live_dashboard, "0.7.2", "97cc4ff2dba1ebe504db72cb45098cb8e91f11160528b980bd282cc45c73b29c", [:mix], [{:ecto, "~> 3.6.2 or ~> 3.7", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_mysql_extras, "~> 0.5", [hex: :ecto_mysql_extras, repo: "hexpm", optional: true]}, {:ecto_psql_extras, "~> 0.7", [hex: :ecto_psql_extras, repo: "hexpm", optional: true]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.18.3", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6 or ~> 1.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "0e5fdf063c7a3b620c566a30fcf68b7ee02e5e46fe48ee46a6ec3ba382dc05b7"}, - "phoenix_live_view": {:hex, :phoenix_live_view, "0.18.3", "2e3d009422addf8b15c3dccc65ce53baccbe26f7cfd21d264680b5867789a9c1", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.15 or ~> 1.7.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.1", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c8845177a866e017dcb7083365393c8f00ab061b8b6b2bda575891079dce81b2"}, + "phoenix_live_dashboard": {:hex, :phoenix_live_dashboard, "0.6.5", "1495bb014be12c9a9252eca04b9af54246f6b5c1e4cd1f30210cd00ec540cf8e", [:mix], [{:ecto, "~> 3.6.2 or ~> 3.7", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_mysql_extras, "~> 0.3", [hex: :ecto_mysql_extras, repo: "hexpm", optional: true]}, {:ecto_psql_extras, "~> 0.7", [hex: :ecto_psql_extras, repo: "hexpm", optional: true]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.17.7", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "ef4fa50dd78364409039c99cf6f98ab5209b4c5f8796c17f4db118324f0db852"}, + "phoenix_live_view": {:hex, :phoenix_live_view, "0.17.12", "74f4c0ad02d7deac2d04f50b52827a5efdc5c6e7fac5cede145f5f0e4183aedc", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.0 or ~> 1.7.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.1", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "af6dd5e0aac16ff43571f527a8e0616d62cb80b10eb87aac82170243e50d99c8"}, "phoenix_pubsub": {:hex, :phoenix_pubsub, "2.1.1", "ba04e489ef03763bf28a17eb2eaddc2c20c6d217e2150a61e3298b0f4c2012b5", [:mix], [], "hexpm", "81367c6d1eea5878ad726be80808eb5a787a23dee699f96e72b1109c57cdd8d9"}, "phoenix_swoosh": {:hex, :phoenix_swoosh, "0.3.4", "615f8f393135de7e0cbb4bd00ba238b1e0cd324b0d90efbaee613c2f02ca5e5c", [:mix], [{:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:swoosh, "~> 1.0", [hex: :swoosh, repo: "hexpm", optional: false]}], "hexpm", "3971221846232021ab5e3c7489fd62ec5bfd6a2e01cae10a317ccf6fb350571c"}, "phoenix_template": {:hex, :phoenix_template, "1.0.0", "c57bc5044f25f007dc86ab21895688c098a9f846a8dda6bc40e2d0ddc146e38f", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "1b066f99a26fd22064c12b2600a9a6e56700f591bf7b20b418054ea38b4d4357"}, From 0995fa141062f2aef1ee017ca03c7f9522dc3da8 Mon Sep 17 00:00:00 2001 From: Tim Buchwaldt Date: Sat, 12 Nov 2022 12:42:53 +0100 Subject: [PATCH 143/631] Track oban failures --- lib/pleroma/web/telemetry.ex | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/lib/pleroma/web/telemetry.ex b/lib/pleroma/web/telemetry.ex index 505ee382c..d9c54c28f 100644 --- a/lib/pleroma/web/telemetry.ex +++ b/lib/pleroma/web/telemetry.ex @@ -72,7 +72,7 @@ def metrics do summary("vm.total_run_queue_lengths.cpu"), summary("vm.total_run_queue_lengths.io"), distribution( - "oban.job.stop", + "oban_job_completion", event_name: [:oban, :job, :stop], measurement: :duration, tags: [:worker], @@ -81,6 +81,17 @@ def metrics do reporter_options: [ buckets: [0.01, 0.025, 0.05, 0.1, 0.2, 0.5, 1, 2.5, 5, 10] ] + ), + distribution( + "oban_job_exception", + event_name: [:oban, :job, :exception], + measurement: :duration, + tags: [:worker], + tag_values: fn tags -> Map.put(tags, :worker, tags.job.worker) end, + unit: {:native, :second}, + reporter_options: [ + buckets: [0.01, 0.025, 0.05, 0.1, 0.2, 0.5, 1, 2.5, 5, 10] + ] ) ] end From 63be819661cd28514207bbc19be6d4964235685b Mon Sep 17 00:00:00 2001 From: Tim Buchwaldt Date: Sat, 12 Nov 2022 16:11:38 +0100 Subject: [PATCH 144/631] Take tesla telemetry --- lib/pleroma/http.ex | 2 +- lib/pleroma/web/telemetry.ex | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/lib/pleroma/http.ex b/lib/pleroma/http.ex index d8028651c..6ae1cdebb 100644 --- a/lib/pleroma/http.ex +++ b/lib/pleroma/http.ex @@ -65,7 +65,7 @@ def request(method, url, body, headers, options) when is_binary(url) do options = put_in(options[:adapter], adapter_opts) params = options[:params] || [] request = build_request(method, headers, options, url, body, params) - client = Tesla.client([Tesla.Middleware.FollowRedirects]) + client = Tesla.client([Tesla.Middleware.FollowRedirects, Tesla.Middleware.Telemetry]) request(client, request) end diff --git a/lib/pleroma/web/telemetry.ex b/lib/pleroma/web/telemetry.ex index d9c54c28f..46b5865f7 100644 --- a/lib/pleroma/web/telemetry.ex +++ b/lib/pleroma/web/telemetry.ex @@ -92,6 +92,17 @@ def metrics do reporter_options: [ buckets: [0.01, 0.025, 0.05, 0.1, 0.2, 0.5, 1, 2.5, 5, 10] ] + ), + distribution( + "tesla_request_completed", + event_name: [:tesla, :request, :stop], + measurement: :duration, + tags: [:response_code], + tag_values: fn tags -> Map.put(tags, :response_code, tags.env.status) end, + unit: {:native, :second}, + reporter_options: [ + buckets: [0.01, 0.025, 0.05, 0.1, 0.2, 0.5, 1, 2.5, 5, 10] + ] ) ] end From 29584197bb53a6fb5f980cc8d2566b0492196def Mon Sep 17 00:00:00 2001 From: Tim Buchwaldt Date: Sat, 12 Nov 2022 17:13:39 +0100 Subject: [PATCH 145/631] Measure stats-data --- lib/pleroma/application.ex | 4 ++-- lib/pleroma/web/telemetry.ex | 17 +++++++++++++++-- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex index ad768b0e0..02336d6d1 100644 --- a/lib/pleroma/application.ex +++ b/lib/pleroma/application.ex @@ -64,7 +64,6 @@ def start(_type, _args) do Config.TransferTask, Pleroma.Emoji, Pleroma.Web.Plugs.RateLimiter.Supervisor, - Pleroma.Web.Telemetry, {Task.Supervisor, name: Pleroma.TaskSupervisor} ] ++ cachex_children() ++ @@ -74,7 +73,8 @@ def start(_type, _args) do Pleroma.JobQueueMonitor, {Majic.Pool, [name: Pleroma.MajicPool, pool_size: Config.get([:majic_pool, :size], 2)]}, {Oban, Config.get(Oban)}, - Pleroma.Web.Endpoint + Pleroma.Web.Endpoint, + Pleroma.Web.Telemetry ] ++ elasticsearch_children() ++ task_children(@mix_env) ++ diff --git a/lib/pleroma/web/telemetry.ex b/lib/pleroma/web/telemetry.ex index 46b5865f7..73ce6a85c 100644 --- a/lib/pleroma/web/telemetry.ex +++ b/lib/pleroma/web/telemetry.ex @@ -1,6 +1,7 @@ defmodule Pleroma.Web.Telemetry do use Supervisor import Telemetry.Metrics + alias Pleroma.Stats def start_link(arg) do Supervisor.start_link(__MODULE__, arg, name: __MODULE__) @@ -103,11 +104,23 @@ def metrics do reporter_options: [ buckets: [0.01, 0.025, 0.05, 0.1, 0.2, 0.5, 1, 2.5, 5, 10] ] - ) + ), + last_value("pleroma.local_users.total"), + last_value("pleroma.domains.total"), + last_value("pleroma.local_statuses.total") ] end defp periodic_measurements do - [] + [ + {__MODULE__, :instance_stats, []} + ] + end + + def instance_stats do + stats = Stats.get_stats() + :telemetry.execute([:pleroma, :local_users], %{total: stats.user_count}, %{}) + :telemetry.execute([:pleroma, :domains], %{total: stats.domain_count}, %{}) + :telemetry.execute([:pleroma, :local_statuses], %{total: stats.status_count}, %{}) end end From e2320f870e6ef4e8fc9f63282cbd459e819d740a Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Thu, 15 Dec 2022 02:02:07 +0000 Subject: [PATCH 146/631] Add prometheus metrics to router --- .../controllers/metrics_controller.ex | 16 ++++ lib/pleroma/web/endpoint.ex | 1 + lib/pleroma/web/plugs/csp_nonce_plug.ex | 21 +++++ lib/pleroma/web/plugs/http_security_plug.ex | 23 ++++-- lib/pleroma/web/router.ex | 3 +- lib/pleroma/web/telemetry.ex | 82 +++++++++++-------- mix.exs | 2 +- mix.lock | 6 +- 8 files changed, 104 insertions(+), 50 deletions(-) create mode 100644 lib/pleroma/web/akkoma_api/controllers/metrics_controller.ex create mode 100644 lib/pleroma/web/plugs/csp_nonce_plug.ex diff --git a/lib/pleroma/web/akkoma_api/controllers/metrics_controller.ex b/lib/pleroma/web/akkoma_api/controllers/metrics_controller.ex new file mode 100644 index 000000000..c8d3d8948 --- /dev/null +++ b/lib/pleroma/web/akkoma_api/controllers/metrics_controller.ex @@ -0,0 +1,16 @@ +defmodule Pleroma.Web.AkkomaAPI.MetricsController do + use Pleroma.Web, :controller + + alias Pleroma.Web.Plugs.OAuthScopesPlug + + @unauthenticated_access %{fallback: :proceed_unauthenticated, scopes: []} + plug(:skip_auth) + + + def show(conn, _params) do + stats = TelemetryMetricsPrometheus.Core.scrape() + + conn + |> text(stats) + end +end diff --git a/lib/pleroma/web/endpoint.ex b/lib/pleroma/web/endpoint.ex index baf0c5651..e3a251ca1 100644 --- a/lib/pleroma/web/endpoint.ex +++ b/lib/pleroma/web/endpoint.ex @@ -13,6 +13,7 @@ defmodule Pleroma.Web.Endpoint do plug(Pleroma.Web.Plugs.SetLocalePlug) plug(CORSPlug) + plug(Pleroma.Web.Plugs.CSPNoncePlug) plug(Pleroma.Web.Plugs.HTTPSecurityPlug) plug(Pleroma.Web.Plugs.UploadedMedia) diff --git a/lib/pleroma/web/plugs/csp_nonce_plug.ex b/lib/pleroma/web/plugs/csp_nonce_plug.ex new file mode 100644 index 000000000..bc2c6fcd8 --- /dev/null +++ b/lib/pleroma/web/plugs/csp_nonce_plug.ex @@ -0,0 +1,21 @@ +defmodule Pleroma.Web.Plugs.CSPNoncePlug do + import Plug.Conn + + def init(opts) do + opts + end + + def call(conn, _opts) do + assign_csp_nonce(conn) + end + + defp assign_csp_nonce(conn) do + nonce = + :crypto.strong_rand_bytes(128) + |> Base.url_encode64() + |> binary_part(0, 15) + + conn + |> assign(:csp_nonce, nonce) + end +end diff --git a/lib/pleroma/web/plugs/http_security_plug.ex b/lib/pleroma/web/plugs/http_security_plug.ex index 47874a980..6593347ca 100644 --- a/lib/pleroma/web/plugs/http_security_plug.ex +++ b/lib/pleroma/web/plugs/http_security_plug.ex @@ -13,7 +13,7 @@ def init(opts), do: opts def call(conn, _options) do if Config.get([:http_security, :enabled]) do conn - |> merge_resp_headers(headers()) + |> merge_resp_headers(headers(conn)) |> maybe_send_sts_header(Config.get([:http_security, :sts])) else conn @@ -36,7 +36,8 @@ def custom_http_frontend_headers do end end - def headers do + @spec headers(Plug.Conn.t()) :: [{String.t(), String.t()}] + def headers(conn) do referrer_policy = Config.get([:http_security, :referrer_policy]) report_uri = Config.get([:http_security, :report_uri]) custom_http_frontend_headers = custom_http_frontend_headers() @@ -47,7 +48,7 @@ def headers do {"x-frame-options", "DENY"}, {"x-content-type-options", "nosniff"}, {"referrer-policy", referrer_policy}, - {"content-security-policy", csp_string()}, + {"content-security-policy", csp_string(conn)}, {"permissions-policy", "interest-cohort=()"} ] @@ -77,19 +78,18 @@ def headers do "default-src 'none'", "base-uri 'none'", "frame-ancestors 'none'", - "style-src 'self' 'unsafe-inline'", - "font-src 'self'", "manifest-src 'self'" ] @csp_start [Enum.join(static_csp_rules, ";") <> ";"] - defp csp_string do + defp csp_string(conn) do scheme = Config.get([Pleroma.Web.Endpoint, :url])[:scheme] static_url = Pleroma.Web.Endpoint.static_url() websocket_url = Pleroma.Web.Endpoint.websocket_url() report_uri = Config.get([:http_security, :report_uri]) - + %{assigns: %{csp_nonce: nonce}} = conn + nonce_tag = "nonce-" <> nonce img_src = "img-src 'self' data: blob:" media_src = "media-src 'self'" @@ -111,11 +111,14 @@ defp csp_string do ["connect-src 'self' blob: ", static_url, ?\s, websocket_url] end + style_src = "style-src 'self' '#{nonce_tag}'" + font_src = "font-src 'self' '#{nonce_tag}' data:" + script_src = if Config.get(:env) == :dev do - "script-src 'self' 'unsafe-eval'" + "script-src 'self' 'unsafe-eval' '#{nonce_tag}'" else - "script-src 'self'" + "script-src 'self' '#{nonce_tag}'" end report = if report_uri, do: ["report-uri ", report_uri, ";report-to csp-endpoint"] @@ -126,6 +129,8 @@ defp csp_string do |> add_csp_param(media_src) |> add_csp_param(connect_src) |> add_csp_param(script_src) + |> add_csp_param(font_src) + |> add_csp_param(style_src) |> add_csp_param(insecure) |> add_csp_param(report) |> :erlang.iolist_to_binary() diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index bcb5fb15e..c0ce645c4 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -467,6 +467,7 @@ defmodule Pleroma.Web.Router do scope "/api/v1/akkoma", Pleroma.Web.AkkomaAPI do pipe_through(:authenticated_api) + get("/metrics", MetricsController, :show) get("/translation/languages", TranslationController, :languages) get("/frontend_settings/:frontend_name", FrontendSettingsController, :list_profiles) @@ -867,7 +868,7 @@ defmodule Pleroma.Web.Router do scope "/" do pipe_through([:pleroma_html, :authenticate, :require_admin]) - live_dashboard("/phoenix/live_dashboard", metrics: Pleroma.Web.Telemetry) + live_dashboard("/phoenix/live_dashboard", metrics: {Pleroma.Web.Telemetry, :live_dashboard_metrics}, csp_nonce_assign_key: :csp_nonce) end # Test-only routes needed to test action dispatching and plug chain execution diff --git a/lib/pleroma/web/telemetry.ex b/lib/pleroma/web/telemetry.ex index 73ce6a85c..435f55799 100644 --- a/lib/pleroma/web/telemetry.ex +++ b/lib/pleroma/web/telemetry.ex @@ -10,27 +10,19 @@ def start_link(arg) do @impl true def init(_arg) do children = [ - # Telemetry poller will execute the given period measurements - # every 10_000ms. Learn more here: https://hexdocs.pm/telemetry_metrics {:telemetry_poller, measurements: periodic_measurements(), period: 10_000}, - # Add reporters as children of your supervision tree. - # {Telemetry.Metrics.ConsoleReporter, metrics: metrics()}, - {TelemetryMetricsPrometheus, metrics: metrics(), plug_cowboy_opts: [ip: {127, 0, 0, 1}]} + {TelemetryMetricsPrometheus, metrics: prometheus_metrics(), plug_cowboy_opts: [ip: {127, 0, 0, 1}]} ] Supervisor.init(children, strategy: :one_for_one) end - def metrics do + @doc """ + A seperate set of metrics for distributions because phoenix dashboard does NOT handle + them well + """ + defp distribution_metrics do [ - # Phoenix Metrics - summary("phoenix.endpoint.stop.duration", - unit: {:native, :millisecond} - ), - summary("phoenix.router_dispatch.stop.duration", - tags: [:route], - unit: {:native, :millisecond} - ), distribution( "phoenix.router_dispatch.stop.duration", # event_name: [:pleroma, :repo, :query, :total_time], @@ -61,28 +53,6 @@ def metrics do buckets: [0.01, 0.025, 0.05, 0.1, 0.2, 0.5, 1, 2.5, 5, 10] ] ), - summary("pleroma.repo.query.total_time", unit: {:native, :millisecond}), - summary("pleroma.repo.query.decode_time", unit: {:native, :millisecond}), - summary("pleroma.repo.query.query_time", unit: {:native, :millisecond}), - summary("pleroma.repo.query.queue_time", unit: {:native, :millisecond}), - summary("pleroma.repo.query.idle_time", unit: {:native, :millisecond}), - - # VM Metrics - summary("vm.memory.total", unit: {:byte, :kilobyte}), - summary("vm.total_run_queue_lengths.total"), - summary("vm.total_run_queue_lengths.cpu"), - summary("vm.total_run_queue_lengths.io"), - distribution( - "oban_job_completion", - event_name: [:oban, :job, :stop], - measurement: :duration, - tags: [:worker], - tag_values: fn tags -> Map.put(tags, :worker, tags.job.worker) end, - unit: {:native, :second}, - reporter_options: [ - buckets: [0.01, 0.025, 0.05, 0.1, 0.2, 0.5, 1, 2.5, 5, 10] - ] - ), distribution( "oban_job_exception", event_name: [:oban, :job, :exception], @@ -105,12 +75,52 @@ def metrics do buckets: [0.01, 0.025, 0.05, 0.1, 0.2, 0.5, 1, 2.5, 5, 10] ] ), + distribution( + "oban_job_completion", + event_name: [:oban, :job, :stop], + measurement: :duration, + tags: [:worker], + tag_values: fn tags -> Map.put(tags, :worker, tags.job.worker) end, + unit: {:native, :second}, + reporter_options: [ + buckets: [0.01, 0.025, 0.05, 0.1, 0.2, 0.5, 1, 2.5, 5, 10] + ] + ) + ] + end + + defp summary_metrics do + [ + # Phoenix Metrics + summary("phoenix.endpoint.stop.duration", + unit: {:native, :millisecond} + ), + summary("phoenix.router_dispatch.stop.duration", + tags: [:route], + unit: {:native, :millisecond} + ), + summary("pleroma.repo.query.total_time", unit: {:native, :millisecond}), + summary("pleroma.repo.query.decode_time", unit: {:native, :millisecond}), + summary("pleroma.repo.query.query_time", unit: {:native, :millisecond}), + summary("pleroma.repo.query.queue_time", unit: {:native, :millisecond}), + summary("pleroma.repo.query.idle_time", unit: {:native, :millisecond}), + + # VM Metrics + summary("vm.memory.total", unit: {:byte, :kilobyte}), + summary("vm.total_run_queue_lengths.total"), + summary("vm.total_run_queue_lengths.cpu"), + summary("vm.total_run_queue_lengths.io"), + + last_value("pleroma.local_users.total"), last_value("pleroma.domains.total"), last_value("pleroma.local_statuses.total") ] end + def prometheus_metrics, do: summary_metrics() ++ distribution_metrics() + def live_dashboard_metrics, do: summary_metrics() + defp periodic_measurements do [ {__MODULE__, :instance_stats, []} diff --git a/mix.exs b/mix.exs index cb46e8da3..b5b7efd0c 100644 --- a/mix.exs +++ b/mix.exs @@ -185,7 +185,7 @@ defp deps do git: "https://github.com/FloatingGhost/pleroma-contrib-search-parser.git", ref: "08971a81e68686f9ac465cfb6661d51c5e4e1e7f"}, {:nimble_parsec, "~> 1.0", override: true}, - {:phoenix_live_dashboard, "~> 0.6.2"}, + {:phoenix_live_dashboard, "~> 0.7.2"}, {:ecto_psql_extras, "~> 0.6"}, {:elasticsearch, git: "https://akkoma.dev/AkkomaGang/elasticsearch-elixir.git", ref: "main"}, diff --git a/mix.lock b/mix.lock index 62f481d83..4fa4c05ec 100644 --- a/mix.lock +++ b/mix.lock @@ -17,7 +17,7 @@ "cowboy": {:hex, :cowboy, "2.9.0", "865dd8b6607e14cf03282e10e934023a1bd8be6f6bacf921a7e2a96d800cd452", [:make, :rebar3], [{:cowlib, "2.11.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "2c729f934b4e1aa149aff882f57c6372c15399a20d54f65c8d67bef583021bde"}, "cowboy_telemetry": {:hex, :cowboy_telemetry, "0.3.1", "ebd1a1d7aff97f27c66654e78ece187abdc646992714164380d8a041eda16754", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "3a6efd3366130eab84ca372cbd4a7d3c3a97bdfcfb4911233b035d117063f0af"}, "cowlib": {:hex, :cowlib, "2.11.0", "0b9ff9c346629256c42ebe1eeb769a83c6cb771a6ee5960bd110ab0b9b872063", [:make, :rebar3], [], "hexpm", "2b3e9da0b21c4565751a6d4901c20d1b4cc25cbb7fd50d91d2ab6dd287bc86a9"}, - "credo": {:hex, :credo, "1.6.7", "323f5734350fd23a456f2688b9430e7d517afb313fbd38671b8a4449798a7854", [:mix], [{:bunt, "~> 0.2.1", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2.8", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "41e110bfb007f7eda7f897c10bf019ceab9a0b269ce79f015d54b0dcf4fc7dd3"}, + "credo": {:git, "https://github.com/rrrene/credo.git", "1c1b99ea41a457761383d81aaf6a606913996fe7", [ref: "1c1b99ea41a457761383d81aaf6a606913996fe7"]}, "crypt": {:git, "https://github.com/msantos/crypt.git", "f75cd55325e33cbea198fb41fe41871392f8fb76", [ref: "f75cd55325e33cbea198fb41fe41871392f8fb76"]}, "custom_base": {:hex, :custom_base, "0.2.1", "4a832a42ea0552299d81652aa0b1f775d462175293e99dfbe4d7dbaab785a706", [:mix], [], "hexpm", "8df019facc5ec9603e94f7270f1ac73ddf339f56ade76a721eaa57c1493ba463"}, "db_connection": {:hex, :db_connection, "2.4.3", "3b9aac9f27347ec65b271847e6baeb4443d8474289bd18c1d6f4de655b70c94d", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c127c15b0fa6cfb32eed07465e05da6c815b032508d4ed7c116122871df73c12"}, @@ -85,8 +85,8 @@ "phoenix": {:hex, :phoenix, "1.6.15", "0a1d96bbc10747fd83525370d691953cdb6f3ccbac61aa01b4acb012474b047d", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 1.0 or ~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: false]}, {:plug, "~> 1.10", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.2", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "d70ab9fbf6b394755ea88b644d34d79d8b146e490973151f248cacd122d20672"}, "phoenix_ecto": {:hex, :phoenix_ecto, "4.4.0", "0672ed4e4808b3fbed494dded89958e22fb882de47a97634c0b13e7b0b5f7720", [:mix], [{:ecto, "~> 3.3", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "09864e558ed31ee00bd48fcc1d4fc58ae9678c9e81649075431e69dbabb43cc1"}, "phoenix_html": {:hex, :phoenix_html, "3.2.0", "1c1219d4b6cb22ac72f12f73dc5fad6c7563104d083f711c3fcd8551a1f4ae11", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "36ec97ba56d25c0136ef1992c37957e4246b649d620958a1f9fa86165f8bc54f"}, - "phoenix_live_dashboard": {:hex, :phoenix_live_dashboard, "0.6.5", "1495bb014be12c9a9252eca04b9af54246f6b5c1e4cd1f30210cd00ec540cf8e", [:mix], [{:ecto, "~> 3.6.2 or ~> 3.7", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_mysql_extras, "~> 0.3", [hex: :ecto_mysql_extras, repo: "hexpm", optional: true]}, {:ecto_psql_extras, "~> 0.7", [hex: :ecto_psql_extras, repo: "hexpm", optional: true]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.17.7", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "ef4fa50dd78364409039c99cf6f98ab5209b4c5f8796c17f4db118324f0db852"}, - "phoenix_live_view": {:hex, :phoenix_live_view, "0.17.12", "74f4c0ad02d7deac2d04f50b52827a5efdc5c6e7fac5cede145f5f0e4183aedc", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.0 or ~> 1.7.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.1", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "af6dd5e0aac16ff43571f527a8e0616d62cb80b10eb87aac82170243e50d99c8"}, + "phoenix_live_dashboard": {:hex, :phoenix_live_dashboard, "0.7.2", "97cc4ff2dba1ebe504db72cb45098cb8e91f11160528b980bd282cc45c73b29c", [:mix], [{:ecto, "~> 3.6.2 or ~> 3.7", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_mysql_extras, "~> 0.5", [hex: :ecto_mysql_extras, repo: "hexpm", optional: true]}, {:ecto_psql_extras, "~> 0.7", [hex: :ecto_psql_extras, repo: "hexpm", optional: true]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.18.3", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6 or ~> 1.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "0e5fdf063c7a3b620c566a30fcf68b7ee02e5e46fe48ee46a6ec3ba382dc05b7"}, + "phoenix_live_view": {:hex, :phoenix_live_view, "0.18.3", "2e3d009422addf8b15c3dccc65ce53baccbe26f7cfd21d264680b5867789a9c1", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.15 or ~> 1.7.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.1", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c8845177a866e017dcb7083365393c8f00ab061b8b6b2bda575891079dce81b2"}, "phoenix_pubsub": {:hex, :phoenix_pubsub, "2.1.1", "ba04e489ef03763bf28a17eb2eaddc2c20c6d217e2150a61e3298b0f4c2012b5", [:mix], [], "hexpm", "81367c6d1eea5878ad726be80808eb5a787a23dee699f96e72b1109c57cdd8d9"}, "phoenix_swoosh": {:hex, :phoenix_swoosh, "0.3.4", "615f8f393135de7e0cbb4bd00ba238b1e0cd324b0d90efbaee613c2f02ca5e5c", [:mix], [{:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:swoosh, "~> 1.0", [hex: :swoosh, repo: "hexpm", optional: false]}], "hexpm", "3971221846232021ab5e3c7489fd62ec5bfd6a2e01cae10a317ccf6fb350571c"}, "phoenix_template": {:hex, :phoenix_template, "1.0.0", "c57bc5044f25f007dc86ab21895688c098a9f846a8dda6bc40e2d0ddc146e38f", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "1b066f99a26fd22064c12b2600a9a6e56700f591bf7b20b418054ea38b4d4357"}, From b8be8192fbfe8c27b457094e8d64ccb1c3a29f7f Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Fri, 16 Dec 2022 03:25:14 +0000 Subject: [PATCH 147/631] do not allow non-admins to register tokens with admin scopes this didn't actually _do_ anything in the past, the users would be prevented from accessing the resource, but they shouldn't be able to even create them --- lib/pleroma/web/o_auth/o_auth_controller.ex | 17 +-- lib/pleroma/web/o_auth/scopes.ex | 16 ++- .../web/o_auth/o_auth_controller_test.exs | 119 +++++++++++++----- 3 files changed, 110 insertions(+), 42 deletions(-) diff --git a/lib/pleroma/web/o_auth/o_auth_controller.ex b/lib/pleroma/web/o_auth/o_auth_controller.ex index 8f32e7219..3943ca449 100644 --- a/lib/pleroma/web/o_auth/o_auth_controller.ex +++ b/lib/pleroma/web/o_auth/o_auth_controller.ex @@ -211,11 +211,11 @@ defp handle_create_authorization_error( {:error, scopes_issue}, %{"authorization" => _} = params ) - when scopes_issue in [:unsupported_scopes, :missing_scopes] do + when scopes_issue in [:unsupported_scopes, :missing_scopes, :user_is_not_an_admin] do # Per https://github.com/tootsuite/mastodon/blob/ # 51e154f5e87968d6bb115e053689767ab33e80cd/app/controllers/api/base_controller.rb#L39 conn - |> put_flash(:error, dgettext("errors", "This action is outside the authorized scopes")) + |> put_flash(:error, dgettext("errors", "This action is outside of authorized scopes")) |> put_status(:unauthorized) |> authorize(params) end @@ -605,7 +605,7 @@ defp do_create_authorization( defp do_create_authorization(%User{} = user, %App{} = app, requested_scopes) when is_list(requested_scopes) do with {:account_status, :active} <- {:account_status, User.account_status(user)}, - {:ok, scopes} <- validate_scopes(app, requested_scopes), + {:ok, scopes} <- validate_scopes(user, app, requested_scopes), {:ok, auth} <- Authorization.create_authorization(app, user, scopes) do {:ok, auth} end @@ -637,15 +637,16 @@ defp build_and_response_mfa_token(user, auth) do end end - @spec validate_scopes(App.t(), map() | list()) :: + @spec validate_scopes(User.t(), App.t(), map() | list()) :: {:ok, list()} | {:error, :missing_scopes | :unsupported_scopes} - defp validate_scopes(%App{} = app, params) when is_map(params) do + defp validate_scopes(%User{} = user, %App{} = app, params) when is_map(params) do requested_scopes = Scopes.fetch_scopes(params, app.scopes) - validate_scopes(app, requested_scopes) + validate_scopes(user, app, requested_scopes) end - defp validate_scopes(%App{} = app, requested_scopes) when is_list(requested_scopes) do - Scopes.validate(requested_scopes, app.scopes) + defp validate_scopes(%User{} = user, %App{} = app, requested_scopes) + when is_list(requested_scopes) do + Scopes.validate(requested_scopes, app.scopes, user) end def default_redirect_uri(%App{} = app) do diff --git a/lib/pleroma/web/o_auth/scopes.ex b/lib/pleroma/web/o_auth/scopes.ex index ada43eae9..7fe04b912 100644 --- a/lib/pleroma/web/o_auth/scopes.ex +++ b/lib/pleroma/web/o_auth/scopes.ex @@ -56,12 +56,20 @@ def to_string(scopes), do: Enum.join(scopes, " ") @doc """ Validates scopes. """ - @spec validate(list() | nil, list()) :: - {:ok, list()} | {:error, :missing_scopes | :unsupported_scopes} - def validate(blank_scopes, _app_scopes) when blank_scopes in [nil, []], + @spec validate(list() | nil, list(), Pleroma.User.t()) :: + {:ok, list()} | {:error, :missing_scopes | :unsupported_scopes, :user_is_not_an_admin} + def validate(blank_scopes, _app_scopes, _user) when blank_scopes in [nil, []], do: {:error, :missing_scopes} - def validate(scopes, app_scopes) do + def validate(scopes, app_scopes, %Pleroma.User{is_admin: is_admin}) do + if !is_admin && contains_admin_scopes?(scopes) do + {:error, :user_is_not_an_admin} + else + validate_scopes_are_supported(scopes, app_scopes) + end + end + + defp validate_scopes_are_supported(scopes, app_scopes) do case OAuthScopesPlug.filter_descendants(scopes, app_scopes) do ^scopes -> {:ok, scopes} _ -> {:error, :unsupported_scopes} diff --git a/test/pleroma/web/o_auth/o_auth_controller_test.exs b/test/pleroma/web/o_auth/o_auth_controller_test.exs index 5a1258ec3..19a7dea60 100644 --- a/test/pleroma/web/o_auth/o_auth_controller_test.exs +++ b/test/pleroma/web/o_auth/o_auth_controller_test.exs @@ -693,45 +693,76 @@ test "with existing authentication and OOB `redirect_uri`, redirects to app with describe "POST /oauth/authorize" do test "redirects with oauth authorization, " <> - "granting requested app-supported scopes to both admin- and non-admin users" do + "granting requested app-supported scopes to both admin users" do app_scopes = ["read", "write", "admin", "secret_scope"] app = insert(:oauth_app, scopes: app_scopes) redirect_uri = OAuthController.default_redirect_uri(app) + scopes_subset = ["read:subscope", "write", "admin"] + admin = insert(:user, is_admin: true) + + # In case scope param is missing, expecting _all_ app-supported scopes to be granted + conn = + post( + build_conn(), + "/oauth/authorize", + %{ + "authorization" => %{ + "name" => admin.nickname, + "password" => "test", + "client_id" => app.client_id, + "redirect_uri" => redirect_uri, + "scope" => scopes_subset, + "state" => "statepassed" + } + } + ) + + target = redirected_to(conn) + assert target =~ redirect_uri + + query = URI.parse(target).query |> URI.query_decoder() |> Map.new() + + assert %{"state" => "statepassed", "code" => code} = query + auth = Repo.get_by(Authorization, token: code) + assert auth + assert auth.scopes == scopes_subset + end + + test "redirects with oauth authorization, " <> + "granting requested app-supported scopes for non-admin users" do + app_scopes = ["read", "write", "secret_scope", "admin"] + app = insert(:oauth_app, scopes: app_scopes) + redirect_uri = OAuthController.default_redirect_uri(app) non_admin = insert(:user, is_admin: false) - admin = insert(:user, is_admin: true) - scopes_subset = ["read:subscope", "write", "admin"] + scopes_subset = ["read:subscope", "write"] # In case scope param is missing, expecting _all_ app-supported scopes to be granted - for user <- [non_admin, admin], - {requested_scopes, expected_scopes} <- - %{scopes_subset => scopes_subset, nil: app_scopes} do - conn = - post( - build_conn(), - "/oauth/authorize", - %{ - "authorization" => %{ - "name" => user.nickname, - "password" => "test", - "client_id" => app.client_id, - "redirect_uri" => redirect_uri, - "scope" => requested_scopes, - "state" => "statepassed" - } + conn = + post( + build_conn(), + "/oauth/authorize", + %{ + "authorization" => %{ + "name" => non_admin.nickname, + "password" => "test", + "client_id" => app.client_id, + "redirect_uri" => redirect_uri, + "scope" => scopes_subset, + "state" => "statepassed" } - ) + } + ) - target = redirected_to(conn) - assert target =~ redirect_uri + target = redirected_to(conn) + assert target =~ redirect_uri - query = URI.parse(target).query |> URI.query_decoder() |> Map.new() + query = URI.parse(target).query |> URI.query_decoder() |> Map.new() - assert %{"state" => "statepassed", "code" => code} = query - auth = Repo.get_by(Authorization, token: code) - assert auth - assert auth.scopes == expected_scopes - end + assert %{"state" => "statepassed", "code" => code} = query + auth = Repo.get_by(Authorization, token: code) + assert auth + assert auth.scopes == scopes_subset end test "authorize from cookie" do @@ -739,6 +770,7 @@ test "authorize from cookie" do app = insert(:oauth_app) oauth_token = insert(:oauth_token, user: user, app: app) redirect_uri = OAuthController.default_redirect_uri(app) + IO.inspect(app) conn = build_conn() @@ -831,6 +863,33 @@ test "returns 401 for wrong credentials", %{conn: conn} do assert result =~ "Invalid Username/Password" end + test "returns 401 when attempting to use an admin scope with a non-admin", %{conn: conn} do + user = insert(:user) + app = insert(:oauth_app, scopes: ["admin"]) + redirect_uri = OAuthController.default_redirect_uri(app) + + result = + conn + |> post("/oauth/authorize", %{ + "authorization" => %{ + "name" => user.nickname, + "password" => "test", + "client_id" => app.client_id, + "redirect_uri" => redirect_uri, + "state" => "statepassed", + "scope" => Enum.join(app.scopes, " ") + } + }) + |> html_response(:unauthorized) + + # Keep the details + assert result =~ app.client_id + assert result =~ redirect_uri + + # Error message + assert result =~ "outside of authorized scopes" + end + test "returns 401 for missing scopes" do user = insert(:user, is_admin: false) app = insert(:oauth_app, scopes: ["read", "write", "admin"]) @@ -855,7 +914,7 @@ test "returns 401 for missing scopes" do assert result =~ redirect_uri # Error message - assert result =~ "This action is outside the authorized scopes" + assert result =~ "This action is outside of authorized scopes" end test "returns 401 for scopes beyond app scopes hierarchy", %{conn: conn} do @@ -882,7 +941,7 @@ test "returns 401 for scopes beyond app scopes hierarchy", %{conn: conn} do assert result =~ redirect_uri # Error message - assert result =~ "This action is outside the authorized scopes" + assert result =~ "This action is outside of authorized scopes" end end From c2054f82abbd67045de21e232e0731e6dbac55a0 Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Fri, 16 Dec 2022 03:32:51 +0000 Subject: [PATCH 148/631] allow users with admin:metrics to read app metrics --- .gitignore | 1 + .../controllers/metrics_controller.ex | 10 +- lib/pleroma/web/plugs/rate_limiter.ex | 6 +- lib/pleroma/web/router.ex | 7 +- lib/pleroma/web/telemetry.ex | 9 +- lib/pleroma/web/templates/layout/app.html.eex | 32 +++-- .../web/templates/layout/static_fe.html.eex | 4 +- .../o_auth/oob_authorization_created.html.eex | 10 +- .../web/templates/o_auth/o_auth/show.html.eex | 4 +- mix.exs | 2 +- priv/static/static-fe/forms.css | 114 ++++++++++++++++++ priv/static/static-fe/static-fe.css | 61 +++++++--- scripts/create_metrics_app.sh | 65 ++++++++++ test/support/factory.ex | 2 +- 14 files changed, 283 insertions(+), 44 deletions(-) create mode 100644 priv/static/static-fe/forms.css create mode 100755 scripts/create_metrics_app.sh diff --git a/.gitignore b/.gitignore index 14373fb8c..95b236af6 100644 --- a/.gitignore +++ b/.gitignore @@ -76,3 +76,4 @@ docs/site # docker stuff docker-db +*.iml diff --git a/lib/pleroma/web/akkoma_api/controllers/metrics_controller.ex b/lib/pleroma/web/akkoma_api/controllers/metrics_controller.ex index c8d3d8948..8d413bf58 100644 --- a/lib/pleroma/web/akkoma_api/controllers/metrics_controller.ex +++ b/lib/pleroma/web/akkoma_api/controllers/metrics_controller.ex @@ -3,9 +3,13 @@ defmodule Pleroma.Web.AkkomaAPI.MetricsController do alias Pleroma.Web.Plugs.OAuthScopesPlug - @unauthenticated_access %{fallback: :proceed_unauthenticated, scopes: []} - plug(:skip_auth) - + plug( + OAuthScopesPlug, + %{scopes: ["admin:metrics"]} + when action in [ + :show + ] + ) def show(conn, _params) do stats = TelemetryMetricsPrometheus.Core.scrape() diff --git a/lib/pleroma/web/plugs/rate_limiter.ex b/lib/pleroma/web/plugs/rate_limiter.ex index 5bebe0ad5..f5ca27f0c 100644 --- a/lib/pleroma/web/plugs/rate_limiter.ex +++ b/lib/pleroma/web/plugs/rate_limiter.ex @@ -197,7 +197,11 @@ defp incorporate_conn_info(action_settings, %{params: params} = conn) do }) end - defp ip(%{remote_ip: remote_ip}) do + defp ip(%{remote_ip: remote_ip}) when is_binary(remote_ip) do + remote_ip + end + + defp ip(%{remote_ip: remote_ip}) when is_tuple(remote_ip) do remote_ip |> Tuple.to_list() |> Enum.join(".") diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index c0ce645c4..f47041b0b 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -868,7 +868,11 @@ defmodule Pleroma.Web.Router do scope "/" do pipe_through([:pleroma_html, :authenticate, :require_admin]) - live_dashboard("/phoenix/live_dashboard", metrics: {Pleroma.Web.Telemetry, :live_dashboard_metrics}, csp_nonce_assign_key: :csp_nonce) + + live_dashboard("/phoenix/live_dashboard", + metrics: {Pleroma.Web.Telemetry, :live_dashboard_metrics}, + csp_nonce_assign_key: :csp_nonce + ) end # Test-only routes needed to test action dispatching and plug chain execution @@ -907,6 +911,7 @@ defmodule Pleroma.Web.Router do scope "/", Pleroma.Web.Fallback do get("/registration/:token", RedirectController, :registration_page) get("/:maybe_nickname_or_id", RedirectController, :redirector_with_meta) + get("/api/*path", RedirectController, :api_not_implemented) get("/*path", RedirectController, :redirector_with_preload) options("/*path", RedirectController, :empty) diff --git a/lib/pleroma/web/telemetry.ex b/lib/pleroma/web/telemetry.ex index 435f55799..5b01ee14d 100644 --- a/lib/pleroma/web/telemetry.ex +++ b/lib/pleroma/web/telemetry.ex @@ -11,16 +11,13 @@ def start_link(arg) do def init(_arg) do children = [ {:telemetry_poller, measurements: periodic_measurements(), period: 10_000}, - {TelemetryMetricsPrometheus, metrics: prometheus_metrics(), plug_cowboy_opts: [ip: {127, 0, 0, 1}]} + {TelemetryMetricsPrometheus.Core, metrics: prometheus_metrics()} ] Supervisor.init(children, strategy: :one_for_one) end - @doc """ - A seperate set of metrics for distributions because phoenix dashboard does NOT handle - them well - """ + # A seperate set of metrics for distributions because phoenix dashboard does NOT handle them well defp distribution_metrics do [ distribution( @@ -110,8 +107,6 @@ defp summary_metrics do summary("vm.total_run_queue_lengths.total"), summary("vm.total_run_queue_lengths.cpu"), summary("vm.total_run_queue_lengths.io"), - - last_value("pleroma.local_users.total"), last_value("pleroma.domains.total"), last_value("pleroma.local_statuses.total") diff --git a/lib/pleroma/web/templates/layout/app.html.eex b/lib/pleroma/web/templates/layout/app.html.eex index e33bada85..31e6ec52b 100644 --- a/lib/pleroma/web/templates/layout/app.html.eex +++ b/lib/pleroma/web/templates/layout/app.html.eex @@ -4,17 +4,33 @@ <%= Pleroma.Config.get([:instance, :name]) %> - + + - + +
+
- <%= @inner_content %> +
+
+
+ <%= @inner_content %> +
+
+ + diff --git a/lib/pleroma/web/templates/layout/static_fe.html.eex b/lib/pleroma/web/templates/layout/static_fe.html.eex index 3d55393f0..d159eb901 100644 --- a/lib/pleroma/web/templates/layout/static_fe.html.eex +++ b/lib/pleroma/web/templates/layout/static_fe.html.eex @@ -20,8 +20,8 @@
-
- <%= @inner_content %> +
+ <%= @inner_content %>