Accept map of strings in ActivityDraft
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
This commit is contained in:
parent
e11d4b6923
commit
0d96c04019
7 changed files with 228 additions and 13 deletions
|
@ -11,6 +11,7 @@ defmodule Pleroma.Web.ActivityPub.Builder do
|
|||
|
||||
alias Pleroma.Activity
|
||||
alias Pleroma.Emoji
|
||||
alias Pleroma.MultiLanguage
|
||||
alias Pleroma.Object
|
||||
alias Pleroma.User
|
||||
alias Pleroma.Web.ActivityPub.Relay
|
||||
|
@ -216,19 +217,39 @@ def create(actor, object, recipients) do
|
|||
|
||||
@spec note(ActivityDraft.t()) :: {:ok, map(), keyword()}
|
||||
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)
|
||||
}
|
||||
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)
|
||||
}
|
||||
else
|
||||
%{"summary" => draft.summary}
|
||||
end
|
||||
|
||||
data =
|
||||
%{
|
||||
"type" => "Note",
|
||||
"to" => draft.to,
|
||||
"cc" => draft.cc,
|
||||
"content" => draft.content_html,
|
||||
"summary" => draft.summary,
|
||||
"sensitive" => draft.sensitive,
|
||||
"context" => draft.context,
|
||||
"attachment" => draft.attachments,
|
||||
"actor" => draft.user.ap_id,
|
||||
"tag" => Keyword.values(draft.tags) |> Enum.uniq()
|
||||
}
|
||||
|> Map.merge(content_fields)
|
||||
|> Map.merge(summary_fields)
|
||||
|> add_in_reply_to(draft.in_reply_to)
|
||||
|> add_quote(draft.quote_post)
|
||||
|> Map.merge(draft.extra)
|
||||
|
|
|
@ -561,6 +561,12 @@ defp create_request do
|
|||
description:
|
||||
"Text content of the status. If `media_ids` is provided, this becomes optional. Attaching a `poll` is optional while `status` is provided."
|
||||
},
|
||||
status_map:
|
||||
Helpers.multilang_map_of(%Schema{
|
||||
type: :string,
|
||||
description:
|
||||
"Text content of the status. If `media_ids` is provided, this becomes optional. Attaching a `poll` is optional while `status` is provided."
|
||||
}),
|
||||
media_ids: %Schema{
|
||||
nullable: true,
|
||||
type: :array,
|
||||
|
@ -584,6 +590,12 @@ defp create_request do
|
|||
description:
|
||||
"Text to be shown as a warning or subject before the actual content. Statuses are generally collapsed behind this field."
|
||||
},
|
||||
spoiler_text_map:
|
||||
Helpers.multilang_map_of(%Schema{
|
||||
type: :string,
|
||||
description:
|
||||
"Text to be shown as a warning or subject before the actual content. Statuses are generally collapsed behind this field."
|
||||
}),
|
||||
scheduled_at: %Schema{
|
||||
type: :string,
|
||||
format: :"date-time",
|
||||
|
@ -592,9 +604,20 @@ defp create_request do
|
|||
"ISO 8601 Datetime at which to schedule a status. Providing this parameter will cause ScheduledStatus to be returned instead of Status. Must be at least 5 minutes in the future."
|
||||
},
|
||||
language: %Schema{
|
||||
type: :string,
|
||||
nullable: true,
|
||||
description: "ISO 639 language code for this status."
|
||||
oneOf: [
|
||||
%Schema{
|
||||
type: :string,
|
||||
nullable: true,
|
||||
description: "ISO 639 language code for this status."
|
||||
},
|
||||
%Schema{
|
||||
type: :array,
|
||||
items: %Schema{
|
||||
type: :string,
|
||||
description: "ISO 639 language code for this status."
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
# Pleroma-specific properties:
|
||||
preview: %Schema{
|
||||
|
|
|
@ -26,7 +26,9 @@ defmodule Pleroma.Web.CommonAPI.ActivityDraft do
|
|||
user: nil,
|
||||
params: %{},
|
||||
status: nil,
|
||||
status_map: nil,
|
||||
summary: nil,
|
||||
summary_map: nil,
|
||||
full_payload: nil,
|
||||
attachments: [],
|
||||
in_reply_to: nil,
|
||||
|
@ -37,6 +39,7 @@ defmodule Pleroma.Web.CommonAPI.ActivityDraft do
|
|||
extra: nil,
|
||||
emoji: %{},
|
||||
content_html: nil,
|
||||
content_html_map: nil,
|
||||
mentions: [],
|
||||
tags: [],
|
||||
to: [],
|
||||
|
@ -149,14 +152,33 @@ defp put_params(draft, params) do
|
|||
%__MODULE__{draft | params: params}
|
||||
end
|
||||
|
||||
defp status(%{params: %{status_map: status_map}} = draft) do
|
||||
%__MODULE__{draft | status_map: status_map}
|
||||
end
|
||||
|
||||
defp status(%{params: %{status: status}} = draft) do
|
||||
%__MODULE__{draft | status: String.trim(status)}
|
||||
end
|
||||
|
||||
defp summary(%{params: %{spoiler_text_map: spoiler_text_map}} = draft) do
|
||||
%__MODULE__{draft | summary_map: spoiler_text_map}
|
||||
end
|
||||
|
||||
defp summary(%{params: params} = draft) do
|
||||
%__MODULE__{draft | summary: Map.get(params, :spoiler_text, "")}
|
||||
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)
|
||||
full_payload = String.trim(status <> summary)
|
||||
|
||||
case Utils.validate_character_limit(full_payload, draft.attachments) do
|
||||
:ok -> %__MODULE__{draft | full_payload: full_payload}
|
||||
{:error, message} -> add_error(draft, message)
|
||||
end
|
||||
end
|
||||
|
||||
defp full_payload(%{status: status, summary: summary} = draft) do
|
||||
full_payload = String.trim(status <> summary)
|
||||
|
||||
|
@ -265,7 +287,9 @@ defp poll(draft) do
|
|||
end
|
||||
|
||||
defp content(%{mentions: mentions} = draft) do
|
||||
{content_html, mentioned_users, tags} = Utils.make_content_html(draft)
|
||||
{content_html_or_map, mentioned_users, tags} = Utils.make_content_html(draft)
|
||||
|
||||
{content_html, content_html_map} = differentiate_string_map(content_html_or_map)
|
||||
|
||||
mentioned_ap_ids =
|
||||
Enum.map(mentioned_users, fn {_, mentioned_user} -> mentioned_user.ap_id end)
|
||||
|
@ -275,7 +299,13 @@ defp content(%{mentions: mentions} = draft) do
|
|||
|> Kernel.++(mentioned_ap_ids)
|
||||
|> Utils.get_addressed_users(draft.params[:to])
|
||||
|
||||
%__MODULE__{draft | content_html: content_html, mentions: mentions, tags: tags}
|
||||
%__MODULE__{
|
||||
draft
|
||||
| content_html: content_html,
|
||||
content_html_map: content_html_map,
|
||||
mentions: mentions,
|
||||
tags: tags
|
||||
}
|
||||
end
|
||||
|
||||
defp to_and_cc(draft) do
|
||||
|
@ -341,10 +371,12 @@ defp object(draft) do
|
|||
object =
|
||||
note_data
|
||||
|> Map.put("emoji", emoji)
|
||||
|> Map.put("source", %{
|
||||
"content" => draft.status,
|
||||
"mediaType" => Utils.get_content_type(draft.params[:content_type])
|
||||
})
|
||||
|> Map.put(
|
||||
"source",
|
||||
Map.merge(get_source_map(draft), %{
|
||||
"mediaType" => Utils.get_content_type(draft.params[:content_type])
|
||||
})
|
||||
)
|
||||
|> Map.put("generator", draft.params[:generator])
|
||||
|> Map.put("content_type", draft.params[:content_type])
|
||||
|> Map.put("language", draft.language)
|
||||
|
@ -461,4 +493,18 @@ defp add_error(draft, message) do
|
|||
|
||||
defp validate(%{valid?: true} = draft), do: {:ok, draft}
|
||||
defp validate(%{errors: [message | _]}), do: {:error, message}
|
||||
|
||||
defp differentiate_string_map(%{} = map), do: {nil, map}
|
||||
defp differentiate_string_map(str) when is_binary(str), do: {str, nil}
|
||||
|
||||
defp get_source_map(%{status_map: status_map} = _draft) do
|
||||
%{
|
||||
"content" => Pleroma.MultiLanguage.map_to_str(status_map, mutiline: true),
|
||||
"contentMap" => status_map
|
||||
}
|
||||
end
|
||||
|
||||
defp get_source_map(%{status: status} = _draft) do
|
||||
%{"content" => status}
|
||||
end
|
||||
end
|
||||
|
|
|
@ -231,7 +231,7 @@ def make_content_html(%ActivityDraft{} = draft) do
|
|||
[]
|
||||
end
|
||||
|
||||
draft.status
|
||||
draft
|
||||
|> format_input(content_type, options)
|
||||
|> maybe_add_attachments(draft.attachments, attachment_links)
|
||||
end
|
||||
|
@ -253,6 +253,15 @@ def make_context(_, _), do: Utils.generate_context_id()
|
|||
|
||||
def maybe_add_attachments(parsed, _attachments, false = _no_links), do: parsed
|
||||
|
||||
def maybe_add_attachments({%{} = text_map, mentions, tags}, attachments, _no_links) do
|
||||
text_map =
|
||||
Enum.reduce(text_map, %{}, fn {lang, text}, acc ->
|
||||
Map.put(acc, lang, add_attachments(text, attachments))
|
||||
end)
|
||||
|
||||
{text_map, mentions, tags}
|
||||
end
|
||||
|
||||
def maybe_add_attachments({text, mentions, tags}, attachments, _no_links) do
|
||||
text = add_attachments(text, attachments)
|
||||
{text, mentions, tags}
|
||||
|
@ -273,6 +282,31 @@ defp build_attachment_link(_), do: ""
|
|||
|
||||
def format_input(text, format, options \\ [])
|
||||
|
||||
def format_input(%ActivityDraft{status_map: status_map} = _draft, format, options)
|
||||
when is_map(status_map) do
|
||||
{content_map, mentions, tags} =
|
||||
Enum.reduce(
|
||||
status_map,
|
||||
{%{}, [], []},
|
||||
fn {lang, status}, {content_map, mentions, tags} ->
|
||||
{cur_content, cur_mentions, cur_tags} = format_input(status, format, options)
|
||||
|
||||
{
|
||||
Map.put(content_map, lang, cur_content),
|
||||
mentions ++ cur_mentions,
|
||||
tags ++ cur_tags
|
||||
}
|
||||
end
|
||||
)
|
||||
|
||||
{content_map, Enum.uniq(mentions), Enum.uniq(tags)}
|
||||
end
|
||||
|
||||
def format_input(%ActivityDraft{status: status} = _draft, format, options)
|
||||
when is_binary(status) do
|
||||
format_input(status, format, options)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Formatting text to plain text, BBCode, HTML, or Markdown
|
||||
"""
|
||||
|
|
|
@ -45,6 +45,32 @@ test "returns note data" do
|
|||
assert {:ok, ^expected, []} = Builder.note(draft)
|
||||
end
|
||||
|
||||
test "accepts multilang" do
|
||||
user = insert(:user)
|
||||
|
||||
draft = %ActivityDraft{
|
||||
user: user,
|
||||
to: [user.ap_id],
|
||||
context: "2hu",
|
||||
content_html_map: %{"a" => "mew", "b" => "lol"},
|
||||
tags: [],
|
||||
summary_map: %{"a" => "mew", "b" => "lol"},
|
||||
cc: [],
|
||||
extra: %{}
|
||||
}
|
||||
|
||||
assert {:ok,
|
||||
%{
|
||||
"contentMap" => %{"a" => "mew", "b" => "lol"},
|
||||
"content" => content,
|
||||
"summaryMap" => %{"a" => "mew", "b" => "lol"},
|
||||
"summary" => summary
|
||||
}, []} = Builder.note(draft)
|
||||
|
||||
assert is_binary(content)
|
||||
assert is_binary(summary)
|
||||
end
|
||||
|
||||
test "quote post" do
|
||||
user = insert(:user)
|
||||
note = insert(:note)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
||||
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.CommonAPI.ActivityDraftTest do
|
||||
|
@ -10,6 +10,30 @@ defmodule Pleroma.Web.CommonAPI.ActivityDraftTest do
|
|||
|
||||
import Pleroma.Factory
|
||||
|
||||
describe "multilang processing" do
|
||||
setup do
|
||||
[user: insert(:user)]
|
||||
end
|
||||
|
||||
test "content", %{user: user} do
|
||||
{:ok, draft} =
|
||||
ActivityDraft.create(user, %{
|
||||
status_map: %{"a" => "mew mew", "b" => "lol lol"},
|
||||
spoiler_text_map: %{"a" => "mew", "b" => "lol"}
|
||||
})
|
||||
|
||||
assert %{
|
||||
"contentMap" => %{"a" => "mew mew", "b" => "lol lol"},
|
||||
"content" => content,
|
||||
"summaryMap" => %{"a" => "mew", "b" => "lol"},
|
||||
"summary" => summary
|
||||
} = draft.object
|
||||
|
||||
assert is_binary(content)
|
||||
assert is_binary(summary)
|
||||
end
|
||||
end
|
||||
|
||||
test "create/2 with a quote post" do
|
||||
user = insert(:user)
|
||||
another_user = insert(:user)
|
||||
|
|
|
@ -81,6 +81,47 @@ test "works for bare text/plain" do
|
|||
assert output == expected
|
||||
end
|
||||
|
||||
test "works for multilang" do
|
||||
draft = %ActivityDraft{
|
||||
status_map: %{
|
||||
"a" => "mew",
|
||||
"b" => "lol"
|
||||
}
|
||||
}
|
||||
|
||||
expected = %{"a" => "mew", "b" => "lol"}
|
||||
|
||||
{output, [], []} = Utils.format_input(draft, "text/plain")
|
||||
|
||||
assert output == expected
|
||||
end
|
||||
|
||||
test "works for multilang, mentions and tags" do
|
||||
user1 = insert(:user)
|
||||
user2 = insert(:user)
|
||||
user3 = insert(:user)
|
||||
|
||||
draft = %ActivityDraft{
|
||||
status_map: %{
|
||||
"a" => "mew, @#{user1.nickname} @#{user2.nickname} #foo #bar",
|
||||
"b" => "lol, @#{user2.nickname} @#{user3.nickname} #bar #lol"
|
||||
}
|
||||
}
|
||||
|
||||
{_, mentions, tags} = Utils.format_input(draft, "text/plain")
|
||||
mentions = Enum.map(mentions, fn {_, user} -> user.ap_id end)
|
||||
tags = Enum.map(tags, fn {_, tag} -> tag end)
|
||||
|
||||
assert [_, _, _] = mentions
|
||||
assert user1.ap_id in mentions
|
||||
assert user2.ap_id in mentions
|
||||
assert user3.ap_id in mentions
|
||||
assert [_, _, _] = tags
|
||||
assert "foo" in tags
|
||||
assert "bar" in tags
|
||||
assert "lol" in tags
|
||||
end
|
||||
|
||||
test "works for bare text/html" do
|
||||
text = "<p>hello world!</p>"
|
||||
expected = "<p>hello world!</p>"
|
||||
|
|
Loading…
Reference in a new issue