MRF.InlineQuotePolicy: Add link to post URL, not ID
"id" is used for the canonical link to the AS2 representation of an object. "url" is typically used for the canonical link to the HTTP representation. It is what we use, for example, when following the "external source" link in the frontend. However, it's not the link we include in the post contents for quote posts. Using URL instead means we include a more user-friendly URL for Mastodon, and a working (in the browser) URL for Threads
This commit is contained in:
parent
2d439034ca
commit
75d9e2b375
2 changed files with 35 additions and 7 deletions
|
@ -6,14 +6,29 @@ defmodule Pleroma.Web.ActivityPub.MRF.InlineQuotePolicy do
|
||||||
@moduledoc "Force a quote line into the message content."
|
@moduledoc "Force a quote line into the message content."
|
||||||
@behaviour Pleroma.Web.ActivityPub.MRF.Policy
|
@behaviour Pleroma.Web.ActivityPub.MRF.Policy
|
||||||
|
|
||||||
|
alias Pleroma.Object
|
||||||
|
|
||||||
defp build_inline_quote(prefix, url) do
|
defp build_inline_quote(prefix, url) do
|
||||||
"<span class=\"quote-inline\"><br/><br/>#{prefix}: <a href=\"#{url}\">#{url}</a></span>"
|
"<span class=\"quote-inline\"><br/><br/>#{prefix}: <a href=\"#{url}\">#{url}</a></span>"
|
||||||
end
|
end
|
||||||
|
|
||||||
defp has_inline_quote?(content, quote_url) do
|
defp resolve_urls(quote_url) do
|
||||||
|
# Fetching here can cause infinite recursion as we run this logic on inbound objects too
|
||||||
|
# This is probably not a problem - its an exceptional corner case for a local user to quote
|
||||||
|
# a post which doesn't exist
|
||||||
|
with %Object{} = obj <- Object.normalize(quote_url, fetch: false) do
|
||||||
|
id = obj.data["id"]
|
||||||
|
url = Map.get(obj.data, "url", id)
|
||||||
|
{id, url, [id, url, quote_url]}
|
||||||
|
else
|
||||||
|
_ -> {quote_url, quote_url, [quote_url]}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp has_inline_quote?(content, urls) do
|
||||||
cond do
|
cond do
|
||||||
# Does the quote URL exist in the content?
|
# Does the quote URL exist in the content?
|
||||||
content =~ quote_url -> true
|
Enum.any?(urls, fn url -> content =~ url end) -> true
|
||||||
# Does the content already have a .quote-inline span?
|
# Does the content already have a .quote-inline span?
|
||||||
content =~ "<span class=\"quote-inline\">" -> true
|
content =~ "<span class=\"quote-inline\">" -> true
|
||||||
# No inline quote found
|
# No inline quote found
|
||||||
|
@ -22,18 +37,22 @@ defmodule Pleroma.Web.ActivityPub.MRF.InlineQuotePolicy do
|
||||||
end
|
end
|
||||||
|
|
||||||
defp filter_object(%{"quoteUri" => quote_url} = object) do
|
defp filter_object(%{"quoteUri" => quote_url} = object) do
|
||||||
|
{id, preferred_url, all_urls} = resolve_urls(quote_url)
|
||||||
|
object = Map.put(object, "quoteUri", id)
|
||||||
|
|
||||||
content = object["content"] || ""
|
content = object["content"] || ""
|
||||||
|
|
||||||
if has_inline_quote?(content, quote_url) do
|
if has_inline_quote?(content, all_urls) do
|
||||||
object
|
object
|
||||||
else
|
else
|
||||||
prefix = Pleroma.Config.get([:mrf_inline_quote, :prefix])
|
prefix = Pleroma.Config.get([:mrf_inline_quote, :prefix])
|
||||||
|
|
||||||
content =
|
content =
|
||||||
if String.ends_with?(content, "</p>") do
|
if String.ends_with?(content, "</p>") do
|
||||||
String.trim_trailing(content, "</p>") <> build_inline_quote(prefix, quote_url) <> "</p>"
|
String.trim_trailing(content, "</p>") <>
|
||||||
|
build_inline_quote(prefix, preferred_url) <> "</p>"
|
||||||
else
|
else
|
||||||
content <> build_inline_quote(prefix, quote_url)
|
content <> build_inline_quote(prefix, preferred_url)
|
||||||
end
|
end
|
||||||
|
|
||||||
Map.put(object, "content", content)
|
Map.put(object, "content", content)
|
||||||
|
|
|
@ -4,10 +4,16 @@
|
||||||
|
|
||||||
defmodule Pleroma.Web.ActivityPub.MRF.InlineQuotePolicyTest do
|
defmodule Pleroma.Web.ActivityPub.MRF.InlineQuotePolicyTest do
|
||||||
alias Pleroma.Web.ActivityPub.MRF.InlineQuotePolicy
|
alias Pleroma.Web.ActivityPub.MRF.InlineQuotePolicy
|
||||||
|
alias Pleroma.Object
|
||||||
use Pleroma.DataCase
|
use Pleroma.DataCase
|
||||||
|
|
||||||
|
setup_all do
|
||||||
|
Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
|
||||||
|
:ok
|
||||||
|
end
|
||||||
|
|
||||||
test "adds quote URL to post content" do
|
test "adds quote URL to post content" do
|
||||||
quote_url = "https://example.com/objects/1234"
|
quote_url = "https://mastodon.social/users/emelie/statuses/101849165031453009"
|
||||||
|
|
||||||
activity = %{
|
activity = %{
|
||||||
"type" => "Create",
|
"type" => "Create",
|
||||||
|
@ -19,10 +25,13 @@ defmodule Pleroma.Web.ActivityPub.MRF.InlineQuotePolicyTest do
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Prefetch the quoted post
|
||||||
|
%Object{} = Object.normalize(quote_url, fetch: true)
|
||||||
|
|
||||||
{:ok, %{"object" => %{"content" => filtered}}} = InlineQuotePolicy.filter(activity)
|
{:ok, %{"object" => %{"content" => filtered}}} = InlineQuotePolicy.filter(activity)
|
||||||
|
|
||||||
assert filtered ==
|
assert filtered ==
|
||||||
"<p>Nice post<span class=\"quote-inline\"><br/><br/>RE: <a href=\"https://example.com/objects/1234\">https://example.com/objects/1234</a></span></p>"
|
"<p>Nice post<span class=\"quote-inline\"><br/><br/>RE: <a href=\"https://mastodon.social/@emelie/101849165031453009\">https://mastodon.social/@emelie/101849165031453009</a></span></p>"
|
||||||
end
|
end
|
||||||
|
|
||||||
test "ignores Misskey quote posts" do
|
test "ignores Misskey quote posts" do
|
||||||
|
|
Loading…
Reference in a new issue