diff --git a/lib/pleroma/formatter.ex b/lib/pleroma/formatter.ex index 78325095a..ad29d21d7 100644 --- a/lib/pleroma/formatter.ex +++ b/lib/pleroma/formatter.ex @@ -32,26 +32,29 @@ def escape_mention_handler("@" <> nickname = mention, buffer, _, _) do end end + def mention_tag(%User{id: id} = user, nickname, opts \\ []) do + user_url = user.uri || user.ap_id + nickname_text = get_nickname_text(nickname, opts) + + :span + |> Phoenix.HTML.Tag.content_tag( + Phoenix.HTML.Tag.content_tag( + :a, + ["@", Phoenix.HTML.Tag.content_tag(:span, nickname_text)], + "data-user": id, + class: "u-url mention", + href: user_url, + rel: "ugc" + ), + class: "h-card" + ) + |> Phoenix.HTML.safe_to_string() + end + def mention_handler("@" <> nickname, buffer, opts, acc) do case User.get_cached_by_nickname(nickname) do - %User{id: id} = user -> - user_url = user.uri || user.ap_id - nickname_text = get_nickname_text(nickname, opts) - - link = - Phoenix.HTML.Tag.content_tag( - :span, - Phoenix.HTML.Tag.content_tag( - :a, - ["@", Phoenix.HTML.Tag.content_tag(:span, nickname_text)], - "data-user": id, - class: "u-url mention", - href: user_url, - rel: "ugc" - ), - class: "h-card" - ) - |> Phoenix.HTML.safe_to_string() + %User{id: _id} = user -> + link = mention_tag(user, nickname, opts) {link, %{acc | mentions: MapSet.put(acc.mentions, {"@" <> nickname, user})}} 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 e11335170..243a25b18 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 @@ -4,7 +4,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.ArticleNotePageValidator do use Ecto.Schema - + alias Pleroma.User alias Pleroma.EctoType.ActivityPub.ObjectValidators alias Pleroma.Object.Fetcher alias Pleroma.Web.CommonAPI.Utils @@ -81,16 +81,39 @@ defp fix_replies(%{"replies" => %{"first" => first}} = data) do defp fix_replies(data), do: data + defp remote_mention_resolver(%{"tag" => tags}, "@" <> nickname = mention, buffer, opts, acc) do + with mention_tag <- + Enum.find(tags, fn t -> t["type"] == "Mention" && t["name"] == mention end), + false <- is_nil(mention_tag), + {:ok, %User{} = user} <- User.get_or_fetch_by_ap_id(mention_tag["href"]) do + link = Pleroma.Formatter.mention_tag(user, nickname, opts) + {link, %{acc | mentions: MapSet.put(acc.mentions, {"@" <> nickname, user})}} + else + _ -> {buffer, acc} + end + end + # https://github.com/misskey-dev/misskey/pull/8787 defp fix_misskey_content( %{"source" => %{"mediaType" => "text/x.misskeymarkdown", "content" => content}} = object ) do - {linked, _, _} = Utils.format_input(content, "text/x.misskeymarkdown") + mention_handler = fn nick, buffer, opts, acc -> + remote_mention_resolver(object, nick, buffer, opts, acc) + end + + {linked, _, _} = + Utils.format_input(content, "text/x.misskeymarkdown", mention_handler: mention_handler) + Map.put(object, "content", linked) end defp fix_misskey_content(%{"_misskey_content" => content} = object) do - {linked, _, _} = Utils.format_input(content, "text/x.misskeymarkdown") + mention_handler = fn nick, buffer, opts, acc -> + remote_mention_resolver(object, nick, buffer, opts, acc) + end + + {linked, _, _} = + Utils.format_input(content, "text/x.misskeymarkdown", mention_handler: mention_handler) object |> Map.put("source", %{ diff --git a/test/fixtures/misskey/mfm_x_format.json b/test/fixtures/misskey/mfm_x_format.json index 31d6e5368..a24e90e7e 100644 --- a/test/fixtures/misskey/mfm_x_format.json +++ b/test/fixtures/misskey/mfm_x_format.json @@ -3,9 +3,9 @@ "type": "Note", "attributedTo": "https://misskey.local.live/users/92hzkskwgy", "summary": null, - "content": "

@akkoma_user@akkoma.local.live linkifylink #dancedance mfm goes here

## aaa

", + "content": "this gets replaced", "source": { - "content": "@akkoma_user linkifylink #dancedance $[jelly mfm goes here] \n\n## aaa", + "content": "@akkoma_user @remote_user @oops_not_a_mention linkifylink #dancedance $[jelly mfm goes here] \n\n## aaa", "mediaType": "text/x.misskeymarkdown" }, "published": "2022-07-10T15:37:36.368Z", @@ -29,6 +29,11 @@ "type": "Mention", "href": "http://localhost:4001/users/akkoma_user", "name": "@akkoma_user" + }, + { + "type": "Mention", + "href": "http://misskey.local.live/users/remote_user", + "name": "@remote_user" } ] } 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 62526d952..4ea7a5bc0 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 @@ -71,7 +71,14 @@ test "a note with an attachment should work", _ do end test "a misskey MFM status with a content field should work and be linked", _ do - local_user = insert(:user, %{nickname: "akkoma_user"}) + local_user = + insert(:user, %{nickname: "akkoma_user", ap_id: "http://localhost:4001/users/akkoma_user"}) + + remote_user = + insert(:user, %{ + nickname: "remote_user", + ap_id: "http://misskey.local.live/users/remote_user" + }) insert(:user, %{ap_id: "https://misskey.local.live/users/92hzkskwgy"}) @@ -80,23 +87,31 @@ test "a misskey MFM status with a content field should work and be linked", _ do |> File.read!() |> Jason.decode!() - expected_content = - "@akkoma_user linkifylink #dancedance $[jelly mfm goes here]

## aaa" - %{ valid?: true, changes: %{ - content: ^expected_content, + content: content, source: %{ - "content" => "@akkoma_user linkifylink #dancedance $[jelly mfm goes here] \n\n## aaa", + "content" => + "@akkoma_user @remote_user @oops_not_a_mention linkifylink #dancedance $[jelly mfm goes here] \n\n## aaa", "mediaType" => "text/x.misskeymarkdown" } } } = ArticleNotePageValidator.cast_and_validate(note) + + assert content =~ + "@akkoma_user" + + assert content =~ + "@remote_user" + + assert content =~ "@oops_not_a_mention" + assert content =~ "$[jelly mfm goes here]

## aaa" end test "a misskey MFM status with a _misskey_content field should work and be linked", _ do - local_user = insert(:user, %{nickname: "akkoma_user"}) + local_user = + insert(:user, %{nickname: "akkoma_user", ap_id: "http://localhost:4001/users/akkoma_user"}) insert(:user, %{ap_id: "https://misskey.local.live/users/92hzkskwgy"})