From d8bed0ff635d99bcd75207e5ee78fac6d3f186a4 Mon Sep 17 00:00:00 2001 From: provable_ascent Date: Thu, 27 Apr 2023 05:22:12 +0000 Subject: [PATCH 1/6] Make UserNote comment default to the empty string. This make the behavior consistent between when UserNote doesn't exist and when comment is null. The current behavior may return null in APIs, which misleads some clients doing feature detection into thinking the server does not support comments. For example, see https://codeberg.org/husky/husky/issues/92 --- lib/pleroma/user_note.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pleroma/user_note.ex b/lib/pleroma/user_note.ex index 5e82d359f..ff4981cb7 100644 --- a/lib/pleroma/user_note.ex +++ b/lib/pleroma/user_note.ex @@ -31,7 +31,7 @@ def show(%User{} = source, %User{} = target) do UserNote |> where(source_id: ^source.id, target_id: ^target.id) |> Repo.one() do - note.comment + note.comment || "" else _ -> "" end From f1e66b39c75071f990a49d803ab4b8fd9ac13fb3 Mon Sep 17 00:00:00 2001 From: midnight Date: Mon, 8 May 2023 18:52:19 -0400 Subject: [PATCH 2/6] Return empty string in the event of no detected language --- .../akkoma/translators/libre_translate.ex | 6 +++--- .../pleroma/translators/libre_translate_test.exs | 16 ++++++++++++++++ 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/lib/pleroma/akkoma/translators/libre_translate.ex b/lib/pleroma/akkoma/translators/libre_translate.ex index 3a8d9d827..5b08a6384 100644 --- a/lib/pleroma/akkoma/translators/libre_translate.ex +++ b/lib/pleroma/akkoma/translators/libre_translate.ex @@ -39,9 +39,9 @@ def translate(string, from_language, to_language) do detected = if Map.has_key?(body, "detectedLanguage") do get_in(body, ["detectedLanguage", "language"]) - else - from_language - end + else + from_language || "" + end {:ok, detected, translated} else diff --git a/test/pleroma/translators/libre_translate_test.exs b/test/pleroma/translators/libre_translate_test.exs index 3c81c3d76..a93f408f5 100644 --- a/test/pleroma/translators/libre_translate_test.exs +++ b/test/pleroma/translators/libre_translate_test.exs @@ -133,5 +133,21 @@ test "should gracefully handle an unsupported language" do assert {:error, "libre_translate: request failed (code 400)"} = LibreTranslate.translate("ギュギュ握りつぶしちゃうぞ", nil, "zoop") end + + test "should work when no detected language is received" do + Tesla.Mock.mock(fn + %{method: :post, url: "http://libre.translate/translate"} -> + %Tesla.Env{ + status: 200, + body: + Jason.encode!(%{ + translatedText: "I will crush you" + }) + } + end) + + assert {:ok, "", "I will crush you"} = + LibreTranslate.translate("ギュギュ握りつぶしちゃうぞ", nil, "en") + end end end From 9c4203632da7b6e0bd7edbe6e93dc97e748819cc Mon Sep 17 00:00:00 2001 From: provable_ascent Date: Fri, 12 May 2023 02:18:24 +0000 Subject: [PATCH 3/6] Add user_note_test.exs. --- test/pleroma/user_note_test.exs | 39 +++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 test/pleroma/user_note_test.exs diff --git a/test/pleroma/user_note_test.exs b/test/pleroma/user_note_test.exs new file mode 100644 index 000000000..7d818196e --- /dev/null +++ b/test/pleroma/user_note_test.exs @@ -0,0 +1,39 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.UserNoteTest do + alias Pleroma.UserNote + + use Pleroma.DataCase, async: false + import Pleroma.Factory + + describe "show/2" do + setup do + {:ok, users: insert_list(2, :user)} + end + + test "if record does not exist, returns empty string", %{users: [user1, user2]} do + comment = UserNote.show(user1, user2) + + assert comment == "" + end + + test "if record exists with comment == nil, returns empty string", %{users: [user1, user2]} do + UserNote.create(user1, user2, nil) + + comment = UserNote.show(user1, user2) + + assert comment == "" + end + + test "if record exists with non-nil comment, returns comment", %{users: [user1, user2]} do + expected_comment = "hello" + UserNote.create(user1, user2, expected_comment) + + comment = UserNote.show(user1, user2) + + assert comment == expected_comment + end + end +end From ddf4d8026dd3b99df042de82a91c124e36b428ce Mon Sep 17 00:00:00 2001 From: Denys Nykula Date: Thu, 18 May 2023 22:53:40 +0300 Subject: [PATCH 4/6] fix remote interaction form style --- priv/static/static-fe/forms.css | 41 ++++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/priv/static/static-fe/forms.css b/priv/static/static-fe/forms.css index 196713ea0..9d6085d1d 100644 --- a/priv/static/static-fe/forms.css +++ b/priv/static/static-fe/forms.css @@ -14,13 +14,13 @@ input { padding: 10px; margin-top: 5px; margin-bottom: 10px; - background-color: var(--background-color); - color: var(--primary-text-color); + background-color: transparent; + color: inherit; border: 0; transition-property: border-bottom; transition-duration: 0.35s; - border-bottom: 2px solid #2a384a; - font-size: 14px; + border-bottom: 2px solid var(--faint); + font: inherit; width: inherit; box-sizing: border-box; } @@ -91,26 +91,22 @@ [type="checkbox"]:checked+label:before { a.button, button { width: 100%; - background-color: #1c2a3a; - color: var(--primary-text-color); + background-color: var(--btn); + color: var(--btnText); border-radius: 4px; border: none; padding: 10px 16px; margin-top: 20px; margin-bottom: 20px; text-transform: uppercase; - font-size: 16px; - box-shadow: 0px 0px 2px 0px black, - 0px 1px 0px 0px rgba(255, 255, 255, 0.2) inset, - 0px -1px 0px 0px rgba(0, 0, 0, 0.2) inset; + box-shadow: var(--btnShadow); + font: inherit; } a.button:hover, button:hover { cursor: pointer; - box-shadow: 0px 0px 0px 1px var(--brand-color), - 0px 1px 0px 0px rgba(255, 255, 255, 0.2) inset, - 0px -1px 0px 0px rgba(0, 0, 0, 0.2) inset; + box-shadow: var(--btnHoverShadow); } .actions { @@ -155,4 +151,21 @@ .account-header__display-name { .account-header__nickname { font-size: 14px; color: var(--muted-text-color); -} \ No newline at end of file +} + +.oauth { + /* Remote interaction /main/ostatus has such hierarchy, and its header and + * content do not pad themselves: + * (.panel.oauth (h2) + * (form (input) + * (button))) */ + padding: 1px 1em; +} + +.oauth .container__content { + /* Frontend selection /oauth/authorize needs an inverse because its heading + * and content have their own background and padding: + * (.panel.oauth (form (.container__content (.panel-heading) + * (.panel-content)))) */ + margin: -1px -1em; +} From c7fb78cc32a91255f4bdc6af0db6b9c88b9e95b3 Mon Sep 17 00:00:00 2001 From: ilja Date: Sun, 21 May 2023 11:47:38 +0200 Subject: [PATCH 5/6] Move deadline and old_insert_date to setup Several tests for prune_objetcs need a date older than the deadline for pruning, so I moved that to the setup --- test/mix/tasks/pleroma/database_test.exs | 73 ++++++++---------------- 1 file changed, 23 insertions(+), 50 deletions(-) diff --git a/test/mix/tasks/pleroma/database_test.exs b/test/mix/tasks/pleroma/database_test.exs index 9edb2c115..21c365412 100644 --- a/test/mix/tasks/pleroma/database_test.exs +++ b/test/mix/tasks/pleroma/database_test.exs @@ -45,21 +45,25 @@ test "it replaces objects with references" do end describe "prune_objects" do - test "it prunes old objects from the database" do + setup do deadline = Pleroma.Config.get([:instance, :remote_post_retention_days]) + 1 - date = + old_insert_date = Timex.now() |> Timex.shift(days: -deadline) |> Timex.to_naive_datetime() |> NaiveDateTime.truncate(:second) + %{old_insert_date: old_insert_date} + end + + test "it prunes old objects from the database", %{old_insert_date: old_insert_date} do insert(:note) %{id: note_remote_public_id} = :note |> insert() - |> Ecto.Changeset.change(%{updated_at: date}) + |> Ecto.Changeset.change(%{updated_at: old_insert_date}) |> Repo.update!() note_remote_non_public = @@ -69,7 +73,7 @@ test "it prunes old objects from the database" do note_remote_non_public |> Ecto.Changeset.change(%{ - updated_at: date, + updated_at: old_insert_date, data: note_remote_non_public_data |> update_in(["to"], fn _ -> [] end) }) |> Repo.update!() @@ -83,21 +87,14 @@ test "it prunes old objects from the database" do refute Object.get_by_id(note_remote_non_public_id) end - test "with the --keep-non-public option it still keeps non-public posts even if they are not local" do - deadline = Pleroma.Config.get([:instance, :remote_post_retention_days]) + 1 - - date = - Timex.now() - |> Timex.shift(days: -deadline) - |> Timex.to_naive_datetime() - |> NaiveDateTime.truncate(:second) - + test "with the --keep-non-public option it still keeps non-public posts even if they are not local", + %{old_insert_date: old_insert_date} do insert(:note) %{id: note_remote_id} = :note |> insert() - |> Ecto.Changeset.change(%{updated_at: date}) + |> Ecto.Changeset.change(%{updated_at: old_insert_date}) |> Repo.update!() note_remote_non_public = @@ -107,7 +104,7 @@ test "with the --keep-non-public option it still keeps non-public posts even if note_remote_non_public |> Ecto.Changeset.change(%{ - updated_at: date, + updated_at: old_insert_date, data: note_remote_non_public_data |> update_in(["to"], fn _ -> [] end) }) |> Repo.update!() @@ -120,16 +117,10 @@ test "with the --keep-non-public option it still keeps non-public posts even if refute Object.get_by_id(note_remote_id) end - test "with the --keep-threads and --keep-non-public option it keeps old threads with non-public replies even if the interaction is not local" do + test "with the --keep-threads and --keep-non-public option it keeps old threads with non-public replies even if the interaction is not local", + %{old_insert_date: old_insert_date} do # For non-public we only check Create Activities because only these are relevant for threads # Flags are always non-public, Announces from relays can be non-public... - deadline = Pleroma.Config.get([:instance, :remote_post_retention_days]) + 1 - - old_insert_date = - Timex.now() - |> Timex.shift(days: -deadline) - |> Timex.to_naive_datetime() - |> NaiveDateTime.truncate(:second) remote_user1 = insert(:user, local: false) remote_user2 = insert(:user, local: false) @@ -212,15 +203,9 @@ test "with the --keep-threads option it still keeps non-old threads even with no assert length(Repo.all(Object)) == 2 end - test "with the --keep-threads option it deletes old threads with no local interaction" do - deadline = Pleroma.Config.get([:instance, :remote_post_retention_days]) + 1 - - old_insert_date = - Timex.now() - |> Timex.shift(days: -deadline) - |> Timex.to_naive_datetime() - |> NaiveDateTime.truncate(:second) - + test "with the --keep-threads option it deletes old threads with no local interaction", %{ + old_insert_date: old_insert_date + } do remote_user = insert(:user, local: false) remote_user2 = insert(:user, local: false) @@ -261,15 +246,9 @@ test "with the --keep-threads option it deletes old threads with no local intera assert length(Repo.all(Object)) == 0 end - test "with the --keep-threads option it keeps old threads with local interaction" do - deadline = Pleroma.Config.get([:instance, :remote_post_retention_days]) + 1 - - old_insert_date = - Timex.now() - |> Timex.shift(days: -deadline) - |> Timex.to_naive_datetime() - |> NaiveDateTime.truncate(:second) - + test "with the --keep-threads option it keeps old threads with local interaction", %{ + old_insert_date: old_insert_date + } do remote_user = insert(:user, local: false) local_user = insert(:user, local: true) @@ -326,15 +305,9 @@ test "with the --keep-threads option it keeps old threads with local interaction assert length(Repo.all(Object)) == 4 end - test "with the --keep-threads option it keeps old threads with bookmarked posts" do - deadline = Pleroma.Config.get([:instance, :remote_post_retention_days]) + 1 - - old_insert_date = - Timex.now() - |> Timex.shift(days: -deadline) - |> Timex.to_naive_datetime() - |> NaiveDateTime.truncate(:second) - + test "with the --keep-threads option it keeps old threads with bookmarked posts", %{ + old_insert_date: old_insert_date + } do remote_user = insert(:user, local: false) local_user = insert(:user, local: true) From f49e9e6d4cb7cfdd0c2fbb2ea74c82a7ec7d13e4 Mon Sep 17 00:00:00 2001 From: ilja Date: Sun, 21 May 2023 13:02:28 +0200 Subject: [PATCH 6/6] Clean up bookmarks after prune_objects When doing prune_objects, it's possible that bookmarked objects are deleted. This gave problems when fetching the bookmark TL. Here we clean up the bookmarks during pruning in the case were it's possible that bookmarked objects are deleted. --- lib/mix/tasks/pleroma/database.ex | 15 +++++++++++++++ test/mix/tasks/pleroma/database_test.exs | 24 ++++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/lib/mix/tasks/pleroma/database.ex b/lib/mix/tasks/pleroma/database.ex index 726a22d41..55d1c8ddc 100644 --- a/lib/mix/tasks/pleroma/database.ex +++ b/lib/mix/tasks/pleroma/database.ex @@ -171,6 +171,21 @@ def run(["prune_objects" | args]) do end |> Repo.delete_all(timeout: :infinity) + if !Keyword.get(options, :keep_threads) do + # Without the --keep-threads option, it's possible that bookmarked + # objects have been deleted. We remove the corresponding bookmarks. + """ + delete from public.bookmarks + where id in ( + select b.id from public.bookmarks b + left join public.activities a on b.activity_id = a.id + left join public.objects o on a."data" ->> 'object' = o.data ->> 'id' + where o.id is null + ) + """ + |> Repo.query([], timeout: :infinity) + end + if Keyword.get(options, :prune_orphaned_activities) do # Prune activities who link to a single object """ diff --git a/test/mix/tasks/pleroma/database_test.exs b/test/mix/tasks/pleroma/database_test.exs index 21c365412..40c5fd402 100644 --- a/test/mix/tasks/pleroma/database_test.exs +++ b/test/mix/tasks/pleroma/database_test.exs @@ -7,6 +7,7 @@ defmodule Mix.Tasks.Pleroma.DatabaseTest do use Oban.Testing, repo: Pleroma.Repo alias Pleroma.Activity + alias Pleroma.Bookmark alias Pleroma.Object alias Pleroma.Repo alias Pleroma.User @@ -87,6 +88,29 @@ test "it prunes old objects from the database", %{old_insert_date: old_insert_da refute Object.get_by_id(note_remote_non_public_id) end + test "it cleans up bookmarks", %{old_insert_date: old_insert_date} do + user = insert(:user) + {:ok, old_object_activity} = CommonAPI.post(user, %{status: "yadayada"}) + + Repo.one(Object) + |> Ecto.Changeset.change(%{updated_at: old_insert_date}) + |> Repo.update!() + + {:ok, new_object_activity} = CommonAPI.post(user, %{status: "yadayada"}) + + {:ok, _} = Bookmark.create(user.id, old_object_activity.id) + {:ok, _} = Bookmark.create(user.id, new_object_activity.id) + + assert length(Repo.all(Object)) == 2 + assert length(Repo.all(Bookmark)) == 2 + + Mix.Tasks.Pleroma.Database.run(["prune_objects"]) + + assert length(Repo.all(Object)) == 1 + assert length(Repo.all(Bookmark)) == 1 + refute Bookmark.get(user.id, old_object_activity.id) + end + test "with the --keep-non-public option it still keeps non-public posts even if they are not local", %{old_insert_date: old_insert_date} do insert(:note)