Fix parsing links with hashtag characters

Closes #1008

Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
Thomas Citharel 2022-01-18 12:46:33 +01:00
parent bda18a2150
commit c8735e5837
No known key found for this signature in database
GPG key ID: A061B9DDE0CA0773
2 changed files with 17 additions and 40 deletions

View file

@ -94,8 +94,7 @@ defmodule Mobilizon.Service.Formatter do
options = linkify_opts() ++ options options = linkify_opts() ++ options
acc = %{mentions: MapSet.new(), tags: MapSet.new()} acc = %{mentions: MapSet.new(), tags: MapSet.new()}
{text, %{mentions: mentions}} = Linkify.link_map(text, acc, options) {text, %{mentions: mentions, tags: tags}} = Linkify.link_map(text, acc, options)
{text, tags} = extract_tags(text)
{text, MapSet.to_list(mentions), MapSet.to_list(tags)} {text, MapSet.to_list(mentions), MapSet.to_list(tags)}
end end
@ -157,46 +156,10 @@ defmodule Mobilizon.Service.Formatter do
defp linkify_opts do defp linkify_opts do
Mobilizon.Config.get(__MODULE__) ++ Mobilizon.Config.get(__MODULE__) ++
[ [
hashtag: false, hashtag: true,
hashtag_handler: &__MODULE__.hashtag_handler/4,
mention: true, mention: true,
mention_handler: &__MODULE__.mention_handler/4 mention_handler: &__MODULE__.mention_handler/4
] ]
end end
@match_hashtag ~r/(?:^|[^\p{L}\p{M}\p{Nd}\)])(?<tag>\#[[:word:]_]*[[:alpha:]_·][[:word:]_·\p{M}]*)/u
@spec extract_tags(String.t()) :: {String.t(), MapSet.t()}
def extract_tags(text) do
matches =
@match_hashtag
|> Regex.scan(text, capture: [:tag])
|> Enum.map(&hd/1)
|> Enum.map(&{&1, tag_text_strip(&1)})
|> MapSet.new()
text =
@match_hashtag
|> Regex.replace(text, &generate_tag_link/2)
|> String.trim()
{text, matches}
end
@spec generate_tag_link(String.t(), String.t()) :: String.t()
defp generate_tag_link(_, tag_text) do
tag = tag_text_strip(tag_text)
url = "#{Endpoint.url()}/tag/#{tag}"
Tag.content_tag(:a, tag_text,
class: "hashtag",
"data-tag": tag,
href: url,
rel: "tag ugc"
)
|> Phoenix.HTML.safe_to_string()
|> (&" #{&1}").()
end
@spec tag_text_strip(String.t()) :: String.t()
defp tag_text_strip(tag), do: tag |> String.trim("#") |> String.downcase()
end end

View file

@ -112,6 +112,20 @@ defmodule Mobilizon.Service.FormatterTest do
"<a href=\"#{text}\" target=\"_blank\" rel=\"noopener noreferrer ugc\">#{text}</a>" "<a href=\"#{text}\" target=\"_blank\" rel=\"noopener noreferrer ugc\">#{text}</a>"
assert {^expected, [], []} = Formatter.linkify(text) assert {^expected, [], []} = Formatter.linkify(text)
text = "https://example.org/#foobar"
expected =
"<a href=\"#{text}\" target=\"_blank\" rel=\"noopener noreferrer ugc\">#{text}</a>"
assert {^expected, [], []} = Formatter.linkify(text)
text = "<p>An article tagged with a #tag.</p>"
expected =
"<p>An article tagged with a <a class=\"hashtag\" data-tag=\"tag\" href=\"http://mobilizon.test/tag/tag\" rel=\"tag ugc\">#tag</a>.</p>"
assert {^expected, [], [{"#tag", "tag"}]} = Formatter.linkify(text)
end end
end end