Post single-language status with language attribute

This commit is contained in:
tusooa 2023-01-04 11:43:25 -05:00 committed by marcin mikołajczak
parent c4cec5fd6a
commit 9555e630fd
5 changed files with 153 additions and 20 deletions

View file

@ -9,7 +9,7 @@ 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])
defp is_good_locale_code?(code) do
def is_good_locale_code?(code) do
code
|> String.codepoints()
|> Enum.all?(&valid_char?/1)
@ -68,8 +68,14 @@ defp map_to_str_impl(data, mode) do
end
end
def str_to_map(data) do
%{"und" => data}
def str_to_map(data, opts \\ []) do
with lang when is_binary(lang) <- opts[:lang],
true <- is_good_locale_code?(lang) do
%{lang => data}
else
_ ->
%{"und" => data}
end
end
def format_template(template, %{code: code, content: content}) do

View file

@ -219,20 +219,32 @@ def create(actor, object, recipients) do
def note(%ActivityDraft{} = draft) do
content_fields =
if draft.content_html_map do
%{
"contentMap" => draft.content_html_map,
"content" => MultiLanguage.map_to_str(draft.content_html_map, multiline: true)
}
case Map.keys(draft.content_html_map) do
["und"] ->
%{"content" => MultiLanguage.map_to_str(draft.content_html_map, multiline: true)}
_ ->
%{
"contentMap" => draft.content_html_map,
"content" => MultiLanguage.map_to_str(draft.content_html_map, multiline: true)
}
end
else
%{"content" => draft.content_html}
end
summary_fields =
if draft.summary_map do
%{
"summaryMap" => draft.summary_map,
"summary" => MultiLanguage.map_to_str(draft.summary_map, multiline: false)
}
case Map.keys(draft.summary_map) do
["und"] ->
%{"summary" => MultiLanguage.map_to_str(draft.summary_map, multiline: false)}
_ ->
%{
"summaryMap" => draft.summary_map,
"summary" => MultiLanguage.map_to_str(draft.summary_map, multiline: false)
}
end
else
%{"summary" => draft.summary}
end

View file

@ -26,6 +26,7 @@ defmodule Pleroma.Web.CommonAPI.ActivityDraft do
errors: [],
user: nil,
params: %{},
language: nil,
status: nil,
status_map: nil,
summary: nil,
@ -65,6 +66,7 @@ def new(user, params) do
def create(user, params) do
user
|> new(params)
|> language()
|> status()
|> summary()
|> with_valid(&attachments/1)
@ -153,6 +155,16 @@ defp put_params(draft, params) do
%__MODULE__{draft | params: params}
end
defp language(%{params: %{language: language}} = draft) do
if MultiLanguage.is_good_locale_code?(language) do
%__MODULE__{draft | language: language}
else
add_error(draft, dgettext("errors", "language \"%{language}\" is invalid", language: language))
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}
@ -178,16 +190,25 @@ defp summary(%{params: params} = draft) do
end
defp full_payload(%{status: status, status_map: nil} = draft) do
full_payload(%__MODULE__{draft | status_map: MultiLanguage.str_to_map(status)})
full_payload(%__MODULE__{
draft
| status_map: MultiLanguage.str_to_map(status, lang: draft.language)
})
end
defp full_payload(%{summary: summary, summary_map: nil} = draft) do
full_payload(%__MODULE__{draft | summary_map: MultiLanguage.str_to_map(summary)})
full_payload(%__MODULE__{
draft
| summary_map: MultiLanguage.str_to_map(summary, lang: draft.language)
})
end
defp full_payload(%{status_map: %{} = status_map, summary_map: %{} = summary_map} = draft) do
status = status_map |> Enum.reduce("", fn {_lang, content}, acc -> acc <> content end)
summary = summary_map |> Enum.reduce("", fn {_lang, content}, acc -> acc <> content end)
status = status_map |> Enum.reduce("", fn {_lang, content}, acc -> acc <> " " <> content end)
summary =
summary_map |> Enum.reduce("", fn {_lang, content}, acc -> acc <> " " <> content end)
full_payload = String.trim(status <> summary)
case Utils.validate_character_limit(full_payload, draft.attachments) do

View file

@ -151,7 +151,6 @@ def make_poll_data(%{"poll" => %{"expires_in" => expires_in}} = data)
def make_poll_data(%{poll: %{options_map: options_map, expires_in: expires_in}} = data)
when is_list(options_map) do
limits = Config.get([:instance, :poll_limits])
is_single_language = data.poll[:is_single_language]
options = options |> Enum.uniq()
@ -161,6 +160,8 @@ def make_poll_data(%{poll: %{options_map: options_map, expires_in: expires_in}}
:ok <- validate_poll_options_length(options_map, limits) do
{option_notes, emoji} =
Enum.map_reduce(options_map, %{}, fn option, emoji ->
is_single_language = Map.keys(option) == ["und"]
name_attrs =
if is_single_language do
%{"name" => option["und"]}
@ -196,8 +197,10 @@ def make_poll_data(%{poll: %{options_map: options_map, expires_in: expires_in}}
def make_poll_data(%{poll: %{options: options}} = data) when is_list(options) do
new_poll =
data.poll
|> Map.put(:options_map, Enum.map(options, &MultiLanguage.str_to_map/1))
|> Map.put(:is_single_language, true)
|> Map.put(
:options_map,
Enum.map(options, &MultiLanguage.str_to_map(&1, lang: data[:language]))
)
data
|> Map.put(:poll, new_poll)

View file

@ -83,8 +83,13 @@ test "posting a status", %{conn: conn} do
"sensitive" => "0"
})
assert %{"content" => "cofe", "id" => id, "spoiler_text" => "2hu", "sensitive" => false} =
json_response_and_validate_schema(conn_one, 200)
assert %{
"content" => "cofe",
"id" => id,
"spoiler_text" => "2hu",
"sensitive" => false,
"language" => nil
} = json_response_and_validate_schema(conn_one, 200)
assert Activity.get_by_id(id)
@ -139,6 +144,52 @@ test "posting a status", %{conn: conn} do
)
end
test "posting a single lang status ", %{conn: conn} do
idempotency_key = "Pikachu rocks!"
conn_one =
conn
|> put_req_header("content-type", "application/json")
|> put_req_header("idempotency-key", idempotency_key)
|> post("/api/v1/statuses", %{
"status" => "mew mew",
"spoiler_text" => "mew",
"sensitive" => "0",
"language" => "a"
})
assert %{
"content" => "mew mew",
"content_map" => %{"a" => "mew mew"},
"id" => id,
"spoiler_text" => "mew",
"spoiler_text_map" => %{"a" => "mew"},
"sensitive" => false,
"language" => "a"
} = json_response_and_validate_schema(conn_one, 200)
assert Activity.get_by_id(id)
end
test "posting a single lang status, bad language code", %{conn: conn} do
idempotency_key = "Pikachu rocks!"
conn_one =
conn
|> put_req_header("content-type", "application/json")
|> put_req_header("idempotency-key", idempotency_key)
|> post("/api/v1/statuses", %{
"status" => "mew mew",
"spoiler_text" => "mew",
"sensitive" => "0",
"language" => "a_"
})
assert %{
"error" => _
} = json_response_and_validate_schema(conn_one, 422)
end
test "posting a multilang status", %{conn: conn} do
idempotency_key = "Pikachu rocks!"
@ -748,6 +799,46 @@ test "posting a poll", %{conn: conn} do
assert question.data["closed"] =~ "Z"
end
test "posting a single-language poll", %{conn: conn} do
conn =
conn
|> put_req_header("content-type", "application/json")
|> post("/api/v1/statuses", %{
"status" => "Who is the #bestgrill?",
"poll" => %{
"options" => ["Rei", "Asuka", "Misato"],
"expires_in" => 420
},
"language" => "a"
})
response = json_response_and_validate_schema(conn, 200)
assert Enum.all?(response["poll"]["options"], fn %{"title_map" => title} ->
title in [
%{"a" => "Rei"},
%{"a" => "Asuka"},
%{"a" => "Misato"}
]
end)
end
test "posting a single-language poll, invalid language code", %{conn: conn} do
conn =
conn
|> put_req_header("content-type", "application/json")
|> post("/api/v1/statuses", %{
"status" => "Who is the #bestgrill?",
"poll" => %{
"options" => ["Rei", "Asuka", "Misato"],
"expires_in" => 420
},
"language" => "a_"
})
json_response_and_validate_schema(conn, 422)
end
test "posting a multilang poll", %{conn: conn} do
time = NaiveDateTime.utc_now()