Resolve merge conflict
[akkoma] / lib / pleroma / formatter.ex
index 8024d97c2dc716454592cd5fc8e739d1962f4765..49f7075e6f1640667bae117e9feb7325ec0d44f1 100644 (file)
@@ -1,15 +1,22 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
 defmodule Pleroma.Formatter do
   alias Pleroma.User
   alias Pleroma.Web.MediaProxy
   alias Pleroma.HTML
   alias Pleroma.Emoji
 
-  @tag_regex ~r/\#\w+/u
+  @tag_regex ~r/((?<=[^&])|\A)(\#)(\w+)/u
   @markdown_characters_regex ~r/(`|\*|_|{|}|[|]|\(|\)|#|\+|-|\.|!)/
 
+  # Modified from https://www.w3.org/TR/html5/forms.html#valid-e-mail-address
+  @mentions_regex ~r/@[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]*@?[a-zA-Z0-9_-](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*/u
+
   def parse_tags(text, data \\ %{}) do
     Regex.scan(@tag_regex, text)
-    |> Enum.map(fn ["#" <> tag = full_tag] -> {full_tag, String.downcase(tag)} end)
+    |> Enum.map(fn ["#" <> tag = full_tag | _] -> {full_tag, String.downcase(tag)} end)
     |> (fn map ->
           if data["sensitive"] in [true, "True", "true", "1"],
             do: [{"#nsfw", "nsfw"}] ++ map,
@@ -17,16 +24,15 @@ defmodule Pleroma.Formatter do
         end).()
   end
 
+  @doc "Parses mentions text and returns list {nickname, user}."
+  @spec parse_mentions(binary()) :: list({binary(), User.t()})
   def parse_mentions(text) do
-    # Modified from https://www.w3.org/TR/html5/forms.html#valid-e-mail-address
-    regex =
-      ~r/@[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]*@?[a-zA-Z0-9_-](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*/u
-
-    Regex.scan(regex, text)
+    Regex.scan(@mentions_regex, text)
     |> List.flatten()
     |> Enum.uniq()
-    |> Enum.map(fn "@" <> match = full_match ->
-      {full_match, User.get_cached_by_nickname(match)}
+    |> Enum.map(fn nickname ->
+      with nickname <- String.trim_leading(nickname, "@"),
+           do: {"@" <> nickname, User.get_cached_by_nickname(nickname)}
     end)
     |> Enum.filter(fn {_match, user} -> user end)
   end
@@ -155,7 +161,7 @@ defmodule Pleroma.Formatter do
     uuid_text =
       tags
       |> Enum.reduce(text, fn {match, _short, uuid}, text ->
-        String.replace(text, match, uuid)
+        String.replace(text, ~r/((?<=[^&])|(\A))#{match}/, uuid)
       end)
 
     subs =