From 4745a41393cddd9bbc5a14affa77595204488b8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= Date: Thu, 10 Aug 2023 23:03:19 +0200 Subject: [PATCH 01/19] Allow to specify post language MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: marcin mikołajczak --- changelog.d/post-languages.add | 1 + lib/pleroma/constants.ex | 6 +- .../article_note_page_validator.ex | 1 + .../object_validators/common_fields.ex | 1 + .../web/activity_pub/transmogrifier.ex | 78 +++++++++++- lib/pleroma/web/activity_pub/utils.ex | 11 +- .../web/activity_pub/views/object_view.ex | 6 +- lib/pleroma/web/common_api/activity_draft.ex | 13 ++ lib/pleroma/web/common_api/utils.ex | 16 +++ .../web/mastodon_api/views/status_view.ex | 4 +- .../transmogrifier/note_handling_test.exs | 111 ++++++++++++++++++ .../web/activity_pub/transmogrifier_test.exs | 12 ++ test/pleroma/web/activity_pub/utils_test.exs | 34 ++++-- .../mastodon_api/views/status_view_test.exs | 10 ++ 14 files changed, 279 insertions(+), 25 deletions(-) create mode 100644 changelog.d/post-languages.add diff --git a/changelog.d/post-languages.add b/changelog.d/post-languages.add new file mode 100644 index 000000000..04b350f3f --- /dev/null +++ b/changelog.d/post-languages.add @@ -0,0 +1 @@ +Allow to specify post language \ No newline at end of file diff --git a/lib/pleroma/constants.ex b/lib/pleroma/constants.ex index 6befc6897..c2e577b49 100644 --- a/lib/pleroma/constants.ex +++ b/lib/pleroma/constants.ex @@ -19,7 +19,8 @@ defmodule Pleroma.Constants do "context_id", "deleted_activity_id", "pleroma_internal", - "generator" + "generator", + "language" ] ) @@ -38,7 +39,8 @@ defmodule Pleroma.Constants do "summary", "sensitive", "attachment", - "generator" + "generator", + "language" ] ) 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 2670e3f17..73101f20f 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 @@ -86,6 +86,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.ArticleNotePageValidator do |> fix_attachments() |> Transmogrifier.fix_emoji() |> Transmogrifier.fix_content_map() + |> Transmogrifier.maybe_add_language() end def changeset(struct, data) do diff --git a/lib/pleroma/web/activity_pub/object_validators/common_fields.ex b/lib/pleroma/web/activity_pub/object_validators/common_fields.ex index d580208df..5ed3ea023 100644 --- a/lib/pleroma/web/activity_pub/object_validators/common_fields.ex +++ b/lib/pleroma/web/activity_pub/object_validators/common_fields.ex @@ -57,6 +57,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CommonFields do field(:replies_count, :integer, default: 0) field(:like_count, :integer, default: 0) field(:announcement_count, :integer, default: 0) + field(:language, :string) field(:inReplyTo, ObjectValidators.ObjectID) field(:url, ObjectValidators.BareUri) diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index 0e6c429f9..732d878c4 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -22,6 +22,8 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do alias Pleroma.Web.Federator import Ecto.Query + import Pleroma.Web.CommonAPI.Utils, only: [is_good_locale_code?: 1] + import Pleroma.Web.Utils.Guards, only: [not_empty_string: 1] require Logger require Pleroma.Constants @@ -42,6 +44,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do |> fix_content_map() |> fix_addressing() |> fix_summary() + |> maybe_add_language() end def fix_summary(%{"summary" => nil} = object) do @@ -318,6 +321,8 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do def fix_tag(object), do: object + def fix_content_map(%{"content" => content} = object) when not_empty_string(content), do: object + # content map usually only has one language so this will do for now. def fix_content_map(%{"contentMap" => content_map} = object) do content_groups = Map.to_list(content_map) @@ -454,6 +459,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do |> strip_internal_fields() |> fix_type(fetch_options) |> fix_in_reply_to(fetch_options) + |> maybe_add_language_from_activity(data) data = Map.put(data, "object", object) options = Keyword.put(options, :local, false) @@ -679,6 +685,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do |> add_mention_tags |> add_emoji_tags |> add_attributed_to + |> maybe_add_content_map |> prepare_attachments |> set_conversation |> set_reply_to_uri @@ -722,7 +729,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do data = data |> Map.put("object", object) - |> Map.merge(Utils.make_json_ld_header()) + |> Map.merge(Utils.make_json_ld_header(data)) |> Map.delete("bcc") {:ok, data} @@ -737,7 +744,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do data = data |> Map.put("object", object) - |> Map.merge(Utils.make_json_ld_header()) + |> Map.merge(Utils.make_json_ld_header(data)) |> Map.delete("bcc") {:ok, data} @@ -758,7 +765,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do data = data |> strip_internal_fields - |> Map.merge(Utils.make_json_ld_header()) + |> Map.merge(Utils.make_json_ld_header(data)) |> Map.delete("bcc") {:ok, data} @@ -778,7 +785,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do data = data |> Map.put("object", object) - |> Map.merge(Utils.make_json_ld_header()) + |> Map.merge(Utils.make_json_ld_header(data)) {:ok, data} end @@ -796,7 +803,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do data = data |> Map.put("object", object) - |> Map.merge(Utils.make_json_ld_header()) + |> Map.merge(Utils.make_json_ld_header(data)) {:ok, data} end @@ -807,7 +814,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do data |> strip_internal_fields |> maybe_fix_object_url - |> Map.merge(Utils.make_json_ld_header()) + |> Map.merge(Utils.make_json_ld_header(data)) {:ok, data} end @@ -952,4 +959,63 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do def maybe_fix_user_url(data), do: data def maybe_fix_user_object(data), do: maybe_fix_user_url(data) + + defp maybe_add_content_map(%{"language" => language, "content" => content} = object) + when not_empty_string(language) do + Map.put(object, "contentMap", Map.put(%{}, language, content)) + end + + defp maybe_add_content_map(object), do: object + + def maybe_add_language(object) do + language = + [ + get_language_from_context(object), + get_language_from_content_map(object), + get_language_from_content(object) + ] + |> Enum.find(&is_good_locale_code?(&1)) + + if language do + Map.put(object, "language", language) + else + object + end + end + + def maybe_add_language_from_activity(object, activity) do + language = get_language_from_context(activity) + + if is_good_locale_code?(language) do + Map.put(object, "language", language) + else + object + end + end + + defp get_language_from_context(%{"@context" => context}) when is_list(context) do + case context + |> Enum.find(fn + %{"@language" => language} -> language != "und" + _ -> nil + end) do + %{"@language" => language} -> language + _ -> nil + end + end + + defp get_language_from_context(_), do: nil + + defp get_language_from_content_map(%{"contentMap" => content_map, "content" => source_content}) do + content_groups = Map.to_list(content_map) + + case Enum.find(content_groups, fn {_, content} -> content == source_content end) do + {language, _} -> language + _ -> nil + end + end + + defp get_language_from_content_map(_), do: nil + + defp get_language_from_content(_), do: nil end diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index 437220077..2866cf2ce 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -19,6 +19,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do alias Pleroma.Web.Router.Helpers import Ecto.Query + import Pleroma.Web.Utils.Guards, only: [not_empty_string: 1] require Logger require Pleroma.Constants @@ -108,18 +109,24 @@ defmodule Pleroma.Web.ActivityPub.Utils do end end - def make_json_ld_header do + def make_json_ld_header(data \\ %{}) do %{ "@context" => [ "https://www.w3.org/ns/activitystreams", "#{Endpoint.url()}/schemas/litepub-0.1.jsonld", %{ - "@language" => "und" + "@language" => get_language(data) } ] } end + defp get_language(%{"language" => language}) when not_empty_string(language) do + language + end + + defp get_language(_), do: "und" + def make_date do DateTime.utc_now() |> DateTime.to_iso8601() end diff --git a/lib/pleroma/web/activity_pub/views/object_view.ex b/lib/pleroma/web/activity_pub/views/object_view.ex index 63caa915c..13b5b2542 100644 --- a/lib/pleroma/web/activity_pub/views/object_view.ex +++ b/lib/pleroma/web/activity_pub/views/object_view.ex @@ -9,7 +9,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectView do alias Pleroma.Web.ActivityPub.Transmogrifier def render("object.json", %{object: %Object{} = object}) do - base = Pleroma.Web.ActivityPub.Utils.make_json_ld_header() + base = Pleroma.Web.ActivityPub.Utils.make_json_ld_header(object.data) additional = Transmogrifier.prepare_object(object.data) Map.merge(base, additional) @@ -17,7 +17,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectView do def render("object.json", %{object: %Activity{data: %{"type" => activity_type}} = activity}) when activity_type in ["Create", "Listen"] do - base = Pleroma.Web.ActivityPub.Utils.make_json_ld_header() + base = Pleroma.Web.ActivityPub.Utils.make_json_ld_header(activity.data) object = Object.normalize(activity, fetch: false) additional = @@ -28,7 +28,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectView do end def render("object.json", %{object: %Activity{} = activity}) do - base = Pleroma.Web.ActivityPub.Utils.make_json_ld_header() + base = Pleroma.Web.ActivityPub.Utils.make_json_ld_header(activity.data) object_id = Object.normalize(activity, id_only: true) additional = diff --git a/lib/pleroma/web/common_api/activity_draft.ex b/lib/pleroma/web/common_api/activity_draft.ex index 9af635da8..bcbb134bb 100644 --- a/lib/pleroma/web/common_api/activity_draft.ex +++ b/lib/pleroma/web/common_api/activity_draft.ex @@ -33,6 +33,7 @@ defmodule Pleroma.Web.CommonAPI.ActivityDraft do cc: [], context: nil, sensitive: false, + language: nil, object: nil, preview?: false, changes: %{} @@ -57,6 +58,7 @@ defmodule Pleroma.Web.CommonAPI.ActivityDraft do |> content() |> with_valid(&to_and_cc/1) |> with_valid(&context/1) + |> with_valid(&language/1) |> sensitive() |> with_valid(&object/1) |> preview?() @@ -190,6 +192,16 @@ defmodule Pleroma.Web.CommonAPI.ActivityDraft do %__MODULE__{draft | sensitive: sensitive} end + defp language(draft) do + language = draft.params[:language] + + if Utils.is_good_locale_code?(language) do + %__MODULE__{draft | language: language} + else + draft + end + end + defp object(draft) do emoji = Map.merge(Pleroma.Emoji.Formatter.get_emoji_map(draft.full_payload), draft.emoji) @@ -229,6 +241,7 @@ defmodule Pleroma.Web.CommonAPI.ActivityDraft do "mediaType" => Utils.get_content_type(draft.params[:content_type]) }) |> Map.put("generator", draft.params[:generator]) + |> Map.put("language", draft.language) %__MODULE__{draft | object: object} end diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex index b9fe0224c..28553c35a 100644 --- a/lib/pleroma/web/common_api/utils.ex +++ b/lib/pleroma/web/common_api/utils.ex @@ -494,4 +494,20 @@ defmodule Pleroma.Web.CommonAPI.Utils do {:error, dgettext("errors", "Too many attachments")} end end + + def is_good_locale_code?(code) when is_binary(code) do + code + |> String.codepoints() + |> Enum.all?(&valid_char?/1) + end + + def is_good_locale_code?(_code), do: false + + # [a-zA-Z0-9-] + defp valid_char?(char) do + ("a" <= char and char <= "z") or + ("A" <= char and char <= "Z") or + ("0" <= char and char <= "9") or + char == "-" + end end diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex index dea22f9c2..50d8ebde9 100644 --- a/lib/pleroma/web/mastodon_api/views/status_view.ex +++ b/lib/pleroma/web/mastodon_api/views/status_view.ex @@ -200,7 +200,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do mentions: mentions, tags: reblogged[:tags] || [], application: build_application(object.data["generator"]), - language: nil, + language: object.data["language"], emojis: [], pleroma: %{ local: activity.local, @@ -391,7 +391,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do mentions: mentions, tags: build_tags(tags), application: build_application(object.data["generator"]), - language: nil, + language: object.data["language"], emojis: build_emojis(object.data["emoji"]), pleroma: %{ local: activity.local, diff --git a/test/pleroma/web/activity_pub/transmogrifier/note_handling_test.exs b/test/pleroma/web/activity_pub/transmogrifier/note_handling_test.exs index a9ad3e9c8..8abc8a903 100644 --- a/test/pleroma/web/activity_pub/transmogrifier/note_handling_test.exs +++ b/test/pleroma/web/activity_pub/transmogrifier/note_handling_test.exs @@ -221,6 +221,36 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.NoteHandlingTest do "

@lain

" end + test "it only uses contentMap if content is not present" do + user = insert(:user) + + message = %{ + "@context" => "https://www.w3.org/ns/activitystreams", + "to" => ["https://www.w3.org/ns/activitystreams#Public"], + "cc" => [], + "type" => "Create", + "object" => %{ + "to" => ["https://www.w3.org/ns/activitystreams#Public"], + "cc" => [], + "id" => Utils.generate_object_id(), + "type" => "Note", + "content" => "Hi", + "contentMap" => %{ + "de" => "Hallo", + "uk" => "Привіт" + }, + "inReplyTo" => nil, + "attributedTo" => user.ap_id + }, + "actor" => user.ap_id + } + + {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(message) + object = Object.normalize(data["object"], fetch: false) + + assert object.data["content"] == "Hi" + end + test "it works for incoming notices with to/cc not being an array (kroeg)" do data = File.read!("test/fixtures/kroeg-post-activity.json") |> Jason.decode!() @@ -358,6 +388,87 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.NoteHandlingTest do end end + test "it detects language from context" do + user = insert(:user) + + message = %{ + "@context" => ["https://www.w3.org/ns/activitystreams", %{"@language" => "pl"}], + "to" => ["https://www.w3.org/ns/activitystreams#Public"], + "cc" => [], + "type" => "Create", + "object" => %{ + "to" => ["https://www.w3.org/ns/activitystreams#Public"], + "cc" => [], + "id" => Utils.generate_object_id(), + "type" => "Note", + "content" => "Szczęść Boże", + "attributedTo" => user.ap_id + }, + "actor" => user.ap_id + } + + {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(message) + object = Object.normalize(data["object"], fetch: false) + + assert object.data["language"] == "pl" + end + + test "it detects language from contentMap" do + user = insert(:user) + + message = %{ + "@context" => "https://www.w3.org/ns/activitystreams", + "to" => ["https://www.w3.org/ns/activitystreams#Public"], + "cc" => [], + "type" => "Create", + "object" => %{ + "to" => ["https://www.w3.org/ns/activitystreams#Public"], + "cc" => [], + "id" => Utils.generate_object_id(), + "type" => "Note", + "content" => "Szczęść Boże", + "contentMap" => %{ + "de" => "Gott segne", + "pl" => "Szczęść Boże" + }, + "attributedTo" => user.ap_id + }, + "actor" => user.ap_id + } + + {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(message) + object = Object.normalize(data["object"], fetch: false) + + assert object.data["language"] == "pl" + end + + test "it detects language from content" do + clear_config([Pleroma.Language.LanguageDetector, :provider], LanguageDetectorMock) + + user = insert(:user) + + message = %{ + "@context" => ["https://www.w3.org/ns/activitystreams"], + "to" => ["https://www.w3.org/ns/activitystreams#Public"], + "cc" => [], + "type" => "Create", + "object" => %{ + "to" => ["https://www.w3.org/ns/activitystreams#Public"], + "cc" => [], + "id" => Utils.generate_object_id(), + "type" => "Note", + "content" => "Dieu vous bénisse, Fédivers.", + "attributedTo" => user.ap_id + }, + "actor" => user.ap_id + } + + {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(message) + object = Object.normalize(data["object"], fetch: false) + + assert object.data["language"] == "fr" + end + describe "`handle_incoming/2`, Mastodon format `replies` handling" do setup do: clear_config([:activitypub, :note_replies_output_limit], 5) setup do: clear_config([:instance, :federation_incoming_replies_max_depth]) diff --git a/test/pleroma/web/activity_pub/transmogrifier_test.exs b/test/pleroma/web/activity_pub/transmogrifier_test.exs index 3e0c8dc65..a72edf79c 100644 --- a/test/pleroma/web/activity_pub/transmogrifier_test.exs +++ b/test/pleroma/web/activity_pub/transmogrifier_test.exs @@ -352,6 +352,18 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do end end + test "it adds contentMap if language is specified" do + user = insert(:user) + + {:ok, activity} = CommonAPI.post(user, %{status: "тест", language: "uk"}) + + {:ok, prepared} = Transmogrifier.prepare_outgoing(activity.data) + + assert prepared["object"]["contentMap"] == %{ + "uk" => "тест" + } + end + describe "actor rewriting" do test "it fixes the actor URL property to be a proper URI" do data = %{ diff --git a/test/pleroma/web/activity_pub/utils_test.exs b/test/pleroma/web/activity_pub/utils_test.exs index 3f93c872b..525bdb032 100644 --- a/test/pleroma/web/activity_pub/utils_test.exs +++ b/test/pleroma/web/activity_pub/utils_test.exs @@ -138,16 +138,30 @@ defmodule Pleroma.Web.ActivityPub.UtilsTest do end end - test "make_json_ld_header/0" do - assert Utils.make_json_ld_header() == %{ - "@context" => [ - "https://www.w3.org/ns/activitystreams", - "http://localhost:4001/schemas/litepub-0.1.jsonld", - %{ - "@language" => "und" - } - ] - } + describe "make_json_ld_header/1" do + test "makes jsonld header" do + assert Utils.make_json_ld_header() == %{ + "@context" => [ + "https://www.w3.org/ns/activitystreams", + "http://localhost:4001/schemas/litepub-0.1.jsonld", + %{ + "@language" => "und" + } + ] + } + end + + test "includes language if specified" do + assert Utils.make_json_ld_header(%{"language" => "pl"}) == %{ + "@context" => [ + "https://www.w3.org/ns/activitystreams", + "http://localhost:4001/schemas/litepub-0.1.jsonld", + %{ + "@language" => "pl" + } + ] + } + end end describe "get_existing_votes" do diff --git a/test/pleroma/web/mastodon_api/views/status_view_test.exs b/test/pleroma/web/mastodon_api/views/status_view_test.exs index b93335190..d6884ac2c 100644 --- a/test/pleroma/web/mastodon_api/views/status_view_test.exs +++ b/test/pleroma/web/mastodon_api/views/status_view_test.exs @@ -770,6 +770,16 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do assert status.edited_at end + test "it shows post language" do + user = insert(:user) + + {:ok, post} = CommonAPI.post(user, %{status: "Szczęść Boże", language: "pl"}) + + status = StatusView.render("show.json", activity: post) + + assert status.language == "pl" + end + test "with a source object" do note = insert(:note, From 049045cf2ac90dcca074be9b5cf2d8264828f834 Mon Sep 17 00:00:00 2001 From: Haelwenn Date: Fri, 11 Aug 2023 11:44:13 +0000 Subject: [PATCH 02/19] Apply lanodan's suggestion --- lib/pleroma/web/common_api/utils.ex | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex index 28553c35a..229e13504 100644 --- a/lib/pleroma/web/common_api/utils.ex +++ b/lib/pleroma/web/common_api/utils.ex @@ -494,20 +494,7 @@ defmodule Pleroma.Web.CommonAPI.Utils do {:error, dgettext("errors", "Too many attachments")} end end - - def is_good_locale_code?(code) when is_binary(code) do - code - |> String.codepoints() - |> Enum.all?(&valid_char?/1) - end + def is_good_locale_code?(code) when is_binary(code), do: code =~ ~r<[A-zA-Z0-9\-]+> def is_good_locale_code?(_code), do: false - - # [a-zA-Z0-9-] - defp valid_char?(char) do - ("a" <= char and char <= "z") or - ("A" <= char and char <= "Z") or - ("0" <= char and char <= "9") or - char == "-" - end end From 04c8f6b4d1e2a9a30f66b0ffb99d7a17a1510a3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= Date: Fri, 11 Aug 2023 13:44:30 +0200 Subject: [PATCH 03/19] Add ObjectValidators.LanguageCode type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: marcin mikołajczak --- .../object_validators/language_code.ex | 25 +++++++++++++++++ .../object_validators/common_fields.ex | 2 +- .../{bare_uri_test.ex => bare_uri_test.exs} | 10 +++---- .../object_validators/language_code.exs | 28 +++++++++++++++++++ 4 files changed, 59 insertions(+), 6 deletions(-) create mode 100644 lib/pleroma/ecto_type/activity_pub/object_validators/language_code.ex rename test/pleroma/ecto_type/activity_pub/object_validators/{bare_uri_test.ex => bare_uri_test.exs} (73%) create mode 100644 test/pleroma/ecto_type/activity_pub/object_validators/language_code.exs diff --git a/lib/pleroma/ecto_type/activity_pub/object_validators/language_code.ex b/lib/pleroma/ecto_type/activity_pub/object_validators/language_code.ex new file mode 100644 index 000000000..327279bf8 --- /dev/null +++ b/lib/pleroma/ecto_type/activity_pub/object_validators/language_code.ex @@ -0,0 +1,25 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2023 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.EctoType.ActivityPub.ObjectValidators.LanguageCode do + use Ecto.Type + + import Pleroma.Web.CommonAPI.Utils, only: [is_good_locale_code?: 1] + + def type, do: :string + + def cast(language) when is_binary(language) do + if is_good_locale_code?(language) do + {:ok, language} + else + {:error, :invalid_language} + end + end + + def cast(_), do: :error + + def dump(data), do: {:ok, data} + + def load(data), do: {:ok, data} +end diff --git a/lib/pleroma/web/activity_pub/object_validators/common_fields.ex b/lib/pleroma/web/activity_pub/object_validators/common_fields.ex index 5ed3ea023..7ba393270 100644 --- a/lib/pleroma/web/activity_pub/object_validators/common_fields.ex +++ b/lib/pleroma/web/activity_pub/object_validators/common_fields.ex @@ -57,7 +57,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CommonFields do field(:replies_count, :integer, default: 0) field(:like_count, :integer, default: 0) field(:announcement_count, :integer, default: 0) - field(:language, :string) + field(:language, ObjectValidators.LanguageCode) field(:inReplyTo, ObjectValidators.ObjectID) field(:url, ObjectValidators.BareUri) diff --git a/test/pleroma/ecto_type/activity_pub/object_validators/bare_uri_test.ex b/test/pleroma/ecto_type/activity_pub/object_validators/bare_uri_test.exs similarity index 73% rename from test/pleroma/ecto_type/activity_pub/object_validators/bare_uri_test.ex rename to test/pleroma/ecto_type/activity_pub/object_validators/bare_uri_test.exs index 226383c3c..760ecb465 100644 --- a/test/pleroma/ecto_type/activity_pub/object_validators/bare_uri_test.ex +++ b/test/pleroma/ecto_type/activity_pub/object_validators/bare_uri_test.exs @@ -9,17 +9,17 @@ defmodule Pleroma.EctoType.ActivityPub.ObjectValidators.BareUriTest do test "diaspora://" do text = "diaspora://alice@fediverse.example/post/deadbeefdeadbeefdeadbeefdeadbeef" - assert {:ok, text} = BareUri.cast(text) + assert {:ok, ^text} = BareUri.cast(text) end test "nostr:" do text = "nostr:note1gwdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef" - assert {:ok, text} = BareUri.cast(text) + assert {:ok, ^text} = BareUri.cast(text) end test "errors for non-URIs" do - assert :error == SafeText.cast(1) - assert :error == SafeText.cast("foo") - assert :error == SafeText.cast("foo bar") + assert :error == BareUri.cast(1) + assert :error == BareUri.cast("foo") + assert :error == BareUri.cast("foo bar") end end diff --git a/test/pleroma/ecto_type/activity_pub/object_validators/language_code.exs b/test/pleroma/ecto_type/activity_pub/object_validators/language_code.exs new file mode 100644 index 000000000..2261cc209 --- /dev/null +++ b/test/pleroma/ecto_type/activity_pub/object_validators/language_code.exs @@ -0,0 +1,28 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2023 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.EctoType.ActivityPub.ObjectValidators.LanguageCodeTest do + use Pleroma.DataCase, async: true + + alias Pleroma.EctoType.ActivityPub.ObjectValidators.LanguageCode + + test "it accepts language code" do + text = "pl" + assert {:ok, ^text} = LanguageCode.cast(text) + end + + test "it accepts language code with region" do + text = "pl-PL" + assert {:ok, ^text} = LanguageCode.cast(text) + end + + test "errors for invalid language code" do + assert {:error, :invalid_language} = LanguageCode.cast("ru_RU") + assert {:error, :invalid_language} = LanguageCode.cast(" ") + end + + test "errors for non-text" do + assert :error == LanguageCode.cast(42) + end +end From 366559c5a33c30de181782418cd1b52f65d0ca5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= Date: Fri, 11 Aug 2023 14:59:58 +0200 Subject: [PATCH 04/19] Make status.language == nil for 'und' value MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: marcin mikołajczak --- lib/pleroma/web/mastodon_api/views/status_view.ex | 8 ++++++-- .../web/mastodon_api/views/status_view_test.exs | 10 ++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex index 50d8ebde9..2ae5e14aa 100644 --- a/lib/pleroma/web/mastodon_api/views/status_view.ex +++ b/lib/pleroma/web/mastodon_api/views/status_view.ex @@ -200,7 +200,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do mentions: mentions, tags: reblogged[:tags] || [], application: build_application(object.data["generator"]), - language: object.data["language"], + language: get_language(object), emojis: [], pleroma: %{ local: activity.local, @@ -391,7 +391,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do mentions: mentions, tags: build_tags(tags), application: build_application(object.data["generator"]), - language: object.data["language"], + language: get_language(object), emojis: build_emojis(object.data["emoji"]), pleroma: %{ local: activity.local, @@ -756,4 +756,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do defp get_source_content_type(_source) do Utils.get_content_type(nil) end + + defp get_language(%{data: %{"language" => "und"}}), do: nil + + defp get_language(object), do: object.data["language"] end diff --git a/test/pleroma/web/mastodon_api/views/status_view_test.exs b/test/pleroma/web/mastodon_api/views/status_view_test.exs index d6884ac2c..8c53e6567 100644 --- a/test/pleroma/web/mastodon_api/views/status_view_test.exs +++ b/test/pleroma/web/mastodon_api/views/status_view_test.exs @@ -780,6 +780,16 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do assert status.language == "pl" end + test "doesn't show post language if it's 'und'" do + user = insert(:user) + + {:ok, post} = CommonAPI.post(user, %{status: "sdifjogijodfg", language: "und"}) + + status = StatusView.render("show.json", activity: post) + + assert status.language == nil + end + test "with a source object" do note = insert(:note, From b430b805c469b33b9862d8f402fa8e63e6bdee8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= Date: Fri, 11 Aug 2023 16:44:13 +0200 Subject: [PATCH 05/19] Lint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: marcin mikołajczak --- lib/pleroma/web/common_api/utils.ex | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex index 229e13504..05a5b818e 100644 --- a/lib/pleroma/web/common_api/utils.ex +++ b/lib/pleroma/web/common_api/utils.ex @@ -494,7 +494,8 @@ defmodule Pleroma.Web.CommonAPI.Utils do {:error, dgettext("errors", "Too many attachments")} end end - def is_good_locale_code?(code) when is_binary(code), do: code =~ ~r<[A-zA-Z0-9\-]+> + + def is_good_locale_code?(code) when is_binary(code), do: code =~ ~r<^[a-zA-Z0-9\-]+$> def is_good_locale_code?(_code), do: false end From 69d53a62388270a9807cfe1f96f3819287bc477a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= Date: Fri, 11 Aug 2023 16:45:26 +0200 Subject: [PATCH 06/19] Rename test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: marcin mikołajczak --- .../{language_code.exs => language_code_test.exs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename test/pleroma/ecto_type/activity_pub/object_validators/{language_code.exs => language_code_test.exs} (100%) diff --git a/test/pleroma/ecto_type/activity_pub/object_validators/language_code.exs b/test/pleroma/ecto_type/activity_pub/object_validators/language_code_test.exs similarity index 100% rename from test/pleroma/ecto_type/activity_pub/object_validators/language_code.exs rename to test/pleroma/ecto_type/activity_pub/object_validators/language_code_test.exs From 47ba7d346f5d5b45b5bbcecb7a549ee303ee8089 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= Date: Fri, 11 Aug 2023 18:10:58 +0200 Subject: [PATCH 07/19] Remove test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: marcin mikołajczak --- .../transmogrifier/note_handling_test.exs | 27 ------------------- 1 file changed, 27 deletions(-) diff --git a/test/pleroma/web/activity_pub/transmogrifier/note_handling_test.exs b/test/pleroma/web/activity_pub/transmogrifier/note_handling_test.exs index 8abc8a903..70283ac5a 100644 --- a/test/pleroma/web/activity_pub/transmogrifier/note_handling_test.exs +++ b/test/pleroma/web/activity_pub/transmogrifier/note_handling_test.exs @@ -442,33 +442,6 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.NoteHandlingTest do assert object.data["language"] == "pl" end - test "it detects language from content" do - clear_config([Pleroma.Language.LanguageDetector, :provider], LanguageDetectorMock) - - user = insert(:user) - - message = %{ - "@context" => ["https://www.w3.org/ns/activitystreams"], - "to" => ["https://www.w3.org/ns/activitystreams#Public"], - "cc" => [], - "type" => "Create", - "object" => %{ - "to" => ["https://www.w3.org/ns/activitystreams#Public"], - "cc" => [], - "id" => Utils.generate_object_id(), - "type" => "Note", - "content" => "Dieu vous bénisse, Fédivers.", - "attributedTo" => user.ap_id - }, - "actor" => user.ap_id - } - - {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(message) - object = Object.normalize(data["object"], fetch: false) - - assert object.data["language"] == "fr" - end - describe "`handle_incoming/2`, Mastodon format `replies` handling" do setup do: clear_config([:activitypub, :note_replies_output_limit], 5) setup do: clear_config([:instance, :federation_incoming_replies_max_depth]) From edc8689d9176e0134dc9d3a45dae5b530f8950e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= Date: Sat, 19 Aug 2023 15:28:19 +0200 Subject: [PATCH 08/19] Move `maybe_add_language` to CommonFixes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: marcin mikołajczak --- .../web/activity_pub/object_validator.ex | 27 +++++---- .../article_note_page_validator.ex | 20 +++---- .../object_validators/common_fixes.ex | 42 ++++++++++++++ .../web/activity_pub/transmogrifier.ex | 55 ------------------- 4 files changed, 67 insertions(+), 77 deletions(-) diff --git a/lib/pleroma/web/activity_pub/object_validator.ex b/lib/pleroma/web/activity_pub/object_validator.ex index 5e0d1aa8e..4ef036f34 100644 --- a/lib/pleroma/web/activity_pub/object_validator.ex +++ b/lib/pleroma/web/activity_pub/object_validator.ex @@ -103,7 +103,8 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do meta ) when objtype in ~w[Question Answer Audio Video Image Event Article Note Page] do - with {:ok, object_data} <- cast_and_apply_and_stringify_with_history(object), + with {:ok, object_data} <- + cast_and_apply_and_stringify_with_history(object, activity_data: create_activity), meta = Keyword.put(meta, :object_data, object_data), {:ok, create_activity} <- create_activity @@ -213,40 +214,42 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do def validate(o, m), do: {:error, {:validator_not_set, {o, m}}} - def cast_and_apply_and_stringify_with_history(object) do + def cast_and_apply_and_stringify_with_history(object, meta \\ []) do do_separate_with_history(object, fn object -> - with {:ok, object_data} <- cast_and_apply(object), + with {:ok, object_data} <- cast_and_apply(object, meta), object_data <- object_data |> stringify_keys() do {:ok, object_data} end end) end - def cast_and_apply(%{"type" => "ChatMessage"} = object) do + def cast_and_apply(object, meta \\ []) + + def cast_and_apply(%{"type" => "ChatMessage"} = object, _) do ChatMessageValidator.cast_and_apply(object) end - def cast_and_apply(%{"type" => "Question"} = object) do + def cast_and_apply(%{"type" => "Question"} = object, _) do QuestionValidator.cast_and_apply(object) end - def cast_and_apply(%{"type" => "Answer"} = object) do + def cast_and_apply(%{"type" => "Answer"} = object, _) do AnswerValidator.cast_and_apply(object) end - def cast_and_apply(%{"type" => type} = object) when type in ~w[Audio Image Video] do + def cast_and_apply(%{"type" => type} = object, _) when type in ~w[Audio Image Video] do AudioImageVideoValidator.cast_and_apply(object) end - def cast_and_apply(%{"type" => "Event"} = object) do - EventValidator.cast_and_apply(object) + def cast_and_apply(%{"type" => "Event"} = object, meta) do + EventValidator.cast_and_apply(object, meta) end - def cast_and_apply(%{"type" => type} = object) when type in ~w[Article Note Page] do - ArticleNotePageValidator.cast_and_apply(object) + def cast_and_apply(%{"type" => type} = object, meta) when type in ~w[Article Note Page] do + ArticleNotePageValidator.cast_and_apply(object, meta) end - def cast_and_apply(o), do: {:error, {:validator_not_set, o}} + def cast_and_apply(o, _), do: {:error, {:validator_not_set, o}} def stringify_keys(object) when is_struct(object) do object 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 73101f20f..9e6a1b0fb 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 @@ -28,21 +28,21 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.ArticleNotePageValidator do field(:replies, {:array, ObjectValidators.ObjectID}, default: []) end - def cast_and_apply(data) do + def cast_and_apply(data, meta \\ []) do data - |> cast_data + |> cast_data(meta) |> apply_action(:insert) end - def cast_and_validate(data) do + def cast_and_validate(data, meta \\ []) do data - |> cast_data() + |> cast_data(meta) |> validate_data() end - def cast_data(data) do + def cast_data(data, meta \\ []) do %__MODULE__{} - |> changeset(data) + |> changeset(data, meta) end defp fix_url(%{"url" => url} = data) when is_bitstring(url), do: data @@ -76,7 +76,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.ArticleNotePageValidator do def fix_attachments(data), do: data - defp fix(data) do + defp fix(data, meta) do data |> CommonFixes.fix_actor() |> CommonFixes.fix_object_defaults() @@ -86,11 +86,11 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.ArticleNotePageValidator do |> fix_attachments() |> Transmogrifier.fix_emoji() |> Transmogrifier.fix_content_map() - |> Transmogrifier.maybe_add_language() + |> CommonFixes.maybe_add_language(meta) end - def changeset(struct, data) do - data = fix(data) + def changeset(struct, data, meta \\ []) do + data = fix(data, meta) struct |> cast(data, __schema__(:fields) -- [:attachment, :tag]) diff --git a/lib/pleroma/web/activity_pub/object_validators/common_fixes.ex b/lib/pleroma/web/activity_pub/object_validators/common_fixes.ex index add46d561..66e44afe6 100644 --- a/lib/pleroma/web/activity_pub/object_validators/common_fixes.ex +++ b/lib/pleroma/web/activity_pub/object_validators/common_fixes.ex @@ -10,6 +10,8 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes do alias Pleroma.Web.ActivityPub.Transmogrifier alias Pleroma.Web.ActivityPub.Utils + import Pleroma.Web.CommonAPI.Utils, only: [is_good_locale_code?: 1] + def cast_and_filter_recipients(message, field, follower_collection, field_fallback \\ []) do {:ok, data} = ObjectValidators.Recipients.cast(message[field] || field_fallback) @@ -76,4 +78,44 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes do Map.put(data, "to", to) end + + def maybe_add_language(object, meta \\ []) do + language = + [ + get_language_from_context(object), + get_language_from_context(Keyword.get(meta, :activity_data)), + get_language_from_content_map(object) + ] + |> Enum.find(&is_good_locale_code?(&1)) + + if language do + Map.put(object, "language", language) + else + object + end + end + + defp get_language_from_context(%{"@context" => context}) when is_list(context) do + case context + |> Enum.find(fn + %{"@language" => language} -> language != "und" + _ -> nil + end) do + %{"@language" => language} -> language + _ -> nil + end + end + + defp get_language_from_context(_), do: nil + + defp get_language_from_content_map(%{"contentMap" => content_map, "content" => source_content}) do + content_groups = Map.to_list(content_map) + + case Enum.find(content_groups, fn {_, content} -> content == source_content end) do + {language, _} -> language + _ -> nil + end + end + + defp get_language_from_content_map(_), do: nil end diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index 732d878c4..fd7059dea 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -22,7 +22,6 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do alias Pleroma.Web.Federator import Ecto.Query - import Pleroma.Web.CommonAPI.Utils, only: [is_good_locale_code?: 1] import Pleroma.Web.Utils.Guards, only: [not_empty_string: 1] require Logger @@ -44,7 +43,6 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do |> fix_content_map() |> fix_addressing() |> fix_summary() - |> maybe_add_language() end def fix_summary(%{"summary" => nil} = object) do @@ -459,7 +457,6 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do |> strip_internal_fields() |> fix_type(fetch_options) |> fix_in_reply_to(fetch_options) - |> maybe_add_language_from_activity(data) data = Map.put(data, "object", object) options = Keyword.put(options, :local, false) @@ -966,56 +963,4 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do end defp maybe_add_content_map(object), do: object - - def maybe_add_language(object) do - language = - [ - get_language_from_context(object), - get_language_from_content_map(object), - get_language_from_content(object) - ] - |> Enum.find(&is_good_locale_code?(&1)) - - if language do - Map.put(object, "language", language) - else - object - end - end - - def maybe_add_language_from_activity(object, activity) do - language = get_language_from_context(activity) - - if is_good_locale_code?(language) do - Map.put(object, "language", language) - else - object - end - end - - defp get_language_from_context(%{"@context" => context}) when is_list(context) do - case context - |> Enum.find(fn - %{"@language" => language} -> language != "und" - _ -> nil - end) do - %{"@language" => language} -> language - _ -> nil - end - end - - defp get_language_from_context(_), do: nil - - defp get_language_from_content_map(%{"contentMap" => content_map, "content" => source_content}) do - content_groups = Map.to_list(content_map) - - case Enum.find(content_groups, fn {_, content} -> content == source_content end) do - {language, _} -> language - _ -> nil - end - end - - defp get_language_from_content_map(_), do: nil - - defp get_language_from_content(_), do: nil end From 62340b50b57eeab0b7ab4093e07d05080991bfc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= Date: Sat, 19 Aug 2023 19:03:25 +0200 Subject: [PATCH 09/19] Move maybe_add_content_map out of Transmogrifier, use code from tusooa's branch for MapOfString MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: marcin mikołajczak --- .../object_validators/map_of_string.ex | 48 +++++++++++++ .../article_note_page_validator.ex | 1 + .../object_validators/common_fields.ex | 1 + .../object_validators/common_fixes.ex | 8 +++ .../object_validators/event_validator.ex | 20 +++--- .../web/activity_pub/transmogrifier.ex | 8 --- .../object_validators/map_of_string_test.exs | 55 +++++++++++++++ .../article_note_page_validator_test.exs | 70 +++++++++++++++++++ .../transmogrifier/note_handling_test.exs | 54 -------------- 9 files changed, 194 insertions(+), 71 deletions(-) create mode 100644 lib/pleroma/ecto_type/activity_pub/object_validators/map_of_string.ex create mode 100644 test/pleroma/ecto_type/activity_pub/object_validators/map_of_string_test.exs diff --git a/lib/pleroma/ecto_type/activity_pub/object_validators/map_of_string.ex b/lib/pleroma/ecto_type/activity_pub/object_validators/map_of_string.ex new file mode 100644 index 000000000..e86275f92 --- /dev/null +++ b/lib/pleroma/ecto_type/activity_pub/object_validators/map_of_string.ex @@ -0,0 +1,48 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2022 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.EctoType.ActivityPub.ObjectValidators.MapOfString do + use Ecto.Type + + import Pleroma.Web.CommonAPI.Utils, only: [is_good_locale_code?: 1] + + def type, do: :map + + def cast(%{} = object) do + with {status, %{} = data} when status in [:modified, :ok] <- validate_map(object) do + {:ok, data} + else + {_, nil} -> {:ok, nil} + {:error, _} -> :error + end + end + + def cast(_), do: :error + + def dump(data), do: {:ok, data} + + def load(data), do: {:ok, data} + + defp validate_map(%{} = object) do + {status, data} = + object + |> Enum.reduce({:ok, %{}}, fn + {lang, value}, {status, acc} when is_binary(lang) and is_binary(value) -> + if is_good_locale_code?(lang) do + {status, Map.put(acc, lang, value)} + else + {:modified, acc} + end + + _, {_status, acc} -> + {:modified, acc} + end) + + if data == %{} do + {status, nil} + else + {status, data} + end + end +end 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 9e6a1b0fb..0c7aa769b 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 @@ -87,6 +87,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.ArticleNotePageValidator do |> Transmogrifier.fix_emoji() |> Transmogrifier.fix_content_map() |> CommonFixes.maybe_add_language(meta) + |> CommonFixes.maybe_add_content_map() end def changeset(struct, data, meta \\ []) do diff --git a/lib/pleroma/web/activity_pub/object_validators/common_fields.ex b/lib/pleroma/web/activity_pub/object_validators/common_fields.ex index 7ba393270..0cef5b533 100644 --- a/lib/pleroma/web/activity_pub/object_validators/common_fields.ex +++ b/lib/pleroma/web/activity_pub/object_validators/common_fields.ex @@ -31,6 +31,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CommonFields do defmacro object_fields do quote bind_quoted: binding() do field(:content, :string) + field(:contentMap, ObjectValidators.MapOfString) field(:published, ObjectValidators.DateTime) field(:updated, ObjectValidators.DateTime) diff --git a/lib/pleroma/web/activity_pub/object_validators/common_fixes.ex b/lib/pleroma/web/activity_pub/object_validators/common_fixes.ex index 66e44afe6..b141cc74c 100644 --- a/lib/pleroma/web/activity_pub/object_validators/common_fixes.ex +++ b/lib/pleroma/web/activity_pub/object_validators/common_fixes.ex @@ -11,6 +11,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes do alias Pleroma.Web.ActivityPub.Utils import Pleroma.Web.CommonAPI.Utils, only: [is_good_locale_code?: 1] + import Pleroma.Web.Utils.Guards, only: [not_empty_string: 1] def cast_and_filter_recipients(message, field, follower_collection, field_fallback \\ []) do {:ok, data} = ObjectValidators.Recipients.cast(message[field] || field_fallback) @@ -118,4 +119,11 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes do end defp get_language_from_content_map(_), do: nil + + def maybe_add_content_map(%{"language" => language, "content" => content} = object) + when not_empty_string(language) do + Map.put(object, "contentMap", Map.put(%{}, language, content)) + end + + def maybe_add_content_map(object), do: object end diff --git a/lib/pleroma/web/activity_pub/object_validators/event_validator.ex b/lib/pleroma/web/activity_pub/object_validators/event_validator.ex index ab204f69a..56ca6fe40 100644 --- a/lib/pleroma/web/activity_pub/object_validators/event_validator.ex +++ b/lib/pleroma/web/activity_pub/object_validators/event_validator.ex @@ -26,32 +26,34 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.EventValidator do end end - def cast_and_apply(data) do + def cast_and_apply(data, meta \\ []) do data - |> cast_data + |> cast_data(meta) |> apply_action(:insert) end - def cast_and_validate(data) do + def cast_and_validate(data, meta \\ []) do data - |> cast_data() + |> cast_data(meta) |> validate_data() end - def cast_data(data) do + def cast_data(data, meta \\ []) do %__MODULE__{} - |> changeset(data) + |> changeset(data, meta) end - defp fix(data) do + defp fix(data, meta) do data |> CommonFixes.fix_actor() |> CommonFixes.fix_object_defaults() |> Transmogrifier.fix_emoji() + |> CommonFixes.maybe_add_language(meta) + |> CommonFixes.maybe_add_content_map() end - def changeset(struct, data) do - data = fix(data) + def changeset(struct, data, meta \\ []) do + data = fix(data, meta) struct |> cast(data, __schema__(:fields) -- [:attachment, :tag]) diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index fd7059dea..a60e98c28 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -682,7 +682,6 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do |> add_mention_tags |> add_emoji_tags |> add_attributed_to - |> maybe_add_content_map |> prepare_attachments |> set_conversation |> set_reply_to_uri @@ -956,11 +955,4 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do def maybe_fix_user_url(data), do: data def maybe_fix_user_object(data), do: maybe_fix_user_url(data) - - defp maybe_add_content_map(%{"language" => language, "content" => content} = object) - when not_empty_string(language) do - Map.put(object, "contentMap", Map.put(%{}, language, content)) - end - - defp maybe_add_content_map(object), do: object end diff --git a/test/pleroma/ecto_type/activity_pub/object_validators/map_of_string_test.exs b/test/pleroma/ecto_type/activity_pub/object_validators/map_of_string_test.exs new file mode 100644 index 000000000..4ee179dc8 --- /dev/null +++ b/test/pleroma/ecto_type/activity_pub/object_validators/map_of_string_test.exs @@ -0,0 +1,55 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2022 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.EctoType.ActivityPub.ObjectValidators.MapOfStringTest do + alias Pleroma.EctoType.ActivityPub.ObjectValidators.MapOfString + use Pleroma.DataCase, async: true + + test "it validates" do + data = %{ + "en-US" => "mew mew", + "en-GB" => "meow meow" + } + + assert {:ok, ^data} = MapOfString.cast(data) + end + + test "it validates empty strings" do + data = %{ + "en-US" => "mew mew", + "en-GB" => "" + } + + assert {:ok, ^data} = MapOfString.cast(data) + end + + test "it ignores non-strings within the map" do + data = %{ + "en-US" => "mew mew", + "en-GB" => 123 + } + + assert {:ok, validated_data} = MapOfString.cast(data) + + assert validated_data == %{"en-US" => "mew mew"} + end + + test "it ignores bad locale codes" do + data = %{ + "en-US" => "mew mew", + "en_GB" => "meow meow", + "en<<#@!$#!@%!GB" => "meow meow" + } + + assert {:ok, validated_data} = MapOfString.cast(data) + + assert validated_data == %{"en-US" => "mew mew"} + end + + test "it complains with non-map data" do + assert :error = MapOfString.cast("mew") + assert :error = MapOfString.cast(["mew"]) + assert :error = MapOfString.cast([%{"en-US" => "mew"}]) + end +end 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 c7a62be18..a0c50b10d 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 @@ -116,4 +116,74 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.ArticleNotePageValidatorTest %{valid?: true} = ArticleNotePageValidator.cast_and_validate(note) end + + describe "Note language" do + test "it detects language from context" do + user = insert(:user) + + note_activity = %{ + "@context" => ["https://www.w3.org/ns/activitystreams", %{"@language" => "pl"}], + "to" => ["https://www.w3.org/ns/activitystreams#Public"], + "cc" => [], + "type" => "Create", + "object" => %{ + "to" => ["https://www.w3.org/ns/activitystreams#Public"], + "cc" => [], + "id" => Utils.generate_object_id(), + "type" => "Note", + "content" => "Szczęść Boże", + "attributedTo" => user.ap_id + }, + "actor" => user.ap_id + } + + {:ok, object} = + ArticleNotePageValidator.cast_and_apply(note_activity["object"], + activity_data: note_activity + ) + + assert object.language == "pl" + end + + test "it detects language from contentMap" do + user = insert(:user) + + note = %{ + "to" => ["https://www.w3.org/ns/activitystreams#Public"], + "cc" => [], + "id" => Utils.generate_object_id(), + "type" => "Note", + "content" => "Szczęść Boże", + "contentMap" => %{ + "de" => "Gott segne", + "pl" => "Szczęść Boże" + }, + "attributedTo" => user.ap_id + } + + {:ok, object} = ArticleNotePageValidator.cast_and_apply(note) + + assert object.language == "pl" + end + + test "it adds contentMap if language is specified" do + user = insert(:user) + + note = %{ + "to" => ["https://www.w3.org/ns/activitystreams#Public"], + "cc" => [], + "id" => Utils.generate_object_id(), + "type" => "Note", + "content" => "тест", + "language" => "uk", + "attributedTo" => user.ap_id + } + + {:ok, object} = ArticleNotePageValidator.cast_and_apply(note) + + assert object.contentMap == %{ + "uk" => "тест" + } + end + end end diff --git a/test/pleroma/web/activity_pub/transmogrifier/note_handling_test.exs b/test/pleroma/web/activity_pub/transmogrifier/note_handling_test.exs index 70283ac5a..1e57ebabe 100644 --- a/test/pleroma/web/activity_pub/transmogrifier/note_handling_test.exs +++ b/test/pleroma/web/activity_pub/transmogrifier/note_handling_test.exs @@ -388,60 +388,6 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.NoteHandlingTest do end end - test "it detects language from context" do - user = insert(:user) - - message = %{ - "@context" => ["https://www.w3.org/ns/activitystreams", %{"@language" => "pl"}], - "to" => ["https://www.w3.org/ns/activitystreams#Public"], - "cc" => [], - "type" => "Create", - "object" => %{ - "to" => ["https://www.w3.org/ns/activitystreams#Public"], - "cc" => [], - "id" => Utils.generate_object_id(), - "type" => "Note", - "content" => "Szczęść Boże", - "attributedTo" => user.ap_id - }, - "actor" => user.ap_id - } - - {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(message) - object = Object.normalize(data["object"], fetch: false) - - assert object.data["language"] == "pl" - end - - test "it detects language from contentMap" do - user = insert(:user) - - message = %{ - "@context" => "https://www.w3.org/ns/activitystreams", - "to" => ["https://www.w3.org/ns/activitystreams#Public"], - "cc" => [], - "type" => "Create", - "object" => %{ - "to" => ["https://www.w3.org/ns/activitystreams#Public"], - "cc" => [], - "id" => Utils.generate_object_id(), - "type" => "Note", - "content" => "Szczęść Boże", - "contentMap" => %{ - "de" => "Gott segne", - "pl" => "Szczęść Boże" - }, - "attributedTo" => user.ap_id - }, - "actor" => user.ap_id - } - - {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(message) - object = Object.normalize(data["object"], fetch: false) - - assert object.data["language"] == "pl" - end - describe "`handle_incoming/2`, Mastodon format `replies` handling" do setup do: clear_config([:activitypub, :note_replies_output_limit], 5) setup do: clear_config([:instance, :federation_incoming_replies_max_depth]) From c160ef7b6a4c8d214a7abbb5054993341ee66b2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= Date: Sat, 19 Aug 2023 20:33:42 +0200 Subject: [PATCH 10/19] Remove test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: marcin mikołajczak --- .../activity_pub/object_validators/map_of_string.ex | 2 +- .../activity_pub/object_validators/common_fixes.ex | 2 +- .../object_validators/map_of_string_test.exs | 5 +++-- .../pleroma/web/activity_pub/transmogrifier_test.exs | 12 ------------ 4 files changed, 5 insertions(+), 16 deletions(-) diff --git a/lib/pleroma/ecto_type/activity_pub/object_validators/map_of_string.ex b/lib/pleroma/ecto_type/activity_pub/object_validators/map_of_string.ex index e86275f92..96b7f2da6 100644 --- a/lib/pleroma/ecto_type/activity_pub/object_validators/map_of_string.ex +++ b/lib/pleroma/ecto_type/activity_pub/object_validators/map_of_string.ex @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2022 Pleroma Authors +# Copyright © 2017-2023 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.EctoType.ActivityPub.ObjectValidators.MapOfString do diff --git a/lib/pleroma/web/activity_pub/object_validators/common_fixes.ex b/lib/pleroma/web/activity_pub/object_validators/common_fixes.ex index b141cc74c..ccc76beed 100644 --- a/lib/pleroma/web/activity_pub/object_validators/common_fixes.ex +++ b/lib/pleroma/web/activity_pub/object_validators/common_fixes.ex @@ -121,7 +121,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes do defp get_language_from_content_map(_), do: nil def maybe_add_content_map(%{"language" => language, "content" => content} = object) - when not_empty_string(language) do + when not_empty_string(language) do Map.put(object, "contentMap", Map.put(%{}, language, content)) end diff --git a/test/pleroma/ecto_type/activity_pub/object_validators/map_of_string_test.exs b/test/pleroma/ecto_type/activity_pub/object_validators/map_of_string_test.exs index 4ee179dc8..941199ce8 100644 --- a/test/pleroma/ecto_type/activity_pub/object_validators/map_of_string_test.exs +++ b/test/pleroma/ecto_type/activity_pub/object_validators/map_of_string_test.exs @@ -1,11 +1,12 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2022 Pleroma Authors +# Copyright © 2017-2023 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.EctoType.ActivityPub.ObjectValidators.MapOfStringTest do - alias Pleroma.EctoType.ActivityPub.ObjectValidators.MapOfString use Pleroma.DataCase, async: true + alias Pleroma.EctoType.ActivityPub.ObjectValidators.MapOfString + test "it validates" do data = %{ "en-US" => "mew mew", diff --git a/test/pleroma/web/activity_pub/transmogrifier_test.exs b/test/pleroma/web/activity_pub/transmogrifier_test.exs index a72edf79c..3e0c8dc65 100644 --- a/test/pleroma/web/activity_pub/transmogrifier_test.exs +++ b/test/pleroma/web/activity_pub/transmogrifier_test.exs @@ -352,18 +352,6 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do end end - test "it adds contentMap if language is specified" do - user = insert(:user) - - {:ok, activity} = CommonAPI.post(user, %{status: "тест", language: "uk"}) - - {:ok, prepared} = Transmogrifier.prepare_outgoing(activity.data) - - assert prepared["object"]["contentMap"] == %{ - "uk" => "тест" - } - end - describe "actor rewriting" do test "it fixes the actor URL property to be a proper URI" do data = %{ From b52d189fcca13088531002ef0bdc0dc5e5df6569 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= Date: Thu, 31 Aug 2023 11:35:09 +0200 Subject: [PATCH 11/19] Move is_good_locale_code? to object validator MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: marcin mikołajczak --- .../activity_pub/object_validators/language_code.ex | 6 ++++-- .../activity_pub/object_validators/map_of_string.ex | 3 ++- .../web/activity_pub/object_validators/common_fixes.ex | 4 +++- lib/pleroma/web/common_api/activity_draft.ex | 5 ++++- lib/pleroma/web/common_api/utils.ex | 4 ---- 5 files changed, 13 insertions(+), 9 deletions(-) diff --git a/lib/pleroma/ecto_type/activity_pub/object_validators/language_code.ex b/lib/pleroma/ecto_type/activity_pub/object_validators/language_code.ex index 327279bf8..b15e9ec5e 100644 --- a/lib/pleroma/ecto_type/activity_pub/object_validators/language_code.ex +++ b/lib/pleroma/ecto_type/activity_pub/object_validators/language_code.ex @@ -5,8 +5,6 @@ defmodule Pleroma.EctoType.ActivityPub.ObjectValidators.LanguageCode do use Ecto.Type - import Pleroma.Web.CommonAPI.Utils, only: [is_good_locale_code?: 1] - def type, do: :string def cast(language) when is_binary(language) do @@ -22,4 +20,8 @@ defmodule Pleroma.EctoType.ActivityPub.ObjectValidators.LanguageCode do def dump(data), do: {:ok, data} def load(data), do: {:ok, data} + + def is_good_locale_code?(code) when is_binary(code), do: code =~ ~r<^[a-zA-Z0-9\-]+$> + + def is_good_locale_code?(_code), do: false end diff --git a/lib/pleroma/ecto_type/activity_pub/object_validators/map_of_string.ex b/lib/pleroma/ecto_type/activity_pub/object_validators/map_of_string.ex index 96b7f2da6..2228edd24 100644 --- a/lib/pleroma/ecto_type/activity_pub/object_validators/map_of_string.ex +++ b/lib/pleroma/ecto_type/activity_pub/object_validators/map_of_string.ex @@ -5,7 +5,8 @@ defmodule Pleroma.EctoType.ActivityPub.ObjectValidators.MapOfString do use Ecto.Type - import Pleroma.Web.CommonAPI.Utils, only: [is_good_locale_code?: 1] + import Pleroma.EctoType.ActivityPub.ObjectValidators.LanguageCode, + only: [is_good_locale_code?: 1] def type, do: :map diff --git a/lib/pleroma/web/activity_pub/object_validators/common_fixes.ex b/lib/pleroma/web/activity_pub/object_validators/common_fixes.ex index ccc76beed..fa581eba4 100644 --- a/lib/pleroma/web/activity_pub/object_validators/common_fixes.ex +++ b/lib/pleroma/web/activity_pub/object_validators/common_fixes.ex @@ -10,7 +10,9 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes do alias Pleroma.Web.ActivityPub.Transmogrifier alias Pleroma.Web.ActivityPub.Utils - import Pleroma.Web.CommonAPI.Utils, only: [is_good_locale_code?: 1] + import Pleroma.EctoType.ActivityPub.ObjectValidators.LanguageCode, + only: [is_good_locale_code?: 1] + import Pleroma.Web.Utils.Guards, only: [not_empty_string: 1] def cast_and_filter_recipients(message, field, follower_collection, field_fallback \\ []) do diff --git a/lib/pleroma/web/common_api/activity_draft.ex b/lib/pleroma/web/common_api/activity_draft.ex index bcbb134bb..1b6118cf8 100644 --- a/lib/pleroma/web/common_api/activity_draft.ex +++ b/lib/pleroma/web/common_api/activity_draft.ex @@ -10,6 +10,9 @@ defmodule Pleroma.Web.CommonAPI.ActivityDraft do alias Pleroma.Web.CommonAPI alias Pleroma.Web.CommonAPI.Utils + import Pleroma.EctoType.ActivityPub.ObjectValidators.LanguageCode, + only: [is_good_locale_code?: 1] + import Pleroma.Web.Gettext defstruct valid?: true, @@ -195,7 +198,7 @@ defmodule Pleroma.Web.CommonAPI.ActivityDraft do defp language(draft) do language = draft.params[:language] - if Utils.is_good_locale_code?(language) do + if is_good_locale_code?(language) do %__MODULE__{draft | language: language} else draft diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex index 05a5b818e..b9fe0224c 100644 --- a/lib/pleroma/web/common_api/utils.ex +++ b/lib/pleroma/web/common_api/utils.ex @@ -494,8 +494,4 @@ defmodule Pleroma.Web.CommonAPI.Utils do {:error, dgettext("errors", "Too many attachments")} end end - - def is_good_locale_code?(code) when is_binary(code), do: code =~ ~r<^[a-zA-Z0-9\-]+$> - - def is_good_locale_code?(_code), do: false end From c5ed684273fa329bc955c59dbc7beed9804fb0f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= Date: Thu, 7 Sep 2023 15:12:15 +0200 Subject: [PATCH 12/19] Rename MapOfString to ContentLanguageMap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: marcin mikołajczak --- .../object_validators/map_of_string.ex | 49 ---------------- .../object_validators/common_fields.ex | 2 +- .../object_validators/map_of_string_test.exs | 56 ------------------- 3 files changed, 1 insertion(+), 106 deletions(-) delete mode 100644 lib/pleroma/ecto_type/activity_pub/object_validators/map_of_string.ex delete mode 100644 test/pleroma/ecto_type/activity_pub/object_validators/map_of_string_test.exs diff --git a/lib/pleroma/ecto_type/activity_pub/object_validators/map_of_string.ex b/lib/pleroma/ecto_type/activity_pub/object_validators/map_of_string.ex deleted file mode 100644 index 2228edd24..000000000 --- a/lib/pleroma/ecto_type/activity_pub/object_validators/map_of_string.ex +++ /dev/null @@ -1,49 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2023 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.EctoType.ActivityPub.ObjectValidators.MapOfString do - use Ecto.Type - - import Pleroma.EctoType.ActivityPub.ObjectValidators.LanguageCode, - only: [is_good_locale_code?: 1] - - def type, do: :map - - def cast(%{} = object) do - with {status, %{} = data} when status in [:modified, :ok] <- validate_map(object) do - {:ok, data} - else - {_, nil} -> {:ok, nil} - {:error, _} -> :error - end - end - - def cast(_), do: :error - - def dump(data), do: {:ok, data} - - def load(data), do: {:ok, data} - - defp validate_map(%{} = object) do - {status, data} = - object - |> Enum.reduce({:ok, %{}}, fn - {lang, value}, {status, acc} when is_binary(lang) and is_binary(value) -> - if is_good_locale_code?(lang) do - {status, Map.put(acc, lang, value)} - else - {:modified, acc} - end - - _, {_status, acc} -> - {:modified, acc} - end) - - if data == %{} do - {status, nil} - else - {status, data} - end - end -end diff --git a/lib/pleroma/web/activity_pub/object_validators/common_fields.ex b/lib/pleroma/web/activity_pub/object_validators/common_fields.ex index 0cef5b533..4a385633a 100644 --- a/lib/pleroma/web/activity_pub/object_validators/common_fields.ex +++ b/lib/pleroma/web/activity_pub/object_validators/common_fields.ex @@ -31,7 +31,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CommonFields do defmacro object_fields do quote bind_quoted: binding() do field(:content, :string) - field(:contentMap, ObjectValidators.MapOfString) + field(:contentMap, ObjectValidators.ContentLanguageMap) field(:published, ObjectValidators.DateTime) field(:updated, ObjectValidators.DateTime) diff --git a/test/pleroma/ecto_type/activity_pub/object_validators/map_of_string_test.exs b/test/pleroma/ecto_type/activity_pub/object_validators/map_of_string_test.exs deleted file mode 100644 index 941199ce8..000000000 --- a/test/pleroma/ecto_type/activity_pub/object_validators/map_of_string_test.exs +++ /dev/null @@ -1,56 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2023 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.EctoType.ActivityPub.ObjectValidators.MapOfStringTest do - use Pleroma.DataCase, async: true - - alias Pleroma.EctoType.ActivityPub.ObjectValidators.MapOfString - - test "it validates" do - data = %{ - "en-US" => "mew mew", - "en-GB" => "meow meow" - } - - assert {:ok, ^data} = MapOfString.cast(data) - end - - test "it validates empty strings" do - data = %{ - "en-US" => "mew mew", - "en-GB" => "" - } - - assert {:ok, ^data} = MapOfString.cast(data) - end - - test "it ignores non-strings within the map" do - data = %{ - "en-US" => "mew mew", - "en-GB" => 123 - } - - assert {:ok, validated_data} = MapOfString.cast(data) - - assert validated_data == %{"en-US" => "mew mew"} - end - - test "it ignores bad locale codes" do - data = %{ - "en-US" => "mew mew", - "en_GB" => "meow meow", - "en<<#@!$#!@%!GB" => "meow meow" - } - - assert {:ok, validated_data} = MapOfString.cast(data) - - assert validated_data == %{"en-US" => "mew mew"} - end - - test "it complains with non-map data" do - assert :error = MapOfString.cast("mew") - assert :error = MapOfString.cast(["mew"]) - assert :error = MapOfString.cast([%{"en-US" => "mew"}]) - end -end From a3b17dac0bf5da57cbd08335379ddfe4f8919bc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= Date: Thu, 7 Sep 2023 15:14:18 +0200 Subject: [PATCH 13/19] Rename test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: marcin mikołajczak --- .../object_validators/content_language_map.ex | 49 ++++++++++++++++ .../content_language_map_test.exs | 56 +++++++++++++++++++ .../article_note_page_validator_test.exs | 2 +- 3 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 lib/pleroma/ecto_type/activity_pub/object_validators/content_language_map.ex create mode 100644 test/pleroma/ecto_type/activity_pub/object_validators/content_language_map_test.exs diff --git a/lib/pleroma/ecto_type/activity_pub/object_validators/content_language_map.ex b/lib/pleroma/ecto_type/activity_pub/object_validators/content_language_map.ex new file mode 100644 index 000000000..2cc0fda00 --- /dev/null +++ b/lib/pleroma/ecto_type/activity_pub/object_validators/content_language_map.ex @@ -0,0 +1,49 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2023 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.EctoType.ActivityPub.ObjectValidators.ContentLanguageMap do + use Ecto.Type + + import Pleroma.EctoType.ActivityPub.ObjectValidators.LanguageCode, + only: [is_good_locale_code?: 1] + + def type, do: :map + + def cast(%{} = object) do + with {status, %{} = data} when status in [:modified, :ok] <- validate_map(object) do + {:ok, data} + else + {_, nil} -> {:ok, nil} + {:error, _} -> :error + end + end + + def cast(_), do: :error + + def dump(data), do: {:ok, data} + + def load(data), do: {:ok, data} + + defp validate_map(%{} = object) do + {status, data} = + object + |> Enum.reduce({:ok, %{}}, fn + {lang, value}, {status, acc} when is_binary(lang) and is_binary(value) -> + if is_good_locale_code?(lang) do + {status, Map.put(acc, lang, value)} + else + {:modified, acc} + end + + _, {_status, acc} -> + {:modified, acc} + end) + + if data == %{} do + {status, nil} + else + {status, data} + end + end +end diff --git a/test/pleroma/ecto_type/activity_pub/object_validators/content_language_map_test.exs b/test/pleroma/ecto_type/activity_pub/object_validators/content_language_map_test.exs new file mode 100644 index 000000000..a05871a6f --- /dev/null +++ b/test/pleroma/ecto_type/activity_pub/object_validators/content_language_map_test.exs @@ -0,0 +1,56 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2023 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.EctoType.ActivityPub.ObjectValidators.ContentLanguageMapTest do + use Pleroma.DataCase, async: true + + alias Pleroma.EctoType.ActivityPub.ObjectValidators.ContentLanguageMap + + test "it validates" do + data = %{ + "en-US" => "mew mew", + "en-GB" => "meow meow" + } + + assert {:ok, ^data} = ContentLanguageMap.cast(data) + end + + test "it validates empty strings" do + data = %{ + "en-US" => "mew mew", + "en-GB" => "" + } + + assert {:ok, ^data} = ContentLanguageMap.cast(data) + end + + test "it ignores non-strings within the map" do + data = %{ + "en-US" => "mew mew", + "en-GB" => 123 + } + + assert {:ok, validated_data} = ContentLanguageMap.cast(data) + + assert validated_data == %{"en-US" => "mew mew"} + end + + test "it ignores bad locale codes" do + data = %{ + "en-US" => "mew mew", + "en_GB" => "meow meow", + "en<<#@!$#!@%!GB" => "meow meow" + } + + assert {:ok, validated_data} = ContentLanguageMap.cast(data) + + assert validated_data == %{"en-US" => "mew mew"} + end + + test "it complains with non-map data" do + assert :error = ContentLanguageMap.cast("mew") + assert :error = ContentLanguageMap.cast(["mew"]) + assert :error = ContentLanguageMap.cast([%{"en-US" => "mew"}]) + end +end 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 a0c50b10d..c4e2aa838 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 @@ -118,7 +118,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.ArticleNotePageValidatorTest end describe "Note language" do - test "it detects language from context" do + test "it detects language from JSON-LD context" do user = insert(:user) note_activity = %{ From 51aef6b78dcf709872de32a02533e943f08858d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= Date: Thu, 28 Dec 2023 15:52:59 +0100 Subject: [PATCH 14/19] Add language from activity context in ObjectValidator MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: marcin mikołajczak --- .../web/activity_pub/object_validator.ex | 35 +++++++++++-------- .../article_note_page_validator.ex | 20 +++++------ .../object_validators/common_fixes.ex | 13 +++++-- .../object_validators/event_validator.ex | 21 +++++------ .../article_note_page_validator_test.exs | 7 ++-- 5 files changed, 54 insertions(+), 42 deletions(-) diff --git a/lib/pleroma/web/activity_pub/object_validator.ex b/lib/pleroma/web/activity_pub/object_validator.ex index 4ef036f34..61d896a5b 100644 --- a/lib/pleroma/web/activity_pub/object_validator.ex +++ b/lib/pleroma/web/activity_pub/object_validator.ex @@ -24,6 +24,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do alias Pleroma.Web.ActivityPub.ObjectValidators.AudioImageVideoValidator alias Pleroma.Web.ActivityPub.ObjectValidators.BlockValidator alias Pleroma.Web.ActivityPub.ObjectValidators.ChatMessageValidator + alias Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes alias Pleroma.Web.ActivityPub.ObjectValidators.CreateChatMessageValidator alias Pleroma.Web.ActivityPub.ObjectValidators.CreateGenericValidator alias Pleroma.Web.ActivityPub.ObjectValidators.DeleteValidator @@ -104,7 +105,9 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do ) when objtype in ~w[Question Answer Audio Video Image Event Article Note Page] do with {:ok, object_data} <- - cast_and_apply_and_stringify_with_history(object, activity_data: create_activity), + object + |> CommonFixes.maybe_add_language_from_activity(create_activity) + |> cast_and_apply_and_stringify_with_history(), meta = Keyword.put(meta, :object_data, object_data), {:ok, create_activity} <- create_activity @@ -154,7 +157,11 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do ) when objtype in ~w[Question Answer Audio Video Event Article Note Page] do with {_, false} <- {:local, Access.get(meta, :local, false)}, - {_, {:ok, object_data, _}} <- {:object_validation, validate(object, meta)}, + {_, {:ok, object_data, _}} <- + {:object_validation, + object + |> CommonFixes.maybe_add_language_from_activity(update_activity) + |> validate(meta)}, meta = Keyword.put(meta, :object_data, object_data), {:ok, update_activity} <- update_activity @@ -214,42 +221,40 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do def validate(o, m), do: {:error, {:validator_not_set, {o, m}}} - def cast_and_apply_and_stringify_with_history(object, meta \\ []) do + def cast_and_apply_and_stringify_with_history(object) do do_separate_with_history(object, fn object -> - with {:ok, object_data} <- cast_and_apply(object, meta), + with {:ok, object_data} <- cast_and_apply(object), object_data <- object_data |> stringify_keys() do {:ok, object_data} end end) end - def cast_and_apply(object, meta \\ []) - - def cast_and_apply(%{"type" => "ChatMessage"} = object, _) do + def cast_and_apply(%{"type" => "ChatMessage"} = object) do ChatMessageValidator.cast_and_apply(object) end - def cast_and_apply(%{"type" => "Question"} = object, _) do + def cast_and_apply(%{"type" => "Question"} = object) do QuestionValidator.cast_and_apply(object) end - def cast_and_apply(%{"type" => "Answer"} = object, _) do + def cast_and_apply(%{"type" => "Answer"} = object) do AnswerValidator.cast_and_apply(object) end - def cast_and_apply(%{"type" => type} = object, _) when type in ~w[Audio Image Video] do + def cast_and_apply(%{"type" => type} = object) when type in ~w[Audio Image Video] do AudioImageVideoValidator.cast_and_apply(object) end - def cast_and_apply(%{"type" => "Event"} = object, meta) do - EventValidator.cast_and_apply(object, meta) + def cast_and_apply(%{"type" => "Event"} = object) do + EventValidator.cast_and_apply(object) end - def cast_and_apply(%{"type" => type} = object, meta) when type in ~w[Article Note Page] do - ArticleNotePageValidator.cast_and_apply(object, meta) + def cast_and_apply(%{"type" => type} = object) when type in ~w[Article Note Page] do + ArticleNotePageValidator.cast_and_apply(object) end - def cast_and_apply(o, _), do: {:error, {:validator_not_set, o}} + def cast_and_apply(o), do: {:error, {:validator_not_set, o}} def stringify_keys(object) when is_struct(object) do object 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 417f04312..4e27284aa 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 @@ -28,21 +28,21 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.ArticleNotePageValidator do field(:replies, {:array, ObjectValidators.ObjectID}, default: []) end - def cast_and_apply(data, meta \\ []) do + def cast_and_apply(data) do data - |> cast_data(meta) + |> cast_data() |> apply_action(:insert) end - def cast_and_validate(data, meta \\ []) do + def cast_and_validate(data) do data - |> cast_data(meta) + |> cast_data() |> validate_data() end - def cast_data(data, meta \\ []) do + def cast_data(data) do %__MODULE__{} - |> changeset(data, meta) + |> changeset(data) end defp fix_url(%{"url" => url} = data) when is_bitstring(url), do: data @@ -76,7 +76,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.ArticleNotePageValidator do def fix_attachments(data), do: data - defp fix(data, meta) do + defp fix(data) do data |> CommonFixes.fix_actor() |> CommonFixes.fix_object_defaults() @@ -87,12 +87,12 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.ArticleNotePageValidator do |> CommonFixes.fix_quote_url() |> Transmogrifier.fix_emoji() |> Transmogrifier.fix_content_map() - |> CommonFixes.maybe_add_language(meta) + |> CommonFixes.maybe_add_language() |> CommonFixes.maybe_add_content_map() end - def changeset(struct, data, meta \\ []) do - data = fix(data, meta) + def changeset(struct, data) do + data = fix(data) struct |> cast(data, __schema__(:fields) -- [:attachment, :tag]) diff --git a/lib/pleroma/web/activity_pub/object_validators/common_fixes.ex b/lib/pleroma/web/activity_pub/object_validators/common_fixes.ex index 218342136..e732a6430 100644 --- a/lib/pleroma/web/activity_pub/object_validators/common_fixes.ex +++ b/lib/pleroma/web/activity_pub/object_validators/common_fixes.ex @@ -128,11 +128,20 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes do def is_object_link_tag(_), do: false - def maybe_add_language(object, meta \\ []) do + def maybe_add_language_from_activity(object, activity) do + language = get_language_from_context(activity) + + if language do + Map.put(object, "language", language) + else + object + end + end + + def maybe_add_language(object) do language = [ get_language_from_context(object), - get_language_from_context(Keyword.get(meta, :activity_data)), get_language_from_content_map(object) ] |> Enum.find(&is_good_locale_code?(&1)) diff --git a/lib/pleroma/web/activity_pub/object_validators/event_validator.ex b/lib/pleroma/web/activity_pub/object_validators/event_validator.ex index 56ca6fe40..ec23770ad 100644 --- a/lib/pleroma/web/activity_pub/object_validators/event_validator.ex +++ b/lib/pleroma/web/activity_pub/object_validators/event_validator.ex @@ -26,34 +26,35 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.EventValidator do end end - def cast_and_apply(data, meta \\ []) do + def cast_and_apply(data) do data - |> cast_data(meta) + |> cast_data() |> apply_action(:insert) end - def cast_and_validate(data, meta \\ []) do + def cast_and_validate(data) do data - |> cast_data(meta) + |> cast_data() |> validate_data() end - def cast_data(data, meta \\ []) do + @spec cast_data(map()) :: map() + def cast_data(data) do %__MODULE__{} - |> changeset(data, meta) + |> changeset(data) end - defp fix(data, meta) do + defp fix(data) do data |> CommonFixes.fix_actor() |> CommonFixes.fix_object_defaults() |> Transmogrifier.fix_emoji() - |> CommonFixes.maybe_add_language(meta) + |> CommonFixes.maybe_add_language() |> CommonFixes.maybe_add_content_map() end - def changeset(struct, data, meta \\ []) do - data = fix(data, meta) + def changeset(struct, data) do + data = fix(data) struct |> cast(data, __schema__(:fields) -- [:attachment, :tag]) 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 25e29c878..611d0bcd0 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 @@ -186,12 +186,9 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.ArticleNotePageValidatorTest "actor" => user.ap_id } - {:ok, object} = - ArticleNotePageValidator.cast_and_apply(note_activity["object"], - activity_data: note_activity - ) + {:ok, _create_activity, meta} = ObjectValidator.validate(note_activity, []) |> IO.inspect() - assert object.language == "pl" + assert meta[:object_data]["language"] == "pl" end test "it detects language from contentMap" do From a6e066a77d5ce65b034cd62775614d5902d29d85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= Date: Thu, 7 Mar 2024 14:05:45 +0100 Subject: [PATCH 15/19] Fix adding language to json ld header, add transmogrifier test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: marcin mikołajczak --- .../web/activity_pub/transmogrifier.ex | 19 +++++++------------ .../web/activity_pub/transmogrifier_test.exs | 18 ++++++++++++++++++ 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index 169ba5db9..b3a3777a2 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -751,12 +751,11 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do object_id |> Object.normalize(fetch: false) |> Map.get(:data) - |> prepare_object data = data - |> Map.put("object", object) - |> Map.merge(Utils.make_json_ld_header(data)) + |> Map.put("object", prepare_object(object)) + |> Map.merge(Utils.make_json_ld_header(object)) |> Map.delete("bcc") {:ok, data} @@ -764,14 +763,10 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do def prepare_outgoing(%{"type" => "Update", "object" => %{"type" => objtype} = object} = data) when objtype in Pleroma.Constants.updatable_object_types() do - object = - object - |> prepare_object - data = data - |> Map.put("object", object) - |> Map.merge(Utils.make_json_ld_header(data)) + |> Map.put("object", prepare_object(object)) + |> Map.merge(Utils.make_json_ld_header(object)) |> Map.delete("bcc") {:ok, data} @@ -792,7 +787,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do data = data |> strip_internal_fields - |> Map.merge(Utils.make_json_ld_header(data)) + |> Map.merge(Utils.make_json_ld_header()) |> Map.delete("bcc") {:ok, data} @@ -812,7 +807,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do data = data |> Map.put("object", object) - |> Map.merge(Utils.make_json_ld_header(data)) + |> Map.merge(Utils.make_json_ld_header()) {:ok, data} end @@ -830,7 +825,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do data = data |> Map.put("object", object) - |> Map.merge(Utils.make_json_ld_header(data)) + |> Map.merge(Utils.make_json_ld_header()) {:ok, data} end diff --git a/test/pleroma/web/activity_pub/transmogrifier_test.exs b/test/pleroma/web/activity_pub/transmogrifier_test.exs index a49e459a6..8fbcf15f1 100644 --- a/test/pleroma/web/activity_pub/transmogrifier_test.exs +++ b/test/pleroma/web/activity_pub/transmogrifier_test.exs @@ -384,6 +384,24 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do assert modified["object"]["quoteUrl"] == quote_id assert modified["object"]["quoteUri"] == quote_id end + + test "it adds language of the object to its json-ld context" do + user = insert(:user) + + {:ok, activity} = CommonAPI.post(user, %{status: "Cześć", language: "pl"}) + {:ok, modified} = Transmogrifier.prepare_outgoing(activity.object.data) + + assert [_, _, %{"@language" => "pl"}] = modified["@context"] + end + + test "it adds language of the object to Create activity json-ld context" do + user = insert(:user) + + {:ok, activity} = CommonAPI.post(user, %{status: "Cześć", language: "pl"}) + {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data) + + assert [_, _, %{"@language" => "pl"}] = modified["@context"] + end end describe "actor rewriting" do From a40bf5d24fb75b246b9e11908b24cdcedabcb3af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= Date: Sun, 28 Jul 2024 13:44:17 +0200 Subject: [PATCH 16/19] Fix good_locale_code?/1 regex MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: marcin mikołajczak --- .../ecto_type/activity_pub/object_validators/language_code.ex | 2 +- .../activity_pub/object_validators/language_code_test.exs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/pleroma/ecto_type/activity_pub/object_validators/language_code.ex b/lib/pleroma/ecto_type/activity_pub/object_validators/language_code.ex index 3135af1fa..4779deeb0 100644 --- a/lib/pleroma/ecto_type/activity_pub/object_validators/language_code.ex +++ b/lib/pleroma/ecto_type/activity_pub/object_validators/language_code.ex @@ -21,7 +21,7 @@ defmodule Pleroma.EctoType.ActivityPub.ObjectValidators.LanguageCode do def load(data), do: {:ok, data} - def good_locale_code?(code) when is_binary(code), do: code =~ ~r<^[a-zA-Z0-9\-]+$> + def good_locale_code?(code) when is_binary(code), do: code =~ ~r<^[a-zA-Z0-9\-]+\z$> def good_locale_code?(_code), do: false end diff --git a/test/pleroma/ecto_type/activity_pub/object_validators/language_code_test.exs b/test/pleroma/ecto_type/activity_pub/object_validators/language_code_test.exs index 2261cc209..086bb3e97 100644 --- a/test/pleroma/ecto_type/activity_pub/object_validators/language_code_test.exs +++ b/test/pleroma/ecto_type/activity_pub/object_validators/language_code_test.exs @@ -20,6 +20,7 @@ defmodule Pleroma.EctoType.ActivityPub.ObjectValidators.LanguageCodeTest do test "errors for invalid language code" do assert {:error, :invalid_language} = LanguageCode.cast("ru_RU") assert {:error, :invalid_language} = LanguageCode.cast(" ") + assert {:error, :invalid_language} = LanguageCode.cast("en-US\n") end test "errors for non-text" do From 120fbbc97e4430fb87749ca9271d318889dba7ff Mon Sep 17 00:00:00 2001 From: mkljczk Date: Mon, 17 Feb 2025 17:55:03 +0100 Subject: [PATCH 17/19] Include contentMap in outgoing posts Signed-off-by: mkljczk --- lib/pleroma/constants.ex | 1 + lib/pleroma/web/activity_pub/transmogrifier.ex | 4 +++- test/pleroma/web/activity_pub/transmogrifier_test.exs | 9 +++++++++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/lib/pleroma/constants.ex b/lib/pleroma/constants.ex index 2d08cd7a1..42751940a 100644 --- a/lib/pleroma/constants.ex +++ b/lib/pleroma/constants.ex @@ -37,6 +37,7 @@ defmodule Pleroma.Constants do "updated", "emoji", "content", + "contentMap", "summary", "sensitive", "attachment", diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index a6f711733..1cea12aa3 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -6,6 +6,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do @moduledoc """ A module to handle coding from internal to wire ActivityPub and back. """ + alias Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes alias Pleroma.Activity alias Pleroma.EctoType.ActivityPub.ObjectValidators alias Pleroma.Maps @@ -167,7 +168,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do def fix_quote_url_and_maybe_fetch(object, options \\ []) do quote_url = - case Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes.fix_quote_url(object) do + case CommonFixes.fix_quote_url(object) do %{"quoteUrl" => quote_url} -> quote_url _ -> nil end @@ -720,6 +721,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do |> set_reply_to_uri |> set_quote_url |> set_replies + |> CommonFixes.maybe_add_content_map() |> strip_internal_fields |> strip_internal_tags |> set_type diff --git a/test/pleroma/web/activity_pub/transmogrifier_test.exs b/test/pleroma/web/activity_pub/transmogrifier_test.exs index ebf70b3e6..a25c6fe1b 100644 --- a/test/pleroma/web/activity_pub/transmogrifier_test.exs +++ b/test/pleroma/web/activity_pub/transmogrifier_test.exs @@ -639,5 +639,14 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do processed = Transmogrifier.prepare_object(original) assert processed["formerRepresentations"] == original["formerRepresentations"] end + + test "it uses contentMap to specify post language" do + user = insert(:user) + + {:ok, activity} = CommonAPI.post(user, %{status: "Cześć", language: "pl"}) + {:ok, modified} = Transmogrifier.prepare_object(activity.object.data) + + assert %{"contentMap" => %{"pl" => "Cześć"}} = modified["object"] + end end end From 04af8bfd9c884dde39dd2073402e70cc219d3c6d Mon Sep 17 00:00:00 2001 From: mkljczk Date: Mon, 17 Feb 2025 18:26:24 +0100 Subject: [PATCH 18/19] credo Signed-off-by: mkljczk --- lib/pleroma/web/activity_pub/transmogrifier.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index 1cea12aa3..4c9956c7a 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -6,7 +6,6 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do @moduledoc """ A module to handle coding from internal to wire ActivityPub and back. """ - alias Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes alias Pleroma.Activity alias Pleroma.EctoType.ActivityPub.ObjectValidators alias Pleroma.Maps @@ -17,6 +16,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.ActivityPub.Builder alias Pleroma.Web.ActivityPub.ObjectValidator + alias Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes alias Pleroma.Web.ActivityPub.Pipeline alias Pleroma.Web.ActivityPub.Utils alias Pleroma.Web.ActivityPub.Visibility From ce4c07cc2b16d429eaabf324407e7aafd93843a9 Mon Sep 17 00:00:00 2001 From: mkljczk Date: Mon, 17 Feb 2025 19:21:08 +0100 Subject: [PATCH 19/19] update test Signed-off-by: mkljczk --- test/pleroma/web/activity_pub/transmogrifier_test.exs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/pleroma/web/activity_pub/transmogrifier_test.exs b/test/pleroma/web/activity_pub/transmogrifier_test.exs index a25c6fe1b..fcb8d65d1 100644 --- a/test/pleroma/web/activity_pub/transmogrifier_test.exs +++ b/test/pleroma/web/activity_pub/transmogrifier_test.exs @@ -644,9 +644,9 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do user = insert(:user) {:ok, activity} = CommonAPI.post(user, %{status: "Cześć", language: "pl"}) - {:ok, modified} = Transmogrifier.prepare_object(activity.object.data) + object = Transmogrifier.prepare_object(activity.object.data) - assert %{"contentMap" => %{"pl" => "Cześć"}} = modified["object"] + assert %{"contentMap" => %{"pl" => "Cześć"}} = object end end end