Adding tag to emoji ets table

changes in apis
This commit is contained in:
Alex S 2019-04-01 17:17:57 +07:00
parent dc39d8d3fb
commit 3601f03147
14 changed files with 165 additions and 25 deletions

View file

@ -54,7 +54,12 @@
cgi: "https://mdii.sakura.ne.jp/mdii-post.cgi", cgi: "https://mdii.sakura.ne.jp/mdii-post.cgi",
files: "https://mdii.sakura.ne.jp" 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, config :pleroma, :uri_schemes,
valid_schemes: [ valid_schemes: [

View file

@ -1,5 +1,5 @@
firefox, /emoji/Firefox.gif firefox, /emoji/Firefox.gif, Gif,Fun
blank, /emoji/blank.png blank, /emoji/blank.png, Fun
f_00b, /emoji/f_00b.png f_00b, /emoji/f_00b.png
f_00b11b, /emoji/f_00b11b.png f_00b11b, /emoji/f_00b11b.png
f_00b33b, /emoji/f_00b33b.png f_00b33b, /emoji/f_00b33b.png
@ -28,4 +28,3 @@ f_33b00b, /emoji/f_33b00b.png
f_33b22b, /emoji/f_33b22b.png f_33b22b, /emoji/f_33b22b.png
f_33h, /emoji/f_33h.png f_33h, /emoji/f_33h.png
f_33t, /emoji/f_33t.png f_33t, /emoji/f_33t.png

View file

@ -10,7 +10,7 @@ Request parameters can be passed via [query strings](https://en.wikipedia.org/wi
* Authentication: not required * Authentication: not required
* Params: none * Params: none
* Response: JSON * 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 APIs `/api/v1/custom_emojis` but in a different format * Note: Same data as Mastodon APIs `/api/v1/custom_emojis` but in a different format
## `/api/pleroma/follow_import` ## `/api/pleroma/follow_import`
@ -27,14 +27,14 @@ Request parameters can be passed via [query strings](https://en.wikipedia.org/wi
* Method: `GET` * Method: `GET`
* Authentication: not required * Authentication: not required
* Params: none * 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"}` * Example response: `{"type": "kocaptcha", "token": "whatever", "url": "https://captcha.kotobank.ch/endpoint"}`
## `/api/pleroma/delete_account` ## `/api/pleroma/delete_account`
### Delete an account ### Delete an account
* Method `POST` * Method `POST`
* Authentication: required * Authentication: required
* Params: * Params:
* `password`: user's password * `password`: user's password
* Response: JSON. Returns `{"status": "success"}` if the deletion was successful, `{"error": "[error message]"}` otherwise * Response: JSON. Returns `{"status": "success"}` if the deletion was successful, `{"error": "[error message]"}` otherwise
* Example response: `{"error": "Invalid password."}` * Example response: `{"error": "Invalid password."}`

View file

@ -11,8 +11,28 @@ image files (in `/priv/static/emoji/custom`): `happy.png` and `sad.png`
content of `config/custom_emoji.txt`: content of `config/custom_emoji.txt`:
``` ```
happy, /emoji/custom/happy.png happy, /emoji/custom/happy.png, Tag1,Tag2
sad, /emoji/custom/sad.png 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. 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
```

View file

@ -8,7 +8,7 @@ defmodule Pleroma.Emoji do
* the built-in Finmojis (if enabled in configuration), * the built-in Finmojis (if enabled in configuration),
* the files: `config/emoji.txt` and `config/custom_emoji.txt` * 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. 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" "woollysocks"
] ]
defp load_finmoji(true) do defp load_finmoji(true) do
tag = Keyword.get(Application.get_env(:pleroma, :emoji), :finmoji_tag)
Enum.map(@finmoji, fn finmoji -> Enum.map(@finmoji, fn finmoji ->
{finmoji, "/finmoji/128px/#{finmoji}-128.png"} {finmoji, "/finmoji/128px/#{finmoji}-128.png", tag}
end) end)
end end
@ -168,31 +170,70 @@ defp load_from_file(file) do
end end
defp load_from_file_stream(stream) do defp load_from_file_stream(stream) do
default_tag =
stream.path
|> Path.basename(".txt")
|> get_default_tag()
stream stream
|> Stream.map(&String.trim/1) |> Stream.map(&String.trim/1)
|> Stream.map(fn line -> |> Stream.map(fn line ->
case String.split(line, ~r/,\s*/) do case String.split(line, ~r/,\s*/) do
[name, file] -> {name, file} [name, file, tags] ->
_ -> nil {name, file, tags}
[name, file] ->
{name, file, default_tag}
_ ->
nil
end end
end) end)
|> Enum.to_list() |> Enum.to_list()
end 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 defp load_from_globs(globs) do
static_path = Path.join(:code.priv_dir(:pleroma), "static") static_path = Path.join(:code.priv_dir(:pleroma), "static")
paths = paths =
Enum.map(globs, fn glob -> Enum.map(globs, fn glob ->
static_part =
Path.dirname(glob)
|> String.replace_trailing("**", "")
Path.join(static_path, glob) Path.join(static_path, glob)
|> Path.wildcard() |> 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) end)
|> Enum.concat() |> 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)) shortcode = Path.basename(path, Path.extname(path))
external_path = Path.join("/", Path.relative_to(path, static_path)) external_path = Path.join("/", Path.relative_to(path, static_path))
{shortcode, external_path} {shortcode, external_path, tag}
end) end)
end end
end end

View file

@ -77,9 +77,9 @@ def emojify(text) do
def emojify(text, nil), do: text def emojify(text, nil), do: text
def emojify(text, emoji, strip \\ false) do def emojify(text, emoji, strip \\ false) do
Enum.reduce(emoji, text, fn {emoji, file}, text -> Enum.reduce(emoji, text, fn emoji_data, text ->
emoji = HTML.strip_tags(emoji) emoji = HTML.strip_tags(elem(emoji_data, 0))
file = HTML.strip_tags(file) file = HTML.strip_tags(elem(emoji_data, 1))
html = html =
if not strip do if not strip do
@ -101,7 +101,7 @@ def demojify(text) do
def demojify(text, nil), do: text def demojify(text, nil), do: text
def get_emoji(text) when is_binary(text) do 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 end
def get_emoji(_), do: [] def get_emoji(_), do: []

View file

@ -167,7 +167,7 @@ def post(user, %{"status" => status} = data) do
object, object,
"emoji", "emoji",
(Formatter.get_emoji(status) ++ Formatter.get_emoji(data["spoiler_text"])) (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}") Map.put(acc, name, "#{Pleroma.Web.Endpoint.static_url()}#{file}")
end) end)
) do ) do

View file

@ -285,7 +285,7 @@ def confirm_current_password(user, password) do
def emoji_from_profile(%{info: _info} = user) do def emoji_from_profile(%{info: _info} = user) do
(Formatter.get_emoji(user.bio) ++ Formatter.get_emoji(user.name)) (Formatter.get_emoji(user.bio) ++ Formatter.get_emoji(user.name))
|> Enum.map(fn {shortcode, url} -> |> Enum.map(fn {shortcode, url, _} ->
%{ %{
"type" => "Emoji", "type" => "Emoji",
"icon" => %{"type" => "Image", "url" => "#{Endpoint.url()}#{url}"}, "icon" => %{"type" => "Image", "url" => "#{Endpoint.url()}#{url}"},

View file

@ -178,14 +178,15 @@ def peers(conn, _params) do
defp mastodonized_emoji do defp mastodonized_emoji do
Pleroma.Emoji.get_all() 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)) url = to_string(URI.merge(Web.base_url(), relative_url))
%{ %{
"shortcode" => shortcode, "shortcode" => shortcode,
"static_url" => url, "static_url" => url,
"visible_in_picker" => true, "visible_in_picker" => true,
"url" => url "url" => url,
"tags" => String.split(tags, ",")
} }
end) end)
end end

View file

@ -266,7 +266,13 @@ def version(conn, _params) do
end end
def emoji(conn, _params) do 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 end
def follow_import(conn, %{"list" => %Plug.Upload{} = listfile}) do def follow_import(conn, %{"list" => %Plug.Upload{} = listfile}) do

30
test/emoji_test.exs Normal file
View file

@ -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

View file

@ -271,7 +271,8 @@ test "it does not add XSS emoji" do
test "it returns the emoji used in the text" do test "it returns the emoji used in the text" do
text = "I love :moominmamma:" 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 end
test "it returns a nice empty result when no emojis are present" do test "it returns a nice empty result when no emojis are present" do

View file

@ -2265,4 +2265,20 @@ test "preserves parameters in link headers", %{conn: conn} do
assert link_header =~ ~r/max_id=#{notification1.id}/ assert link_header =~ ~r/max_id=#{notification1.id}/
end end
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 end

View file

@ -164,4 +164,25 @@ test "returns everything in :pleroma, :frontend_configurations", %{conn: conn} d
assert response == Jason.encode!(config |> Enum.into(%{})) |> Jason.decode!() assert response == Jason.encode!(config |> Enum.into(%{})) |> Jason.decode!()
end end
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 end