diff --git a/lib/pleroma/formatter.ex b/lib/pleroma/formatter.ex index dab8910c1..3d7c36d21 100644 --- a/lib/pleroma/formatter.ex +++ b/lib/pleroma/formatter.ex @@ -113,9 +113,7 @@ defmodule Pleroma.Formatter do html = if not strip do - "#{emoji}" + "#{emoji}" else "" end @@ -130,12 +128,23 @@ defmodule Pleroma.Formatter do def demojify(text, nil), do: text + @doc "Outputs a list of the emoji-shortcodes in a text" def get_emoji(text) when is_binary(text) do Enum.filter(Emoji.get_all(), fn {emoji, _, _} -> String.contains?(text, ":#{emoji}:") end) end def get_emoji(_), do: [] + @doc "Outputs a list of the emoji-Maps in a text" + def get_emoji_map(text) when is_binary(text) do + get_emoji(text) + |> Enum.reduce(%{}, fn {name, file, _group}, acc -> + Map.put(acc, name, "#{Pleroma.Web.Endpoint.static_url()}#{file}") + end) + end + + def get_emoji_map(_), do: [] + def html_escape({text, mentions, hashtags}, type) do {html_escape(text, type), mentions, hashtags} end diff --git a/lib/pleroma/html.ex b/lib/pleroma/html.ex index 726c370ad..d1da746de 100644 --- a/lib/pleroma/html.ex +++ b/lib/pleroma/html.ex @@ -151,6 +151,7 @@ defmodule Pleroma.HTML.Scrubber.TwitterText do Meta.allow_tag_with_these_attributes("img", [ "width", "height", + "class", "title", "alt" ]) @@ -221,6 +222,7 @@ defmodule Pleroma.HTML.Scrubber.Default do Meta.allow_tag_with_these_attributes("img", [ "width", "height", + "class", "title", "alt" ]) diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 1c62f238e..1741ce684 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -11,7 +11,6 @@ defmodule Pleroma.User do alias Comeonin.Pbkdf2 alias Pleroma.Activity alias Pleroma.Bookmark - alias Pleroma.Formatter alias Pleroma.Notification alias Pleroma.Object alias Pleroma.Registration @@ -1331,18 +1330,15 @@ defmodule Pleroma.User do end end - def parse_bio(bio, user \\ %User{info: %{source_data: %{}}}) - def parse_bio(nil, _user), do: "" - def parse_bio(bio, _user) when bio == "", do: bio + def parse_bio(bio) when is_binary(bio) and bio != "" do + bio + |> CommonUtils.format_input("text/plain", mentions_format: :full) + |> elem(0) + end - def parse_bio(bio, user) do - emoji = - (user.info.source_data["tag"] || []) - |> Enum.filter(fn %{"type" => t} -> t == "Emoji" end) - |> Enum.map(fn %{"icon" => %{"url" => url}, "name" => name} -> - {String.trim(name, ":"), url} - end) + def parse_bio(_), do: "" + def parse_bio(bio, user) when is_binary(bio) and bio != "" do # TODO: get profile URLs other than user.ap_id profile_urls = [user.ap_id] @@ -1352,9 +1348,10 @@ defmodule Pleroma.User do rel: &RelMe.maybe_put_rel_me(&1, profile_urls) ) |> elem(0) - |> Formatter.emojify(emoji) end + def parse_bio(_, _), do: "" + def tag(user_identifiers, tags) when is_list(user_identifiers) do Repo.transaction(fn -> for user_identifier <- user_identifiers, do: tag(user_identifier, tags) diff --git a/lib/pleroma/user/info.ex b/lib/pleroma/user/info.ex index a3658d57f..1b81619ce 100644 --- a/lib/pleroma/user/info.ex +++ b/lib/pleroma/user/info.ex @@ -41,6 +41,7 @@ defmodule Pleroma.User.Info do field(:hide_favorites, :boolean, default: true) field(:pinned_activities, {:array, :string}, default: []) field(:flavour, :string, default: nil) + field(:emoji, {:array, :map}, default: []) field(:notification_settings, :map, default: %{"remote" => true, "local" => true, "followers" => true, "follows" => true} diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index b774c2afa..508f3532f 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -856,10 +856,16 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do |> Map.put("tag", tags ++ mentions) end + def add_emoji_tags(%User{info: %{"emoji" => _emoji} = user_info} = object) do + user_info = add_emoji_tags(user_info) + + object + |> Map.put(:info, user_info) + end + # TODO: we should probably send mtime instead of unix epoch time for updated - def add_emoji_tags(object) do + def add_emoji_tags(%{"emoji" => emoji} = object) do tags = object["tag"] || [] - emoji = object["emoji"] || [] out = emoji @@ -877,6 +883,10 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do |> Map.put("tag", tags ++ out) end + def add_emoji_tags(object) do + object + end + def set_conversation(object) do Map.put(object, "conversation", object["context"]) end diff --git a/lib/pleroma/web/activity_pub/views/user_view.ex b/lib/pleroma/web/activity_pub/views/user_view.ex index 5926a3294..1254fdf6c 100644 --- a/lib/pleroma/web/activity_pub/views/user_view.ex +++ b/lib/pleroma/web/activity_pub/views/user_view.ex @@ -69,6 +69,11 @@ defmodule Pleroma.Web.ActivityPub.UserView do endpoints = render("endpoints.json", %{user: user}) + user_tags = + user + |> Transmogrifier.add_emoji_tags() + |> Map.get("tag", []) + %{ "id" => user.ap_id, "type" => "Person", @@ -87,7 +92,7 @@ defmodule Pleroma.Web.ActivityPub.UserView do "publicKeyPem" => public_key }, "endpoints" => endpoints, - "tag" => user.info.source_data["tag"] || [] + "tag" => (user.info.source_data["tag"] || []) ++ user_tags } |> Map.merge(maybe_make_image(&User.avatar_url/2, "icon", user)) |> Map.merge(maybe_make_image(&User.banner_url/2, "image", user)) diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex index ecd183110..b53869c75 100644 --- a/lib/pleroma/web/common_api/common_api.ex +++ b/lib/pleroma/web/common_api/common_api.ex @@ -151,8 +151,8 @@ defmodule Pleroma.Web.CommonAPI do ), {to, cc} <- to_for_user_and_mentions(user, mentions, in_reply_to, visibility), context <- make_context(in_reply_to), - cw <- data["spoiler_text"], - full_payload <- String.trim(status <> (data["spoiler_text"] || "")), + cw <- data["spoiler_text"] || "", + full_payload <- String.trim(status <> cw), length when length in 1..limit <- String.length(full_payload), object <- make_note_data( @@ -170,10 +170,7 @@ defmodule Pleroma.Web.CommonAPI do Map.put( object, "emoji", - (Formatter.get_emoji(status) ++ Formatter.get_emoji(data["spoiler_text"])) - |> Enum.reduce(%{}, fn {name, file, _}, acc -> - Map.put(acc, name, "#{Pleroma.Web.Endpoint.static_url()}#{file}") - end) + Formatter.get_emoji_map(full_payload) ) do res = ActivityPub.create( diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index 201a21f50..0840c2c5a 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -9,6 +9,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do alias Pleroma.Bookmark alias Pleroma.Config alias Pleroma.Filter + alias Pleroma.Formatter alias Pleroma.Notification alias Pleroma.Object alias Pleroma.Object.Fetcher @@ -86,7 +87,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do user_params = %{} |> add_if_present(params, "display_name", :name) - |> add_if_present(params, "note", :bio, fn value -> {:ok, User.parse_bio(value)} end) + |> add_if_present(params, "note", :bio, fn value -> {:ok, User.parse_bio(value, user)} end) |> add_if_present(params, "avatar", :avatar, fn value -> with %Plug.Upload{} <- value, {:ok, object} <- ActivityPub.upload(value, type: :avatar) do @@ -96,6 +97,12 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do end end) + emojis_text = (user_params["display_name"] || "") <> (user_params["note"] || "") + + user_info_emojis = + ((user.info.emoji || []) ++ Formatter.get_emoji_map(emojis_text)) + |> Enum.dedup() + info_params = [:no_rich_text, :locked, :hide_followers, :hide_follows, :hide_favorites, :show_role] |> Enum.reduce(%{}, fn key, acc -> @@ -112,6 +119,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do _ -> :error end end) + |> Map.put(:emoji, user_info_emojis) info_cng = User.Info.profile_update(user.info, info_params) diff --git a/lib/pleroma/web/twitter_api/twitter_api_controller.ex b/lib/pleroma/web/twitter_api/twitter_api_controller.ex index 79ed9dad2..ef7b6fe65 100644 --- a/lib/pleroma/web/twitter_api/twitter_api_controller.ex +++ b/lib/pleroma/web/twitter_api/twitter_api_controller.ex @@ -9,6 +9,7 @@ defmodule Pleroma.Web.TwitterAPI.Controller do alias Ecto.Changeset alias Pleroma.Activity + alias Pleroma.Formatter alias Pleroma.Notification alias Pleroma.Object alias Pleroma.Repo @@ -653,7 +654,22 @@ defmodule Pleroma.Web.TwitterAPI.Controller do defp parse_profile_bio(user, params) do if bio = params["description"] do - Map.put(params, "bio", User.parse_bio(bio, user)) + emojis_text = (params["description"] || "") <> " " <> (params["name"] || "") + + emojis = + ((user.info.emoji || []) ++ Formatter.get_emoji_map(emojis_text)) + |> Enum.dedup() + + user_info = + user.info + |> Map.put( + "emoji", + emojis + ) + + params + |> Map.put("bio", User.parse_bio(bio, user)) + |> Map.put("info", user_info) else params end diff --git a/lib/pleroma/web/twitter_api/views/user_view.ex b/lib/pleroma/web/twitter_api/views/user_view.ex index ea015b8f0..f0a4ddbd3 100644 --- a/lib/pleroma/web/twitter_api/views/user_view.ex +++ b/lib/pleroma/web/twitter_api/views/user_view.ex @@ -67,6 +67,13 @@ defmodule Pleroma.Web.TwitterAPI.UserView do {String.trim(name, ":"), url} end) + emoji = Enum.dedup(emoji ++ user.info.emoji) + + description_html = + (user.bio || "") + |> HTML.filter_tags(User.html_filter_policy(for_user)) + |> Formatter.emojify(emoji) + # ``fields`` is an array of mastodon profile field, containing ``{"name": "…", "value": "…"}``. # For example: [{"name": "Pronoun", "value": "she/her"}, …] fields = @@ -78,7 +85,7 @@ defmodule Pleroma.Web.TwitterAPI.UserView do %{ "created_at" => user.inserted_at |> Utils.format_naive_asctime(), "description" => HTML.strip_tags((user.bio || "") |> String.replace("
", "\n")), - "description_html" => HTML.filter_tags(user.bio, User.html_filter_policy(for_user)), + "description_html" => description_html, "favourites_count" => 0, "followers_count" => user_info[:follower_count], "following" => following, diff --git a/test/formatter_test.exs b/test/formatter_test.exs index fdaf29742..06f4f6e50 100644 --- a/test/formatter_test.exs +++ b/test/formatter_test.exs @@ -248,7 +248,7 @@ defmodule Pleroma.FormatterTest do text = "I love :firefox:" expected_result = - "I love \"firefox\"" + "I love \"firefox\"" assert Formatter.emojify(text) == expected_result end @@ -263,7 +263,7 @@ defmodule Pleroma.FormatterTest do } expected_result = - "I love \"\"" + "I love \"\"" assert Formatter.emojify(text, custom_emoji) == expected_result end diff --git a/test/user_test.exs b/test/user_test.exs index 67266cb7a..6d21b56f7 100644 --- a/test/user_test.exs +++ b/test/user_test.exs @@ -1103,7 +1103,7 @@ defmodule Pleroma.UserTest do expected_text = "A.k.a. " <> "@nick@domain.com" + }'>@nick@domain.com" assert expected_text == User.parse_bio(bio, user) end diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs index c2a12d3c7..610aa486e 100644 --- a/test/web/mastodon_api/mastodon_api_controller_test.exs +++ b/test/web/mastodon_api/mastodon_api_controller_test.exs @@ -2351,6 +2351,33 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do end end end + + test "updates profile emojos", %{conn: conn} do + user = insert(:user) + + note = "*sips :blank:*" + name = "I am :firefox:" + + conn = + conn + |> assign(:user, user) + |> patch("/api/v1/accounts/update_credentials", %{ + "note" => note, + "display_name" => name + }) + + assert json_response(conn, 200) + + conn = + conn + |> get("/api/v1/accounts/#{user.id}") + + assert user = json_response(conn, 200) + + assert user["note"] == note + assert user["display_name"] == name + assert [%{"shortcode" => "blank"}, %{"shortcode" => "firefox"}] = user["emojis"] + end end test "get instance information", %{conn: conn} do diff --git a/test/web/twitter_api/twitter_api_controller_test.exs b/test/web/twitter_api/twitter_api_controller_test.exs index 43ad71a16..90718cfb4 100644 --- a/test/web/twitter_api/twitter_api_controller_test.exs +++ b/test/web/twitter_api/twitter_api_controller_test.exs @@ -1611,6 +1611,34 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do assert json_response(conn, 200) == UserView.render("user.json", %{user: user, for: user}) end + + # Broken before the change to class="emoji" and non- in the DB + @tag :skip + test "it formats emojos", %{conn: conn} do + user = insert(:user) + + conn = + conn + |> assign(:user, user) + |> post("/api/account/update_profile.json", %{ + "bio" => "I love our :moominmamma:​" + }) + + assert response = json_response(conn, 200) + + assert %{ + "description" => "I love our :moominmamma:", + "description_html" => + ~s{I love our moominmamma meow" + "\"firefox\" meow" assert result["summary"] == expected assert result["summary_html"] == expected_html diff --git a/test/web/twitter_api/views/user_view_test.exs b/test/web/twitter_api/views/user_view_test.exs index c99dbddeb..74526673c 100644 --- a/test/web/twitter_api/views/user_view_test.exs +++ b/test/web/twitter_api/views/user_view_test.exs @@ -32,7 +32,7 @@ defmodule Pleroma.Web.TwitterAPI.UserViewTest do test "A user with emoji in username" do expected = - "\"karjalanpiirakka\" man" + "\"karjalanpiirakka\" man" user = insert(:user, %{