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/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/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 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; +} diff --git a/test/mix/tasks/pleroma/database_test.exs b/test/mix/tasks/pleroma/database_test.exs index 9edb2c115..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 @@ -45,21 +46,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 +74,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 +88,37 @@ 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 + test "it cleans up bookmarks", %{old_insert_date: old_insert_date} do + user = insert(:user) + {:ok, old_object_activity} = CommonAPI.post(user, %{status: "yadayada"}) - date = - Timex.now() - |> Timex.shift(days: -deadline) - |> Timex.to_naive_datetime() - |> NaiveDateTime.truncate(:second) + 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) %{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 +128,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 +141,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 +227,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 +270,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 +329,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) 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 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