From 3601f03147bd104f6acff64e7c8d5d4d3e1f53a2 Mon Sep 17 00:00:00 2001 From: Alex S Date: Mon, 1 Apr 2019 17:17:57 +0700 Subject: [PATCH 1/9] Adding tag to emoji ets table changes in apis --- config/config.exs | 7 ++- config/emoji.txt | 5 +- docs/api/pleroma_api.md | 6 +-- docs/config/custom_emoji.md | 24 ++++++++- lib/pleroma/emoji.ex | 53 ++++++++++++++++--- lib/pleroma/formatter.ex | 8 +-- lib/pleroma/web/common_api/common_api.ex | 2 +- lib/pleroma/web/common_api/utils.ex | 2 +- .../mastodon_api/mastodon_api_controller.ex | 5 +- .../controllers/util_controller.ex | 8 ++- test/emoji_test.exs | 30 +++++++++++ test/formatter_test.exs | 3 +- .../mastodon_api_controller_test.exs | 16 ++++++ test/web/twitter_api/util_controller_test.exs | 21 ++++++++ 14 files changed, 165 insertions(+), 25 deletions(-) create mode 100644 test/emoji_test.exs diff --git a/config/config.exs b/config/config.exs index 0df38d75a..245c7d268 100644 --- a/config/config.exs +++ b/config/config.exs @@ -54,7 +54,12 @@ cgi: "https://mdii.sakura.ne.jp/mdii-post.cgi", files: "https://mdii.sakura.ne.jp" -config :pleroma, :emoji, shortcode_globs: ["/emoji/custom/**/*.png"] +config :pleroma, :emoji, + shortcode_globs: ["/emoji/custom/**/*.png"], + custom_tag: "Custom", + finmoji_tag: "Finmoji", + emoji_tag: "Emoji", + custom_emoji_tag: "Custom" config :pleroma, :uri_schemes, valid_schemes: [ diff --git a/config/emoji.txt b/config/emoji.txt index 7afacb09f..79246f239 100644 --- a/config/emoji.txt +++ b/config/emoji.txt @@ -1,5 +1,5 @@ -firefox, /emoji/Firefox.gif -blank, /emoji/blank.png +firefox, /emoji/Firefox.gif, Gif,Fun +blank, /emoji/blank.png, Fun f_00b, /emoji/f_00b.png f_00b11b, /emoji/f_00b11b.png f_00b33b, /emoji/f_00b33b.png @@ -28,4 +28,3 @@ f_33b00b, /emoji/f_33b00b.png f_33b22b, /emoji/f_33b22b.png f_33h, /emoji/f_33h.png f_33t, /emoji/f_33t.png - diff --git a/docs/api/pleroma_api.md b/docs/api/pleroma_api.md index 478c9d874..2e8fb04d2 100644 --- a/docs/api/pleroma_api.md +++ b/docs/api/pleroma_api.md @@ -10,7 +10,7 @@ Request parameters can be passed via [query strings](https://en.wikipedia.org/wi * Authentication: not required * Params: none * Response: JSON -* Example response: `{"kalsarikannit_f":"/finmoji/128px/kalsarikannit_f-128.png","perkele":"/finmoji/128px/perkele-128.png","blobdab":"/emoji/blobdab.png","happiness":"/finmoji/128px/happiness-128.png"}` +* Example response: `[{"kalsarikannit_f":{"tags":["Finmoji"],"image_url":"/finmoji/128px/kalsarikannit_f-128.png"}},{"perkele":{"tags":["Finmoji"],"image_url":"/finmoji/128px/perkele-128.png"}},{"blobdab":{"tags":["SomeTag"],"image_url":"/emoji/blobdab.png"}},"happiness":{"tags":["Finmoji"],"image_url":"/finmoji/128px/happiness-128.png"}}]` * Note: Same data as Mastodon API’s `/api/v1/custom_emojis` but in a different format ## `/api/pleroma/follow_import` @@ -27,14 +27,14 @@ Request parameters can be passed via [query strings](https://en.wikipedia.org/wi * Method: `GET` * Authentication: not required * Params: none -* Response: Provider specific JSON, the only guaranteed parameter is `type` +* Response: Provider specific JSON, the only guaranteed parameter is `type` * Example response: `{"type": "kocaptcha", "token": "whatever", "url": "https://captcha.kotobank.ch/endpoint"}` ## `/api/pleroma/delete_account` ### Delete an account * Method `POST` * Authentication: required -* Params: +* Params: * `password`: user's password * Response: JSON. Returns `{"status": "success"}` if the deletion was successful, `{"error": "[error message]"}` otherwise * Example response: `{"error": "Invalid password."}` diff --git a/docs/config/custom_emoji.md b/docs/config/custom_emoji.md index e833d2080..e47a75c8e 100644 --- a/docs/config/custom_emoji.md +++ b/docs/config/custom_emoji.md @@ -11,8 +11,28 @@ image files (in `/priv/static/emoji/custom`): `happy.png` and `sad.png` content of `config/custom_emoji.txt`: ``` -happy, /emoji/custom/happy.png -sad, /emoji/custom/sad.png +happy, /emoji/custom/happy.png, Tag1,Tag2 +sad, /emoji/custom/sad.png, Tag1 +foo, /emoji/custom/foo.png ``` The files should be PNG (APNG is okay with `.png` for `image/png` Content-type) and under 50kb for compatibility with mastodon. + +# Emoji tags + +Changing default tags: + +* For `Finmoji`, `emoji.txt` and `custom_emoji.txt` are added default tags, which can be configured in the `config.exs`: +* For emoji loaded from globs: + - `priv/static/emoji/custom/*.png` - `custom_tag`, can be configured in `config.exs` + - `priv/static/emoji/custom/TagName/*.png` - folder (`TagName`) is used as tag + + +``` +config :pleroma, :emoji, + shortcode_globs: ["/emoji/custom/**/*.png"], + custom_tag: "Custom", # Default tag for emoji in `priv/static/emoji/custom` path + finmoji_tag: "Finmoji", # Default tag for Finmoji + emoji_tag: "Emoji", # Default tag for emoji.txt + custom_emoji_tag: "Custom" # Default tag for custom_emoji.txt +``` diff --git a/lib/pleroma/emoji.ex b/lib/pleroma/emoji.ex index f3f08cd9d..c35aed6ee 100644 --- a/lib/pleroma/emoji.ex +++ b/lib/pleroma/emoji.ex @@ -8,7 +8,7 @@ defmodule Pleroma.Emoji do * the built-in Finmojis (if enabled in configuration), * the files: `config/emoji.txt` and `config/custom_emoji.txt` - * glob paths + * glob paths, nested folder is used as tag name for grouping e.g. priv/static/emoji/custom/nested_folder This GenServer stores in an ETS table the list of the loaded emojis, and also allows to reload the list at runtime. """ @@ -152,8 +152,10 @@ defp load do "woollysocks" ] defp load_finmoji(true) do + tag = Keyword.get(Application.get_env(:pleroma, :emoji), :finmoji_tag) + Enum.map(@finmoji, fn finmoji -> - {finmoji, "/finmoji/128px/#{finmoji}-128.png"} + {finmoji, "/finmoji/128px/#{finmoji}-128.png", tag} end) end @@ -168,31 +170,70 @@ defp load_from_file(file) do end defp load_from_file_stream(stream) do + default_tag = + stream.path + |> Path.basename(".txt") + |> get_default_tag() + stream |> Stream.map(&String.trim/1) |> Stream.map(fn line -> case String.split(line, ~r/,\s*/) do - [name, file] -> {name, file} - _ -> nil + [name, file, tags] -> + {name, file, tags} + + [name, file] -> + {name, file, default_tag} + + _ -> + nil end end) |> Enum.to_list() end + @spec get_default_tag(String.t()) :: String.t() + defp get_default_tag(file_name) when file_name in ["emoji", "custom_emojii"] do + Keyword.get( + Application.get_env(:pleroma, :emoji), + String.to_existing_atom(file_name <> "_tag") + ) + end + + defp get_default_tag(_), do: Keyword.get(Application.get_env(:pleroma, :emoji), :custom_tag) + defp load_from_globs(globs) do static_path = Path.join(:code.priv_dir(:pleroma), "static") paths = Enum.map(globs, fn glob -> + static_part = + Path.dirname(glob) + |> String.replace_trailing("**", "") + Path.join(static_path, glob) |> Path.wildcard() + |> Enum.map(fn path -> + custom_folder = + path + |> Path.relative_to(Path.join(static_path, static_part)) + |> Path.dirname() + + [path, custom_folder] + end) end) |> Enum.concat() - Enum.map(paths, fn path -> + Enum.map(paths, fn [path, custom_folder] -> + tag = + case custom_folder do + "." -> Keyword.get(Application.get_env(:pleroma, :emoji), :custom_tag) + tag -> tag + end + shortcode = Path.basename(path, Path.extname(path)) external_path = Path.join("/", Path.relative_to(path, static_path)) - {shortcode, external_path} + {shortcode, external_path, tag} end) end end diff --git a/lib/pleroma/formatter.ex b/lib/pleroma/formatter.ex index e3625383b..8ea9dbd38 100644 --- a/lib/pleroma/formatter.ex +++ b/lib/pleroma/formatter.ex @@ -77,9 +77,9 @@ def emojify(text) do def emojify(text, nil), do: text def emojify(text, emoji, strip \\ false) do - Enum.reduce(emoji, text, fn {emoji, file}, text -> - emoji = HTML.strip_tags(emoji) - file = HTML.strip_tags(file) + Enum.reduce(emoji, text, fn emoji_data, text -> + emoji = HTML.strip_tags(elem(emoji_data, 0)) + file = HTML.strip_tags(elem(emoji_data, 1)) html = if not strip do @@ -101,7 +101,7 @@ def demojify(text) do def demojify(text, nil), do: text def get_emoji(text) when is_binary(text) do - Enum.filter(Emoji.get_all(), fn {emoji, _} -> String.contains?(text, ":#{emoji}:") end) + Enum.filter(Emoji.get_all(), fn {emoji, _, _} -> String.contains?(text, ":#{emoji}:") end) end def get_emoji(_), do: [] diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex index 25b990677..f910eb1f9 100644 --- a/lib/pleroma/web/common_api/common_api.ex +++ b/lib/pleroma/web/common_api/common_api.ex @@ -167,7 +167,7 @@ def post(user, %{"status" => status} = data) do object, "emoji", (Formatter.get_emoji(status) ++ Formatter.get_emoji(data["spoiler_text"])) - |> Enum.reduce(%{}, fn {name, file}, acc -> + |> Enum.reduce(%{}, fn {name, file, _}, acc -> Map.put(acc, name, "#{Pleroma.Web.Endpoint.static_url()}#{file}") end) ) do diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex index f596f703b..49f0170cc 100644 --- a/lib/pleroma/web/common_api/utils.ex +++ b/lib/pleroma/web/common_api/utils.ex @@ -285,7 +285,7 @@ def confirm_current_password(user, password) do def emoji_from_profile(%{info: _info} = user) do (Formatter.get_emoji(user.bio) ++ Formatter.get_emoji(user.name)) - |> Enum.map(fn {shortcode, url} -> + |> Enum.map(fn {shortcode, url, _} -> %{ "type" => "Emoji", "icon" => %{"type" => "Image", "url" => "#{Endpoint.url()}#{url}"}, diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index eee4e7678..583e4007c 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -178,14 +178,15 @@ def peers(conn, _params) do defp mastodonized_emoji do Pleroma.Emoji.get_all() - |> Enum.map(fn {shortcode, relative_url} -> + |> Enum.map(fn {shortcode, relative_url, tags} -> url = to_string(URI.merge(Web.base_url(), relative_url)) %{ "shortcode" => shortcode, "static_url" => url, "visible_in_picker" => true, - "url" => url + "url" => url, + "tags" => String.split(tags, ",") } end) end diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex index faa733fec..e58d9e4cd 100644 --- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex +++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex @@ -266,7 +266,13 @@ def version(conn, _params) do end def emoji(conn, _params) do - json(conn, Enum.into(Emoji.get_all(), %{})) + emoji = + Emoji.get_all() + |> Enum.map(fn {short_code, path, tags} -> + %{short_code => %{image_url: path, tags: String.split(tags, ",")}} + end) + + json(conn, emoji) end def follow_import(conn, %{"list" => %Plug.Upload{} = listfile}) do diff --git a/test/emoji_test.exs b/test/emoji_test.exs new file mode 100644 index 000000000..c9c32e20b --- /dev/null +++ b/test/emoji_test.exs @@ -0,0 +1,30 @@ +defmodule Pleroma.EmojiTest do + use ExUnit.Case, async: true + alias Pleroma.Emoji + + describe "get_all/0" do + setup do + emoji_list = Emoji.get_all() + {:ok, emoji_list: emoji_list} + end + test "first emoji", %{emoji_list: emoji_list} do + [emoji | _others] = emoji_list + {code, path, tags} = emoji + + assert tuple_size(emoji) == 3 + assert is_binary(code) + assert is_binary(path) + assert is_binary(tags) + end + + test "random emoji", %{emoji_list: emoji_list} do + emoji = Enum.random(emoji_list) + {code, path, tags} = emoji + + assert tuple_size(emoji) == 3 + assert is_binary(code) + assert is_binary(path) + assert is_binary(tags) + end + end +end diff --git a/test/formatter_test.exs b/test/formatter_test.exs index fcdf931b7..e67042a5f 100644 --- a/test/formatter_test.exs +++ b/test/formatter_test.exs @@ -271,7 +271,8 @@ test "it does not add XSS emoji" do test "it returns the emoji used in the text" do text = "I love :moominmamma:" - assert Formatter.get_emoji(text) == [{"moominmamma", "/finmoji/128px/moominmamma-128.png"}] + tag = Keyword.get(Application.get_env(:pleroma, :emoji), :finmoji_tag) + assert Formatter.get_emoji(text) == [{"moominmamma", "/finmoji/128px/moominmamma-128.png", tag}] end test "it returns a nice empty result when no emojis are present" do diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs index d9bcbf5a9..3b10c4a1a 100644 --- a/test/web/mastodon_api/mastodon_api_controller_test.exs +++ b/test/web/mastodon_api/mastodon_api_controller_test.exs @@ -2265,4 +2265,20 @@ test "preserves parameters in link headers", %{conn: conn} do assert link_header =~ ~r/max_id=#{notification1.id}/ end end + + describe "custom emoji" do + test "with tags", %{conn: conn} do + [emoji | _body] = + conn + |> get("/api/v1/custom_emojis") + |> json_response(200) + + assert Map.has_key?(emoji, "shortcode") + assert Map.has_key?(emoji, "static_url") + assert Map.has_key?(emoji, "tags") + assert is_list(emoji["tags"]) + assert Map.has_key?(emoji, "url") + assert Map.has_key?(emoji, "visible_in_picker") + end + end end diff --git a/test/web/twitter_api/util_controller_test.exs b/test/web/twitter_api/util_controller_test.exs index 832fdc096..1063ad28f 100644 --- a/test/web/twitter_api/util_controller_test.exs +++ b/test/web/twitter_api/util_controller_test.exs @@ -164,4 +164,25 @@ test "returns everything in :pleroma, :frontend_configurations", %{conn: conn} d assert response == Jason.encode!(config |> Enum.into(%{})) |> Jason.decode!() end end + + describe "/api/pleroma/emoji" do + test "returns json with custom emoji with tags", %{conn: conn} do + [emoji | _body] = + conn + |> get("/api/pleroma/emoji") + |> json_response(200) + + [key] = Map.keys(emoji) + + %{ + ^key => %{ + "image_url" => url, + "tags" => tags + } + } = emoji + + assert is_binary(url) + assert is_list(tags) + end + end end From 17d3d05a7196140b62dd791af8d7ced8b0ad9fa1 Mon Sep 17 00:00:00 2001 From: Alex S Date: Mon, 1 Apr 2019 17:54:30 +0700 Subject: [PATCH 2/9] code style little fix --- lib/pleroma/emoji.ex | 6 +++--- test/emoji_test.exs | 3 ++- test/formatter_test.exs | 5 ++++- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/lib/pleroma/emoji.ex b/lib/pleroma/emoji.ex index c35aed6ee..ad3170f9a 100644 --- a/lib/pleroma/emoji.ex +++ b/lib/pleroma/emoji.ex @@ -152,7 +152,7 @@ defp load do "woollysocks" ] defp load_finmoji(true) do - tag = Keyword.get(Application.get_env(:pleroma, :emoji), :finmoji_tag) + tag = Application.get_env(:pleroma, :emoji)[:finmoji_tag] Enum.map(@finmoji, fn finmoji -> {finmoji, "/finmoji/128px/#{finmoji}-128.png", tag} @@ -193,14 +193,14 @@ defp load_from_file_stream(stream) do end @spec get_default_tag(String.t()) :: String.t() - defp get_default_tag(file_name) when file_name in ["emoji", "custom_emojii"] do + defp get_default_tag(file_name) when file_name in ["emoji", "custom_emoji"] do Keyword.get( Application.get_env(:pleroma, :emoji), String.to_existing_atom(file_name <> "_tag") ) end - defp get_default_tag(_), do: Keyword.get(Application.get_env(:pleroma, :emoji), :custom_tag) + defp get_default_tag(_), do: Application.get_env(:pleroma, :emoji)[:custom_tag] defp load_from_globs(globs) do static_path = Path.join(:code.priv_dir(:pleroma), "static") diff --git a/test/emoji_test.exs b/test/emoji_test.exs index c9c32e20b..a90213d7d 100644 --- a/test/emoji_test.exs +++ b/test/emoji_test.exs @@ -7,6 +7,7 @@ defmodule Pleroma.EmojiTest do emoji_list = Emoji.get_all() {:ok, emoji_list: emoji_list} end + test "first emoji", %{emoji_list: emoji_list} do [emoji | _others] = emoji_list {code, path, tags} = emoji @@ -19,7 +20,7 @@ test "first emoji", %{emoji_list: emoji_list} do test "random emoji", %{emoji_list: emoji_list} do emoji = Enum.random(emoji_list) - {code, path, tags} = emoji + {code, path, tags} = emoji assert tuple_size(emoji) == 3 assert is_binary(code) diff --git a/test/formatter_test.exs b/test/formatter_test.exs index e67042a5f..38430e170 100644 --- a/test/formatter_test.exs +++ b/test/formatter_test.exs @@ -272,7 +272,10 @@ test "it returns the emoji used in the text" do text = "I love :moominmamma:" tag = Keyword.get(Application.get_env(:pleroma, :emoji), :finmoji_tag) - assert Formatter.get_emoji(text) == [{"moominmamma", "/finmoji/128px/moominmamma-128.png", tag}] + + assert Formatter.get_emoji(text) == [ + {"moominmamma", "/finmoji/128px/moominmamma-128.png", tag} + ] end test "it returns a nice empty result when no emojis are present" do From 49733f61763091514faa49493fdc20b795c08c1c Mon Sep 17 00:00:00 2001 From: Alex S Date: Mon, 1 Apr 2019 18:28:19 +0700 Subject: [PATCH 3/9] add docs folder to gitignore ref #770 --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 04c61ede7..774893b35 100644 --- a/.gitignore +++ b/.gitignore @@ -35,3 +35,6 @@ erl_crash.dump # Editor config /.vscode/ + +# Prevent committing docs files +/priv/static/doc/* From 9b2188da7cab43a162d441294db7d3155e2eeab3 Mon Sep 17 00:00:00 2001 From: Alex S Date: Tue, 2 Apr 2019 15:44:56 +0700 Subject: [PATCH 4/9] refactoring of emoji tags config to use groups --- config/config.exs | 9 +++-- lib/pleroma/emoji.ex | 92 +++++++++++++++++++++++--------------------- test/emoji_test.exs | 75 ++++++++++++++++++++++++++++++++++++ 3 files changed, 129 insertions(+), 47 deletions(-) diff --git a/config/config.exs b/config/config.exs index 245c7d268..4a22167b2 100644 --- a/config/config.exs +++ b/config/config.exs @@ -56,10 +56,11 @@ config :pleroma, :emoji, shortcode_globs: ["/emoji/custom/**/*.png"], - custom_tag: "Custom", - finmoji_tag: "Finmoji", - emoji_tag: "Emoji", - custom_emoji_tag: "Custom" + groups: [ + # Place here groups, which have more priority on defaults. Example in `docs/config/custom_emoji.md` + Finmoji: "/finmoji/128px/*-128.png", + Custom: ["/emoji/*.png", "/emoji/custom/*.png"] + ] config :pleroma, :uri_schemes, valid_schemes: [ diff --git a/lib/pleroma/emoji.ex b/lib/pleroma/emoji.ex index ad3170f9a..b60d19e89 100644 --- a/lib/pleroma/emoji.ex +++ b/lib/pleroma/emoji.ex @@ -13,8 +13,14 @@ defmodule Pleroma.Emoji do This GenServer stores in an ETS table the list of the loaded emojis, and also allows to reload the list at runtime. """ use GenServer + + @type pattern :: Regex.t() | module() | String.t() + @type patterns :: pattern | [pattern] + @type group_patterns :: keyword(patterns) + @ets __MODULE__.Ets @ets_options [:ordered_set, :protected, :named_table, {:read_concurrency, true}] + @groups Application.get_env(:pleroma, :emoji)[:groups] @doc false def start_link do @@ -73,13 +79,14 @@ def code_change(_old_vsn, state, _extra) do end defp load do + finmoji_enabled = Keyword.get(Application.get_env(:pleroma, :instance), :finmoji_enabled) + shortcode_globs = Keyword.get(Application.get_env(:pleroma, :emoji, []), :shortcode_globs, []) + emojis = - (load_finmoji(Keyword.get(Application.get_env(:pleroma, :instance), :finmoji_enabled)) ++ + (load_finmoji(finmoji_enabled) ++ load_from_file("config/emoji.txt") ++ load_from_file("config/custom_emoji.txt") ++ - load_from_globs( - Keyword.get(Application.get_env(:pleroma, :emoji, []), :shortcode_globs, []) - )) + load_from_globs(shortcode_globs)) |> Enum.reject(fn value -> value == nil end) true = :ets.insert(@ets, emojis) @@ -151,11 +158,12 @@ defp load do "white_nights", "woollysocks" ] - defp load_finmoji(true) do - tag = Application.get_env(:pleroma, :emoji)[:finmoji_tag] + defp load_finmoji(true) do Enum.map(@finmoji, fn finmoji -> - {finmoji, "/finmoji/128px/#{finmoji}-128.png", tag} + file_name = "/finmoji/128px/#{finmoji}-128.png" + group = match_extra(@groups, file_name) + {finmoji, file_name, to_string(group)} end) end @@ -170,11 +178,6 @@ defp load_from_file(file) do end defp load_from_file_stream(stream) do - default_tag = - stream.path - |> Path.basename(".txt") - |> get_default_tag() - stream |> Stream.map(&String.trim/1) |> Stream.map(fn line -> @@ -183,7 +186,7 @@ defp load_from_file_stream(stream) do {name, file, tags} [name, file] -> - {name, file, default_tag} + {name, file, to_string(match_extra(@groups, file))} _ -> nil @@ -192,48 +195,51 @@ defp load_from_file_stream(stream) do |> Enum.to_list() end - @spec get_default_tag(String.t()) :: String.t() - defp get_default_tag(file_name) when file_name in ["emoji", "custom_emoji"] do - Keyword.get( - Application.get_env(:pleroma, :emoji), - String.to_existing_atom(file_name <> "_tag") - ) - end - - defp get_default_tag(_), do: Application.get_env(:pleroma, :emoji)[:custom_tag] - defp load_from_globs(globs) do static_path = Path.join(:code.priv_dir(:pleroma), "static") paths = Enum.map(globs, fn glob -> - static_part = - Path.dirname(glob) - |> String.replace_trailing("**", "") - Path.join(static_path, glob) |> Path.wildcard() - |> Enum.map(fn path -> - custom_folder = - path - |> Path.relative_to(Path.join(static_path, static_part)) - |> Path.dirname() - - [path, custom_folder] - end) end) |> Enum.concat() - Enum.map(paths, fn [path, custom_folder] -> - tag = - case custom_folder do - "." -> Keyword.get(Application.get_env(:pleroma, :emoji), :custom_tag) - tag -> tag - end - + Enum.map(paths, fn path -> + tag = match_extra(@groups, Path.join("/", Path.relative_to(path, static_path))) shortcode = Path.basename(path, Path.extname(path)) external_path = Path.join("/", Path.relative_to(path, static_path)) - {shortcode, external_path, tag} + {shortcode, external_path, to_string(tag)} + end) + end + + @doc """ + Finds a matching group for the given extra filename + """ + @spec match_extra(group_patterns(), String.t()) :: atom() | nil + def match_extra(group_patterns, filename) do + match_group_patterns(group_patterns, fn pattern -> + case pattern do + %Regex{} = regex -> Regex.match?(regex, filename) + string when is_binary(string) -> filename == string + end + end) + end + + defp match_group_patterns(group_patterns, matcher) do + Enum.find_value(group_patterns, fn {group, patterns} -> + patterns = + patterns + |> List.wrap() + |> Enum.map(fn pattern -> + if String.contains?(pattern, "*") do + ~r(#{String.replace(pattern, "*", ".*")}) + else + pattern + end + end) + + Enum.any?(patterns, matcher) && group end) end end diff --git a/test/emoji_test.exs b/test/emoji_test.exs index a90213d7d..cb1d62d00 100644 --- a/test/emoji_test.exs +++ b/test/emoji_test.exs @@ -28,4 +28,79 @@ test "random emoji", %{emoji_list: emoji_list} do assert is_binary(tags) end end + + describe "match_extra/2" do + setup do + groups = [ + "list of files": ["/emoji/custom/first_file.png", "/emoji/custom/second_file.png"], + "wildcard folder": "/emoji/custom/*/file.png", + "wildcard files": "/emoji/custom/folder/*.png", + "special file": "/emoji/custom/special.png" + ] + + {:ok, groups: groups} + end + + test "config for list of files", %{groups: groups} do + group = + groups + |> Emoji.match_extra("/emoji/custom/first_file.png") + |> to_string() + + assert group == "list of files" + end + + test "config with wildcard folder", %{groups: groups} do + group = + groups + |> Emoji.match_extra("/emoji/custom/some_folder/file.png") + |> to_string() + + assert group == "wildcard folder" + end + + test "config with wildcard folder and subfolders", %{groups: groups} do + group = + groups + |> Emoji.match_extra("/emoji/custom/some_folder/another_folder/file.png") + |> to_string() + + assert group == "wildcard folder" + end + + test "config with wildcard files", %{groups: groups} do + group = + groups + |> Emoji.match_extra("/emoji/custom/folder/some_file.png") + |> to_string() + + assert group == "wildcard files" + end + + test "config with wildcard files and subfolders", %{groups: groups} do + group = + groups + |> Emoji.match_extra("/emoji/custom/folder/another_folder/some_file.png") + |> to_string() + + assert group == "wildcard files" + end + + test "config for special file", %{groups: groups} do + group = + groups + |> Emoji.match_extra("/emoji/custom/special.png") + |> to_string() + + assert group == "special file" + end + + test "no mathing returns nil", %{groups: groups} do + group = + groups + |> Emoji.match_extra("/emoji/some_undefined.png") + + refute group + end + end end From 851c5bf0936fbc58bf509f79531e6cdc070efde5 Mon Sep 17 00:00:00 2001 From: Alex S Date: Tue, 2 Apr 2019 15:57:57 +0700 Subject: [PATCH 5/9] updating custom_emoji docs --- docs/config/custom_emoji.md | 41 +++++++++++++++++++++++++------------ 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/docs/config/custom_emoji.md b/docs/config/custom_emoji.md index e47a75c8e..d37220a72 100644 --- a/docs/config/custom_emoji.md +++ b/docs/config/custom_emoji.md @@ -18,21 +18,36 @@ foo, /emoji/custom/foo.png The files should be PNG (APNG is okay with `.png` for `image/png` Content-type) and under 50kb for compatibility with mastodon. -# Emoji tags - -Changing default tags: - -* For `Finmoji`, `emoji.txt` and `custom_emoji.txt` are added default tags, which can be configured in the `config.exs`: -* For emoji loaded from globs: - - `priv/static/emoji/custom/*.png` - `custom_tag`, can be configured in `config.exs` - - `priv/static/emoji/custom/TagName/*.png` - folder (`TagName`) is used as tag - +# Emoji tags (groups) +Default tags are set in `config.exs`. ``` config :pleroma, :emoji, shortcode_globs: ["/emoji/custom/**/*.png"], - custom_tag: "Custom", # Default tag for emoji in `priv/static/emoji/custom` path - finmoji_tag: "Finmoji", # Default tag for Finmoji - emoji_tag: "Emoji", # Default tag for emoji.txt - custom_emoji_tag: "Custom" # Default tag for custom_emoji.txt + groups: [ + Finmoji: "/finmoji/128px/*-128.png", + Custom: ["/emoji/*.png", "/emoji/custom/*.png"] + ] ``` + +Order of the `groups` matters, so to override default tags just put your group on the top of the list. E.g: +``` +config :pleroma, :emoji, + shortcode_globs: ["/emoji/custom/**/*.png"], + groups: [ + "Finmoji special": "/finmoji/128px/a_trusted_friend-128.png", # special file + "Cirno": "/emoji/custom/cirno*.png", # png files in /emoji/custom/ which start with `cirno` + "Special group": "/emoji/custom/special_folder/*.png", # png files in /emoji/custom/special_folder/ + "Another group": "/emoji/custom/special_folder/*/.png", # png files in /emoji/custom/special_folder/ subfolders + Finmoji: "/finmoji/128px/*-128.png", + Custom: ["/emoji/*.png", "/emoji/custom/*.png"] + ] +``` + +Priority of tag assign in emoji.txt and custom.txt: + +`tag in file > special group setting in config.exs > default setting in config.exs` + +Priority for globs: + +`special group setting in config.exs > default setting in config.exs` From 08d64b977f74abb7cb42bf985116eba91d9a6166 Mon Sep 17 00:00:00 2001 From: Alex S Date: Tue, 2 Apr 2019 16:13:34 +0700 Subject: [PATCH 6/9] little changes and typos --- config/config.exs | 2 +- docs/config/custom_emoji.md | 4 ++-- lib/pleroma/emoji.ex | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/config/config.exs b/config/config.exs index 4a22167b2..139ec0ace 100644 --- a/config/config.exs +++ b/config/config.exs @@ -57,7 +57,7 @@ config :pleroma, :emoji, shortcode_globs: ["/emoji/custom/**/*.png"], groups: [ - # Place here groups, which have more priority on defaults. Example in `docs/config/custom_emoji.md` + # Put groups that have higher priority than defaults here. Example in `docs/config/custom_emoji.md` Finmoji: "/finmoji/128px/*-128.png", Custom: ["/emoji/*.png", "/emoji/custom/*.png"] ] diff --git a/docs/config/custom_emoji.md b/docs/config/custom_emoji.md index d37220a72..49a451fcc 100644 --- a/docs/config/custom_emoji.md +++ b/docs/config/custom_emoji.md @@ -30,7 +30,7 @@ config :pleroma, :emoji, ] ``` -Order of the `groups` matters, so to override default tags just put your group on the top of the list. E.g: +Order of the `groups` matters, so to override default tags just put your group on top of the list. E.g: ``` config :pleroma, :emoji, shortcode_globs: ["/emoji/custom/**/*.png"], @@ -44,7 +44,7 @@ config :pleroma, :emoji, ] ``` -Priority of tag assign in emoji.txt and custom.txt: +Priority of tags assigns in emoji.txt and custom.txt: `tag in file > special group setting in config.exs > default setting in config.exs` diff --git a/lib/pleroma/emoji.ex b/lib/pleroma/emoji.ex index b60d19e89..7a60f3961 100644 --- a/lib/pleroma/emoji.ex +++ b/lib/pleroma/emoji.ex @@ -15,8 +15,8 @@ defmodule Pleroma.Emoji do use GenServer @type pattern :: Regex.t() | module() | String.t() - @type patterns :: pattern | [pattern] - @type group_patterns :: keyword(patterns) + @type patterns :: pattern() | [pattern()] + @type group_patterns :: keyword(patterns()) @ets __MODULE__.Ets @ets_options [:ordered_set, :protected, :named_table, {:read_concurrency, true}] @@ -80,7 +80,7 @@ def code_change(_old_vsn, state, _extra) do defp load do finmoji_enabled = Keyword.get(Application.get_env(:pleroma, :instance), :finmoji_enabled) - shortcode_globs = Keyword.get(Application.get_env(:pleroma, :emoji, []), :shortcode_globs, []) + shortcode_globs = Application.get_env(:pleroma, :emoji)[:shortcode_globs] || [] emojis = (load_finmoji(finmoji_enabled) ++ From 484162c18774ff28842a517ae0afcaaf824e12bf Mon Sep 17 00:00:00 2001 From: Alex S Date: Tue, 2 Apr 2019 16:26:40 +0700 Subject: [PATCH 7/9] test fix --- test/formatter_test.exs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/test/formatter_test.exs b/test/formatter_test.exs index 38430e170..e74985c4e 100644 --- a/test/formatter_test.exs +++ b/test/formatter_test.exs @@ -271,10 +271,8 @@ test "it does not add XSS emoji" do test "it returns the emoji used in the text" do text = "I love :moominmamma:" - tag = Keyword.get(Application.get_env(:pleroma, :emoji), :finmoji_tag) - assert Formatter.get_emoji(text) == [ - {"moominmamma", "/finmoji/128px/moominmamma-128.png", tag} + {"moominmamma", "/finmoji/128px/moominmamma-128.png", "Finmoji"} ] end From 3465b7ba9ad0e26128f18fd4e36aece767ba269e Mon Sep 17 00:00:00 2001 From: Alex S Date: Tue, 2 Apr 2019 20:32:37 +0700 Subject: [PATCH 8/9] syntax highlighting --- docs/config/custom_emoji.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/config/custom_emoji.md b/docs/config/custom_emoji.md index 49a451fcc..96fcb2fc6 100644 --- a/docs/config/custom_emoji.md +++ b/docs/config/custom_emoji.md @@ -21,7 +21,7 @@ The files should be PNG (APNG is okay with `.png` for `image/png` Content-type) # Emoji tags (groups) Default tags are set in `config.exs`. -``` +```elixir config :pleroma, :emoji, shortcode_globs: ["/emoji/custom/**/*.png"], groups: [ @@ -31,7 +31,7 @@ config :pleroma, :emoji, ``` Order of the `groups` matters, so to override default tags just put your group on top of the list. E.g: -``` +```elixir config :pleroma, :emoji, shortcode_globs: ["/emoji/custom/**/*.png"], groups: [ From d140738edf75467420b35c500716cf89de66548d Mon Sep 17 00:00:00 2001 From: Alex S Date: Tue, 2 Apr 2019 20:35:41 +0700 Subject: [PATCH 9/9] second level of headertext change in doc --- docs/config/custom_emoji.md | 2 +- lib/pleroma/emoji.ex | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/config/custom_emoji.md b/docs/config/custom_emoji.md index 96fcb2fc6..419a7d0e2 100644 --- a/docs/config/custom_emoji.md +++ b/docs/config/custom_emoji.md @@ -18,7 +18,7 @@ foo, /emoji/custom/foo.png The files should be PNG (APNG is okay with `.png` for `image/png` Content-type) and under 50kb for compatibility with mastodon. -# Emoji tags (groups) +## Emoji tags (groups) Default tags are set in `config.exs`. ```elixir diff --git a/lib/pleroma/emoji.ex b/lib/pleroma/emoji.ex index 7a60f3961..87c7f2cec 100644 --- a/lib/pleroma/emoji.ex +++ b/lib/pleroma/emoji.ex @@ -214,7 +214,7 @@ defp load_from_globs(globs) do end @doc """ - Finds a matching group for the given extra filename + Finds a matching group for the given emoji filename """ @spec match_extra(group_patterns(), String.t()) :: atom() | nil def match_extra(group_patterns, filename) do