Resolve merge conflict
[akkoma] / lib / pleroma / formatter.ex
index 9401689cb913769598b5c94b49d445823af7ba85..49f7075e6f1640667bae117e9feb7325ec0d44f1 100644 (file)
@@ -1,3 +1,7 @@
+# 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
@@ -7,6 +11,9 @@ defmodule Pleroma.Formatter do
   @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)
@@ -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
@@ -177,4 +183,22 @@ defmodule Pleroma.Formatter do
       String.replace(result_text, uuid, replacement)
     end)
   end
+
+  def truncate(text, opts \\ []) do
+    max_length = opts[:max_length] || 200
+    omission = opts[:omission] || "..."
+
+    cond do
+      not String.valid?(text) ->
+        text
+
+      String.length(text) < max_length ->
+        text
+
+      true ->
+        length_with_omission = max_length - String.length(omission)
+
+        "#{String.slice(text, 0, length_with_omission)}#{omission}"
+    end
+  end
 end