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 index 2cc0fda003..0271c0b7e3 100644 --- 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 @@ -5,13 +5,13 @@ defmodule Pleroma.EctoType.ActivityPub.ObjectValidators.ContentLanguageMap do use Ecto.Type - import Pleroma.EctoType.ActivityPub.ObjectValidators.LanguageCode, - only: [is_good_locale_code?: 1] + alias Pleroma.MultiLanguage def type, do: :map def cast(%{} = object) do - with {status, %{} = data} when status in [:modified, :ok] <- validate_map(object) do + with {status, %{} = data} when status in [:modified, :ok] <- + MultiLanguage.validate_map(object) do {:ok, data} else {_, nil} -> {:ok, nil} @@ -24,26 +24,4 @@ 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/ecto_type/activity_pub/object_validators/language_code.ex b/lib/pleroma/ecto_type/activity_pub/object_validators/language_code.ex index b15e9ec5e0..0cf72f404e 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,10 +5,12 @@ defmodule Pleroma.EctoType.ActivityPub.ObjectValidators.LanguageCode do use Ecto.Type + alias Pleroma.MultiLanguage + def type, do: :string def cast(language) when is_binary(language) do - if is_good_locale_code?(language) do + if MultiLanguage.is_good_locale_code?(language) do {:ok, language} else {:error, :invalid_language} @@ -20,8 +22,4 @@ def cast(_), do: :error 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 deleted file mode 100644 index c36fe00b51..0000000000 --- a/lib/pleroma/ecto_type/activity_pub/object_validators/map_of_string.ex +++ /dev/null @@ -1,27 +0,0 @@ -# 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 - - alias Pleroma.MultiLanguage - - def type, do: :map - - def cast(%{} = object) do - with {status, %{} = data} when status in [:modified, :ok] <- - MultiLanguage.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} -end diff --git a/lib/pleroma/multi_language.ex b/lib/pleroma/multi_language.ex index ca69b79813..5d74c19b94 100644 --- a/lib/pleroma/multi_language.ex +++ b/lib/pleroma/multi_language.ex @@ -9,19 +9,9 @@ defp template(:single), do: Pleroma.Config.get([__MODULE__, :single_line_templat defp sep(:multi), do: Pleroma.Config.get([__MODULE__, :separator]) defp sep(:single), do: Pleroma.Config.get([__MODULE__, :single_line_separator]) - def is_good_locale_code?(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\-]+$> - # [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 + def is_good_locale_code?(_code), do: false def validate_map(%{} = object) do {status, data} = diff --git a/lib/pleroma/web/activity_pub/object_validators/attachment_validator.ex b/lib/pleroma/web/activity_pub/object_validators/attachment_validator.ex index c96717e78f..288fa2afa0 100644 --- a/lib/pleroma/web/activity_pub/object_validators/attachment_validator.ex +++ b/lib/pleroma/web/activity_pub/object_validators/attachment_validator.ex @@ -15,7 +15,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AttachmentValidator do field(:type, :string, default: "Link") field(:mediaType, ObjectValidators.MIME, default: "application/octet-stream") field(:name, :string) - field(:nameMap, ObjectValidators.MapOfString) + field(:nameMap, ObjectValidators.ContentLanguageMap) field(:blurhash, :string) embeds_many :url, UrlObjectValidator, primary_key: false 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 b626ccca6f..881ab35a68 100644 --- a/lib/pleroma/web/activity_pub/object_validators/common_fields.ex +++ b/lib/pleroma/web/activity_pub/object_validators/common_fields.ex @@ -50,9 +50,9 @@ defmacro status_object_fields do embeds_many(:tag, TagValidator) field(:name, :string) - field(:nameMap, ObjectValidators.MapOfString) + field(:nameMap, ObjectValidators.ContentLanguageMap) field(:summary, :string) - field(:summaryMap, ObjectValidators.MapOfString) + field(:summaryMap, ObjectValidators.ContentLanguageMap) field(:context, :string) 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 ea90e0819e..aba3932325 100644 --- a/lib/pleroma/web/activity_pub/object_validators/common_fixes.ex +++ b/lib/pleroma/web/activity_pub/object_validators/common_fixes.ex @@ -6,6 +6,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes do alias Pleroma.EctoType.ActivityPub.ObjectValidators alias Pleroma.Language.LanguageDetector alias Pleroma.Maps + alias Pleroma.MultiLanguage alias Pleroma.Object alias Pleroma.Object.Containment alias Pleroma.User @@ -14,9 +15,6 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes do require Pleroma.Constants - 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 @@ -149,7 +147,7 @@ def maybe_add_language(object) do get_language_from_content_map(object), get_language_from_content(object) ] - |> Enum.find(&is_good_locale_code?(&1)) + |> Enum.find(&MultiLanguage.is_good_locale_code?(&1)) if language do Map.put(object, "language", language) diff --git a/lib/pleroma/web/activity_pub/object_validators/question_options_validator.ex b/lib/pleroma/web/activity_pub/object_validators/question_options_validator.ex index 2f80fb9b96..6927cd71fc 100644 --- a/lib/pleroma/web/activity_pub/object_validators/question_options_validator.ex +++ b/lib/pleroma/web/activity_pub/object_validators/question_options_validator.ex @@ -15,7 +15,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.QuestionOptionsValidator do embedded_schema do field(:name, :string) field(:nameRendered, :string) - field(:nameMap, ObjectValidators.MapOfString) + field(:nameMap, ObjectValidators.ContentLanguageMap) embeds_one :replies, Replies, primary_key: false do field(:totalItems, :integer) diff --git a/lib/pleroma/web/common_api/activity_draft.ex b/lib/pleroma/web/common_api/activity_draft.ex index 1ba33a4357..67238c41ab 100644 --- a/lib/pleroma/web/common_api/activity_draft.ex +++ b/lib/pleroma/web/common_api/activity_draft.ex @@ -14,9 +14,6 @@ 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 import Pleroma.Web.Utils.Guards, only: [not_empty_string: 1] @@ -48,7 +45,6 @@ defmodule Pleroma.Web.CommonAPI.ActivityDraft do cc: [], context: nil, sensitive: false, - language: nil, object: nil, preview?: false, changes: %{}, @@ -66,7 +62,6 @@ def new(user, params) do def create(user, params) do user |> new(params) - |> language() |> status() |> summary() |> with_valid(&attachments/1) @@ -81,9 +76,9 @@ def create(user, params) do |> with_valid(&content/1) |> with_valid(&to_and_cc/1) |> with_valid(&context/1) - |> with_valid(&language/1) |> sensitive() |> with_valid(&object/1) + |> with_valid(&language/1) |> preview?() |> with_valid(&changes/1) |> validate() @@ -155,19 +150,27 @@ defp put_params(draft, params) do %__MODULE__{draft | params: params} end - defp language(%{params: %{language: language}} = draft) do + defp language(draft) do + language = + draft.params[:language] || + LanguageDetector.detect( + draft.content_html <> " " <> (draft.summary || draft.params[:name]) + ) + if MultiLanguage.is_good_locale_code?(language) do %__MODULE__{draft | language: language} else - add_error( - draft, - dgettext("errors", "language \"%{language}\" is invalid", language: language) - ) + if draft.params[:language] do + add_error( + draft, + dgettext("errors", "language \"%{language}\" is invalid", language: language) + ) + else + draft + end end end - defp language(draft), do: draft - defp status(%{params: %{status_map: %{} = status_map}} = draft) do with {:ok, %{}} <- MultiLanguage.validate_map(status_map) do %__MODULE__{draft | status_map: status_map} @@ -355,20 +358,6 @@ defp sensitive(draft) do %__MODULE__{draft | sensitive: sensitive} end - defp language(draft) do - language = - draft.params[:language] || - LanguageDetector.detect( - draft.content_html <> " " <> (draft.summary || draft.params[:name]) - ) - - if 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) diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex index d908dcde1c..db805889d7 100644 --- a/lib/pleroma/web/common_api/utils.ex +++ b/lib/pleroma/web/common_api/utils.ex @@ -152,7 +152,7 @@ def make_poll_data(%{poll: %{options_map: options_map, expires_in: expires_in}} when is_list(options_map) do limits = Config.get([:instance, :poll_limits]) - options = options |> Enum.uniq() + options_map = options_map |> Enum.uniq() with :ok <- validate_poll_expiration(expires_in, limits), :ok <- validate_poll_options_map(options_map), diff --git a/lib/pleroma/web/mastodon_api/controllers/status_controller.ex b/lib/pleroma/web/mastodon_api/controllers/status_controller.ex index efc1d9fd7d..575f7188f7 100644 --- a/lib/pleroma/web/mastodon_api/controllers/status_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/status_controller.ex @@ -205,6 +205,26 @@ def create( |> do_create end + def create( + %{ + assigns: %{user: _user}, + private: %{open_api_spex: %{body_params: %{status_map: _}}} + } = conn, + _ + ) do + create(conn |> put_in([:private, :open_api_spex, :body_params, :status], ""), %{}) + end + + def create( + %{ + assigns: %{user: _user}, + private: %{open_api_spex: %{body_params: %{media_ids: _}}} + } = conn, + _ + ) do + create(conn |> put_in([:private, :open_api_spex, :body_params, :status], ""), %{}) + end + defp do_create( %{assigns: %{user: user}, private: %{open_api_spex: %{body_params: params}}} = conn ) do @@ -232,26 +252,6 @@ defp do_create( end end - def create( - %{ - assigns: %{user: _user}, - private: %{open_api_spex: %{body_params: %{status_map: _}}} = params - } = conn, - _ - ) do - create(conn |> put_in([:private, :open_api_spex, :body_params, :status], ""), %{}) - end - - def create( - %{ - assigns: %{user: _user}, - private: %{open_api_spex: %{body_params: %{media_ids: _}}} = params - } = conn, - _ - ) do - create(conn |> put_in([:private, :open_api_spex, :body_params, :status], ""), %{}) - end - @doc "GET /api/v1/statuses/:id/history" def show_history( %{assigns: assigns, private: %{open_api_spex: %{params: %{id: id} = params}}} = conn, diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex index 751b38f3c6..7b0cf0ca88 100644 --- a/lib/pleroma/web/mastodon_api/views/status_view.ex +++ b/lib/pleroma/web/mastodon_api/views/status_view.ex @@ -449,7 +449,7 @@ def render("show.json", %{activity: %{data: %{"object" => _object}} = activity} mentions: mentions, tags: build_tags(tags), application: build_application(object.data["generator"]), - language: get_language(object), + language: get_language(object.data), emojis: build_emojis(object.data["emoji"]), pleroma: %{ local: activity.local, 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 4ee179dc8e..0000000000 --- a/test/pleroma/ecto_type/activity_pub/object_validators/map_of_string_test.exs +++ /dev/null @@ -1,55 +0,0 @@ -# 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