Add OpenAPI spec for EmojiPackController See merge request pleroma/pleroma!2549chore/expose-invalidation-to-adminfe
@@ -426,7 +426,7 @@ The status posting endpoint takes an additional parameter, `in_reply_to_conversa | |||||
* Authentication: required | * Authentication: required | ||||
* Params: | * Params: | ||||
* `file`: file needs to be uploaded with the multipart request or link to remote file. | * `file`: file needs to be uploaded with the multipart request or link to remote file. | ||||
* `shortcode`: (*optional*) shortcode for new emoji, must be uniq for all emoji. If not sended, shortcode will be taken from original filename. | |||||
* `shortcode`: (*optional*) shortcode for new emoji, must be unique for all emoji. If not sended, shortcode will be taken from original filename. | |||||
* `filename`: (*optional*) new emoji file name. If not specified will be taken from original filename. | * `filename`: (*optional*) new emoji file name. If not specified will be taken from original filename. | ||||
* Response: JSON, list of files for updated pack (hashmap -> shortcode => filename) with status 200, either error status with error message. | * Response: JSON, list of files for updated pack (hashmap -> shortcode => filename) with status 200, either error status with error message. | ||||
@@ -16,162 +16,78 @@ defmodule Pleroma.Emoji.Pack do | |||||
alias Pleroma.Emoji | alias Pleroma.Emoji | ||||
@spec emoji_path() :: Path.t() | |||||
def emoji_path do | |||||
static = Pleroma.Config.get!([:instance, :static_dir]) | |||||
Path.join(static, "emoji") | |||||
end | |||||
@spec create(String.t()) :: :ok | {:error, File.posix()} | {:error, :empty_values} | @spec create(String.t()) :: :ok | {:error, File.posix()} | {:error, :empty_values} | ||||
def create(name) when byte_size(name) > 0 do | |||||
dir = Path.join(emoji_path(), name) | |||||
with :ok <- File.mkdir(dir) do | |||||
%__MODULE__{ | |||||
pack_file: Path.join(dir, "pack.json") | |||||
} | |||||
def create(name) do | |||||
with :ok <- validate_not_empty([name]), | |||||
dir <- Path.join(emoji_path(), name), | |||||
:ok <- File.mkdir(dir) do | |||||
%__MODULE__{pack_file: Path.join(dir, "pack.json")} | |||||
|> save_pack() | |> save_pack() | ||||
end | end | ||||
end | end | ||||
def create(_), do: {:error, :empty_values} | |||||
@spec show(String.t()) :: {:ok, t()} | {:loaded, nil} | {:error, :empty_values} | |||||
def show(name) when byte_size(name) > 0 do | |||||
with {_, %__MODULE__{} = pack} <- {:loaded, load_pack(name)}, | |||||
{_, pack} <- validate_pack(pack) do | |||||
{:ok, pack} | |||||
@spec show(String.t()) :: {:ok, t()} | {:error, atom()} | |||||
def show(name) do | |||||
with :ok <- validate_not_empty([name]), | |||||
{:ok, pack} <- load_pack(name) do | |||||
{:ok, validate_pack(pack)} | |||||
end | end | ||||
end | end | ||||
def show(_), do: {:error, :empty_values} | |||||
@spec delete(String.t()) :: | @spec delete(String.t()) :: | ||||
{:ok, [binary()]} | {:error, File.posix(), binary()} | {:error, :empty_values} | {:ok, [binary()]} | {:error, File.posix(), binary()} | {:error, :empty_values} | ||||
def delete(name) when byte_size(name) > 0 do | |||||
emoji_path() | |||||
|> Path.join(name) | |||||
|> File.rm_rf() | |||||
end | |||||
def delete(_), do: {:error, :empty_values} | |||||
@spec add_file(String.t(), String.t(), Path.t(), Plug.Upload.t() | String.t()) :: | |||||
{:ok, t()} | {:error, File.posix()} | {:error, :empty_values} | |||||
def add_file(name, shortcode, filename, file) | |||||
when byte_size(name) > 0 and byte_size(shortcode) > 0 and byte_size(filename) > 0 do | |||||
with {_, nil} <- {:exists, Emoji.get(shortcode)}, | |||||
{_, %__MODULE__{} = pack} <- {:loaded, load_pack(name)} do | |||||
file_path = Path.join(pack.path, filename) | |||||
create_subdirs(file_path) | |||||
case file do | |||||
%Plug.Upload{path: upload_path} -> | |||||
# Copy the uploaded file from the temporary directory | |||||
File.copy!(upload_path, file_path) | |||||
url when is_binary(url) -> | |||||
# Download and write the file | |||||
file_contents = Tesla.get!(url).body | |||||
File.write!(file_path, file_contents) | |||||
end | |||||
files = Map.put(pack.files, shortcode, filename) | |||||
updated_pack = %{pack | files: files} | |||||
case save_pack(updated_pack) do | |||||
:ok -> | |||||
Emoji.reload() | |||||
{:ok, updated_pack} | |||||
e -> | |||||
e | |||||
end | |||||
def delete(name) do | |||||
with :ok <- validate_not_empty([name]) do | |||||
emoji_path() | |||||
|> Path.join(name) | |||||
|> File.rm_rf() | |||||
end | end | ||||
end | end | ||||
def add_file(_, _, _, _), do: {:error, :empty_values} | |||||
defp create_subdirs(file_path) do | |||||
if String.contains?(file_path, "/") do | |||||
file_path | |||||
|> Path.dirname() | |||||
|> File.mkdir_p!() | |||||
@spec add_file(String.t(), String.t(), Path.t(), Plug.Upload.t() | String.t()) :: | |||||
{:ok, t()} | {:error, File.posix() | atom()} | |||||
def add_file(name, shortcode, filename, file) do | |||||
with :ok <- validate_not_empty([name, shortcode, filename]), | |||||
:ok <- validate_emoji_not_exists(shortcode), | |||||
{:ok, pack} <- load_pack(name), | |||||
:ok <- save_file(file, pack, filename), | |||||
{:ok, updated_pack} <- pack |> put_emoji(shortcode, filename) |> save_pack() do | |||||
Emoji.reload() | |||||
{:ok, updated_pack} | |||||
end | end | ||||
end | end | ||||
@spec delete_file(String.t(), String.t()) :: | @spec delete_file(String.t(), String.t()) :: | ||||
{:ok, t()} | {:error, File.posix()} | {:error, :empty_values} | |||||
def delete_file(name, shortcode) when byte_size(name) > 0 and byte_size(shortcode) > 0 do | |||||
with {_, %__MODULE__{} = pack} <- {:loaded, load_pack(name)}, | |||||
{_, {filename, files}} when not is_nil(filename) <- | |||||
{:exists, Map.pop(pack.files, shortcode)}, | |||||
emoji <- Path.join(pack.path, filename), | |||||
{_, true} <- {:exists, File.exists?(emoji)} do | |||||
emoji_dir = Path.dirname(emoji) | |||||
File.rm!(emoji) | |||||
if String.contains?(filename, "/") and File.ls!(emoji_dir) == [] do | |||||
File.rmdir!(emoji_dir) | |||||
end | |||||
updated_pack = %{pack | files: files} | |||||
case save_pack(updated_pack) do | |||||
:ok -> | |||||
Emoji.reload() | |||||
{:ok, updated_pack} | |||||
e -> | |||||
e | |||||
end | |||||
{:ok, t()} | {:error, File.posix() | atom()} | |||||
def delete_file(name, shortcode) do | |||||
with :ok <- validate_not_empty([name, shortcode]), | |||||
{:ok, pack} <- load_pack(name), | |||||
:ok <- remove_file(pack, shortcode), | |||||
{:ok, updated_pack} <- pack |> delete_emoji(shortcode) |> save_pack() do | |||||
Emoji.reload() | |||||
{:ok, updated_pack} | |||||
end | end | ||||
end | end | ||||
def delete_file(_, _), do: {:error, :empty_values} | |||||
@spec update_file(String.t(), String.t(), String.t(), String.t(), boolean()) :: | @spec update_file(String.t(), String.t(), String.t(), String.t(), boolean()) :: | ||||
{:ok, t()} | {:error, File.posix()} | {:error, :empty_values} | |||||
def update_file(name, shortcode, new_shortcode, new_filename, force) | |||||
when byte_size(name) > 0 and byte_size(shortcode) > 0 and byte_size(new_shortcode) > 0 and | |||||
byte_size(new_filename) > 0 do | |||||
with {_, %__MODULE__{} = pack} <- {:loaded, load_pack(name)}, | |||||
{_, {filename, files}} when not is_nil(filename) <- | |||||
{:exists, Map.pop(pack.files, shortcode)}, | |||||
{_, true} <- {:not_used, force or is_nil(Emoji.get(new_shortcode))} do | |||||
old_path = Path.join(pack.path, filename) | |||||
old_dir = Path.dirname(old_path) | |||||
new_path = Path.join(pack.path, new_filename) | |||||
create_subdirs(new_path) | |||||
:ok = File.rename(old_path, new_path) | |||||
if String.contains?(filename, "/") and File.ls!(old_dir) == [] do | |||||
File.rmdir!(old_dir) | |||||
end | |||||
files = Map.put(files, new_shortcode, new_filename) | |||||
updated_pack = %{pack | files: files} | |||||
case save_pack(updated_pack) do | |||||
:ok -> | |||||
Emoji.reload() | |||||
{:ok, updated_pack} | |||||
e -> | |||||
e | |||||
end | |||||
{:ok, t()} | {:error, File.posix() | atom()} | |||||
def update_file(name, shortcode, new_shortcode, new_filename, force) do | |||||
with :ok <- validate_not_empty([name, shortcode, new_shortcode, new_filename]), | |||||
{:ok, pack} <- load_pack(name), | |||||
{:ok, filename} <- get_filename(pack, shortcode), | |||||
:ok <- validate_emoji_not_exists(new_shortcode, force), | |||||
:ok <- rename_file(pack, filename, new_filename), | |||||
{:ok, updated_pack} <- | |||||
pack | |||||
|> delete_emoji(shortcode) | |||||
|> put_emoji(new_shortcode, new_filename) | |||||
|> save_pack() do | |||||
Emoji.reload() | |||||
{:ok, updated_pack} | |||||
end | end | ||||
end | end | ||||
def update_file(_, _, _, _, _), do: {:error, :empty_values} | |||||
@spec import_from_filesystem() :: {:ok, [String.t()]} | {:error, atom()} | |||||
@spec import_from_filesystem() :: {:ok, [String.t()]} | {:error, File.posix() | atom()} | |||||
def import_from_filesystem do | def import_from_filesystem do | ||||
emoji_path = emoji_path() | emoji_path = emoji_path() | ||||
@@ -184,7 +100,7 @@ defmodule Pleroma.Emoji.Pack do | |||||
File.dir?(path) and File.exists?(Path.join(path, "pack.json")) | File.dir?(path) and File.exists?(Path.join(path, "pack.json")) | ||||
end) | end) | ||||
|> Enum.map(&write_pack_contents/1) | |> Enum.map(&write_pack_contents/1) | ||||
|> Enum.filter(& &1) | |||||
|> Enum.reject(&is_nil/1) | |||||
{:ok, names} | {:ok, names} | ||||
else | else | ||||
@@ -193,6 +109,117 @@ defmodule Pleroma.Emoji.Pack do | |||||
end | end | ||||
end | end | ||||
@spec list_remote(String.t()) :: {:ok, map()} | {:error, atom()} | |||||
def list_remote(url) do | |||||
uri = url |> String.trim() |> URI.parse() | |||||
with :ok <- validate_shareable_packs_available(uri) do | |||||
uri | |||||
|> URI.merge("/api/pleroma/emoji/packs") | |||||
|> http_get() | |||||
end | |||||
end | |||||
@spec list_local() :: {:ok, map()} | |||||
def list_local do | |||||
with {:ok, results} <- list_packs_dir() do | |||||
packs = | |||||
results | |||||
|> Enum.map(fn name -> | |||||
case load_pack(name) do | |||||
{:ok, pack} -> pack | |||||
_ -> nil | |||||
end | |||||
end) | |||||
|> Enum.reject(&is_nil/1) | |||||
|> Map.new(fn pack -> {pack.name, validate_pack(pack)} end) | |||||
{:ok, packs} | |||||
end | |||||
end | |||||
@spec get_archive(String.t()) :: {:ok, binary()} | {:error, atom()} | |||||
def get_archive(name) do | |||||
with {:ok, pack} <- load_pack(name), | |||||
:ok <- validate_downloadable(pack) do | |||||
{:ok, fetch_archive(pack)} | |||||
end | |||||
end | |||||
@spec download(String.t(), String.t(), String.t()) :: :ok | {:error, atom()} | |||||
def download(name, url, as) do | |||||
uri = url |> String.trim() |> URI.parse() | |||||
with :ok <- validate_shareable_packs_available(uri), | |||||
{:ok, remote_pack} <- uri |> URI.merge("/api/pleroma/emoji/packs/#{name}") |> http_get(), | |||||
{:ok, %{sha: sha, url: url} = pack_info} <- fetch_pack_info(remote_pack, uri, name), | |||||
{:ok, archive} <- download_archive(url, sha), | |||||
pack <- copy_as(remote_pack, as || name), | |||||
{:ok, _} = unzip(archive, pack_info, remote_pack, pack) do | |||||
# Fallback can't contain a pack.json file, since that would cause the fallback-src-sha256 | |||||
# in it to depend on itself | |||||
if pack_info[:fallback] do | |||||
save_pack(pack) | |||||
else | |||||
{:ok, pack} | |||||
end | |||||
end | |||||
end | |||||
@spec save_metadata(map(), t()) :: {:ok, t()} | {:error, File.posix()} | |||||
def save_metadata(metadata, %__MODULE__{} = pack) do | |||||
pack | |||||
|> Map.put(:pack, metadata) | |||||
|> save_pack() | |||||
end | |||||
@spec update_metadata(String.t(), map()) :: {:ok, t()} | {:error, File.posix()} | |||||
def update_metadata(name, data) do | |||||
with {:ok, pack} <- load_pack(name) do | |||||
if fallback_sha_changed?(pack, data) do | |||||
update_sha_and_save_metadata(pack, data) | |||||
else | |||||
save_metadata(data, pack) | |||||
end | |||||
end | |||||
end | |||||
@spec load_pack(String.t()) :: {:ok, t()} | {:error, :not_found} | |||||
def load_pack(name) do | |||||
pack_file = Path.join([emoji_path(), name, "pack.json"]) | |||||
if File.exists?(pack_file) do | |||||
pack = | |||||
pack_file | |||||
|> File.read!() | |||||
|> from_json() | |||||
|> Map.put(:pack_file, pack_file) | |||||
|> Map.put(:path, Path.dirname(pack_file)) | |||||
|> Map.put(:name, name) | |||||
{:ok, pack} | |||||
else | |||||
{:error, :not_found} | |||||
end | |||||
end | |||||
@spec emoji_path() :: Path.t() | |||||
defp emoji_path do | |||||
[:instance, :static_dir] | |||||
|> Pleroma.Config.get!() | |||||
|> Path.join("emoji") | |||||
end | |||||
defp validate_emoji_not_exists(shortcode, force \\ false) | |||||
defp validate_emoji_not_exists(_shortcode, true), do: :ok | |||||
defp validate_emoji_not_exists(shortcode, _) do | |||||
case Emoji.get(shortcode) do | |||||
nil -> :ok | |||||
_ -> {:error, :already_exists} | |||||
end | |||||
end | |||||
defp write_pack_contents(path) do | defp write_pack_contents(path) do | ||||
pack = %__MODULE__{ | pack = %__MODULE__{ | ||||
files: files_from_path(path), | files: files_from_path(path), | ||||
@@ -201,7 +228,7 @@ defmodule Pleroma.Emoji.Pack do | |||||
} | } | ||||
case save_pack(pack) do | case save_pack(pack) do | ||||
:ok -> Path.basename(path) | |||||
{:ok, _pack} -> Path.basename(path) | |||||
_ -> nil | _ -> nil | ||||
end | end | ||||
end | end | ||||
@@ -216,7 +243,8 @@ defmodule Pleroma.Emoji.Pack do | |||||
# FIXME: Copy-pasted from Pleroma.Emoji/load_from_file_stream/2 | # FIXME: Copy-pasted from Pleroma.Emoji/load_from_file_stream/2 | ||||
# Create a map of shortcodes to filenames from emoji.txt | # Create a map of shortcodes to filenames from emoji.txt | ||||
File.read!(txt_path) | |||||
txt_path | |||||
|> File.read!() | |||||
|> String.split("\n") | |> String.split("\n") | ||||
|> Enum.map(&String.trim/1) | |> Enum.map(&String.trim/1) | ||||
|> Enum.map(fn line -> | |> Enum.map(fn line -> | ||||
@@ -226,21 +254,18 @@ defmodule Pleroma.Emoji.Pack do | |||||
[name, file | _] -> | [name, file | _] -> | ||||
file_dir_name = Path.dirname(file) | file_dir_name = Path.dirname(file) | ||||
file = | |||||
if String.ends_with?(path, file_dir_name) do | |||||
Path.basename(file) | |||||
else | |||||
file | |||||
end | |||||
{name, file} | |||||
if String.ends_with?(path, file_dir_name) do | |||||
{name, Path.basename(file)} | |||||
else | |||||
{name, file} | |||||
end | |||||
_ -> | _ -> | ||||
nil | nil | ||||
end | end | ||||
end) | end) | ||||
|> Enum.filter(& &1) | |||||
|> Enum.into(%{}) | |||||
|> Enum.reject(&is_nil/1) | |||||
|> Map.new() | |||||
else | else | ||||
# If there's no emoji.txt, assume all files | # If there's no emoji.txt, assume all files | ||||
# that are of certain extensions from the config are emojis and import them all | # that are of certain extensions from the config are emojis and import them all | ||||
@@ -249,60 +274,20 @@ defmodule Pleroma.Emoji.Pack do | |||||
end | end | ||||
end | end | ||||
@spec list_remote(String.t()) :: {:ok, map()} | |||||
def list_remote(url) do | |||||
uri = | |||||
url | |||||
|> String.trim() | |||||
|> URI.parse() | |||||
with {_, true} <- {:shareable, shareable_packs_available?(uri)} do | |||||
packs = | |||||
uri | |||||
|> URI.merge("/api/pleroma/emoji/packs") | |||||
|> to_string() | |||||
|> Tesla.get!() | |||||
|> Map.get(:body) | |||||
|> Jason.decode!() | |||||
{:ok, packs} | |||||
end | |||||
end | |||||
@spec list_local() :: {:ok, map()} | |||||
def list_local do | |||||
emoji_path = emoji_path() | |||||
# Create the directory first if it does not exist. This is probably the first request made | |||||
# with the API so it should be sufficient | |||||
with {:create_dir, :ok} <- {:create_dir, File.mkdir_p(emoji_path)}, | |||||
{:ls, {:ok, results}} <- {:ls, File.ls(emoji_path)} do | |||||
packs = | |||||
results | |||||
|> Enum.map(&load_pack/1) | |||||
|> Enum.filter(& &1) | |||||
|> Enum.map(&validate_pack/1) | |||||
|> Map.new() | |||||
{:ok, packs} | |||||
end | |||||
end | |||||
defp validate_pack(pack) do | defp validate_pack(pack) do | ||||
if downloadable?(pack) do | |||||
archive = fetch_archive(pack) | |||||
archive_sha = :crypto.hash(:sha256, archive) |> Base.encode16() | |||||
info = | |||||
if downloadable?(pack) do | |||||
archive = fetch_archive(pack) | |||||
archive_sha = :crypto.hash(:sha256, archive) |> Base.encode16() | |||||
info = | |||||
pack.pack | pack.pack | ||||
|> Map.put("can-download", true) | |> Map.put("can-download", true) | ||||
|> Map.put("download-sha256", archive_sha) | |> Map.put("download-sha256", archive_sha) | ||||
else | |||||
Map.put(pack.pack, "can-download", false) | |||||
end | |||||
{pack.name, Map.put(pack, :pack, info)} | |||||
else | |||||
info = Map.put(pack.pack, "can-download", false) | |||||
{pack.name, Map.put(pack, :pack, info)} | |||||
end | |||||
Map.put(pack, :pack, info) | |||||
end | end | ||||
defp downloadable?(pack) do | defp downloadable?(pack) do | ||||
@@ -315,26 +300,6 @@ defmodule Pleroma.Emoji.Pack do | |||||
end) | end) | ||||
end | end | ||||
@spec get_archive(String.t()) :: {:ok, binary()} | |||||
def get_archive(name) do | |||||
with {_, %__MODULE__{} = pack} <- {:exists?, load_pack(name)}, | |||||
{_, true} <- {:can_download?, downloadable?(pack)} do | |||||
{:ok, fetch_archive(pack)} | |||||
end | |||||
end | |||||
defp fetch_archive(pack) do | |||||
hash = :crypto.hash(:md5, File.read!(pack.pack_file)) | |||||
case Cachex.get!(:emoji_packs_cache, pack.name) do | |||||
%{hash: ^hash, pack_data: archive} -> | |||||
archive | |||||
_ -> | |||||
create_archive_and_cache(pack, hash) | |||||
end | |||||
end | |||||
defp create_archive_and_cache(pack, hash) do | defp create_archive_and_cache(pack, hash) do | ||||
files = ['pack.json' | Enum.map(pack.files, fn {_, file} -> to_charlist(file) end)] | files = ['pack.json' | Enum.map(pack.files, fn {_, file} -> to_charlist(file) end)] | ||||
@@ -356,152 +321,221 @@ defmodule Pleroma.Emoji.Pack do | |||||
result | result | ||||
end | end | ||||
@spec download(String.t(), String.t(), String.t()) :: :ok | |||||
def download(name, url, as) do | |||||
uri = | |||||
url | |||||
|> String.trim() | |||||
|> URI.parse() | |||||
with {_, true} <- {:shareable, shareable_packs_available?(uri)} do | |||||
remote_pack = | |||||
uri | |||||
|> URI.merge("/api/pleroma/emoji/packs/#{name}") | |||||
|> to_string() | |||||
|> Tesla.get!() | |||||
|> Map.get(:body) | |||||
|> Jason.decode!() | |||||
result = | |||||
case remote_pack["pack"] do | |||||
%{"share-files" => true, "can-download" => true, "download-sha256" => sha} -> | |||||
{:ok, | |||||
%{ | |||||
sha: sha, | |||||
url: URI.merge(uri, "/api/pleroma/emoji/packs/#{name}/archive") |> to_string() | |||||
}} | |||||
%{"fallback-src" => src, "fallback-src-sha256" => sha} when is_binary(src) -> | |||||
{:ok, | |||||
%{ | |||||
sha: sha, | |||||
url: src, | |||||
fallback: true | |||||
}} | |||||
defp save_pack(pack) do | |||||
with {:ok, json} <- Jason.encode(pack, pretty: true), | |||||
:ok <- File.write(pack.pack_file, json) do | |||||
{:ok, pack} | |||||
end | |||||
end | |||||
_ -> | |||||
{:error, | |||||
"The pack was not set as shared and there is no fallback src to download from"} | |||||
end | |||||
defp from_json(json) do | |||||
map = Jason.decode!(json) | |||||
with {:ok, %{sha: sha, url: url} = pinfo} <- result, | |||||
%{body: archive} <- Tesla.get!(url), | |||||
{_, true} <- {:checksum, Base.decode16!(sha) == :crypto.hash(:sha256, archive)} do | |||||
local_name = as || name | |||||
struct(__MODULE__, %{files: map["files"], pack: map["pack"]}) | |||||
end | |||||
path = Path.join(emoji_path(), local_name) | |||||
defp validate_shareable_packs_available(uri) do | |||||
with {:ok, %{"links" => links}} <- uri |> URI.merge("/.well-known/nodeinfo") |> http_get(), | |||||
# Get the actual nodeinfo address and fetch it | |||||
{:ok, %{"metadata" => %{"features" => features}}} <- | |||||
links |> List.last() |> Map.get("href") |> http_get() do | |||||
if Enum.member?(features, "shareable_emoji_packs") do | |||||
:ok | |||||
else | |||||
{:error, :not_shareable} | |||||
end | |||||
end | |||||
end | |||||
pack = %__MODULE__{ | |||||
name: local_name, | |||||
path: path, | |||||
files: remote_pack["files"], | |||||
pack_file: Path.join(path, "pack.json") | |||||
} | |||||
defp validate_not_empty(list) do | |||||
if Enum.all?(list, fn i -> is_binary(i) and i != "" end) do | |||||
:ok | |||||
else | |||||
{:error, :empty_values} | |||||
end | |||||
end | |||||
File.mkdir_p!(pack.path) | |||||
defp save_file(file, pack, filename) do | |||||
file_path = Path.join(pack.path, filename) | |||||
create_subdirs(file_path) | |||||
files = Enum.map(remote_pack["files"], fn {_, path} -> to_charlist(path) end) | |||||
# Fallback cannot contain a pack.json file | |||||
files = if pinfo[:fallback], do: files, else: ['pack.json' | files] | |||||
case file do | |||||
%Plug.Upload{path: upload_path} -> | |||||
# Copy the uploaded file from the temporary directory | |||||
with {:ok, _} <- File.copy(upload_path, file_path), do: :ok | |||||
{:ok, _} = :zip.unzip(archive, cwd: to_charlist(pack.path), file_list: files) | |||||
url when is_binary(url) -> | |||||
# Download and write the file | |||||
file_contents = Tesla.get!(url).body | |||||
File.write(file_path, file_contents) | |||||
end | |||||
end | |||||
# Fallback can't contain a pack.json file, since that would cause the fallback-src-sha256 | |||||
# in it to depend on itself | |||||
if pinfo[:fallback] do | |||||
save_pack(pack) | |||||
end | |||||
defp put_emoji(pack, shortcode, filename) do | |||||
files = Map.put(pack.files, shortcode, filename) | |||||
%{pack | files: files} | |||||
end | |||||
:ok | |||||
end | |||||
defp delete_emoji(pack, shortcode) do | |||||
files = Map.delete(pack.files, shortcode) | |||||
%{pack | files: files} | |||||
end | |||||
defp rename_file(pack, filename, new_filename) do | |||||
old_path = Path.join(pack.path, filename) | |||||
new_path = Path.join(pack.path, new_filename) | |||||
create_subdirs(new_path) | |||||
with :ok <- File.rename(old_path, new_path) do | |||||
remove_dir_if_empty(old_path, filename) | |||||
end | end | ||||
end | end | ||||
defp save_pack(pack), do: File.write(pack.pack_file, Jason.encode!(pack, pretty: true)) | |||||
defp create_subdirs(file_path) do | |||||
if String.contains?(file_path, "/") do | |||||
file_path | |||||
|> Path.dirname() | |||||
|> File.mkdir_p!() | |||||
end | |||||
end | |||||
@spec save_metadata(map(), t()) :: {:ok, t()} | {:error, File.posix()} | |||||
def save_metadata(metadata, %__MODULE__{} = pack) do | |||||
pack = Map.put(pack, :pack, metadata) | |||||
defp remove_file(pack, shortcode) do | |||||
with {:ok, filename} <- get_filename(pack, shortcode), | |||||
emoji <- Path.join(pack.path, filename), | |||||
:ok <- File.rm(emoji) do | |||||
remove_dir_if_empty(emoji, filename) | |||||
end | |||||
end | |||||
with :ok <- save_pack(pack) do | |||||
{:ok, pack} | |||||
defp remove_dir_if_empty(emoji, filename) do | |||||
dir = Path.dirname(emoji) | |||||
if String.contains?(filename, "/") and File.ls!(dir) == [] do | |||||
File.rmdir!(dir) | |||||
else | |||||
:ok | |||||
end | end | ||||
end | end | ||||
@spec update_metadata(String.t(), map()) :: {:ok, t()} | {:error, File.posix()} | |||||
def update_metadata(name, data) do | |||||
pack = load_pack(name) | |||||
defp get_filename(pack, shortcode) do | |||||
with %{^shortcode => filename} when is_binary(filename) <- pack.files, | |||||
true <- pack.path |> Path.join(filename) |> File.exists?() do | |||||
{:ok, filename} | |||||
else | |||||
_ -> {:error, :doesnt_exist} | |||||
end | |||||
end | |||||
fb_sha_changed? = | |||||
not is_nil(data["fallback-src"]) and data["fallback-src"] != pack.pack["fallback-src"] | |||||
defp http_get(%URI{} = url), do: url |> to_string() |> http_get() | |||||
with {_, true} <- {:update?, fb_sha_changed?}, | |||||
{:ok, %{body: zip}} <- Tesla.get(data["fallback-src"]), | |||||
{:ok, f_list} <- :zip.unzip(zip, [:memory]), | |||||
{_, true} <- {:has_all_files?, has_all_files?(pack.files, f_list)} do | |||||
fallback_sha = :crypto.hash(:sha256, zip) |> Base.encode16() | |||||
defp http_get(url) do | |||||
with {:ok, %{body: body}} <- url |> Pleroma.HTTP.get() do | |||||
Jason.decode(body) | |||||
end | |||||
end | |||||
data | |||||
|> Map.put("fallback-src-sha256", fallback_sha) | |||||
|> save_metadata(pack) | |||||
defp list_packs_dir do | |||||
emoji_path = emoji_path() | |||||
# Create the directory first if it does not exist. This is probably the first request made | |||||
# with the API so it should be sufficient | |||||
with {:create_dir, :ok} <- {:create_dir, File.mkdir_p(emoji_path)}, | |||||
{:ls, {:ok, results}} <- {:ls, File.ls(emoji_path)} do | |||||
{:ok, results} | |||||
else | else | ||||
{:update?, _} -> save_metadata(data, pack) | |||||
e -> e | |||||
{:create_dir, {:error, e}} -> {:error, :create_dir, e} | |||||
{:ls, {:error, e}} -> {:error, :ls, e} | |||||
end | end | ||||
end | end | ||||
# Check if all files from the pack.json are in the archive | |||||
defp has_all_files?(files, f_list) do | |||||
Enum.all?(files, fn {_, from_manifest} -> | |||||
List.keyfind(f_list, to_charlist(from_manifest), 0) | |||||
end) | |||||
defp validate_downloadable(pack) do | |||||
if downloadable?(pack), do: :ok, else: {:error, :cant_download} | |||||
end | end | ||||
@spec load_pack(String.t()) :: t() | nil | |||||
def load_pack(name) do | |||||
pack_file = Path.join([emoji_path(), name, "pack.json"]) | |||||
defp copy_as(remote_pack, local_name) do | |||||
path = Path.join(emoji_path(), local_name) | |||||
if File.exists?(pack_file) do | |||||
pack_file | |||||
|> File.read!() | |||||
|> from_json() | |||||
|> Map.put(:pack_file, pack_file) | |||||
|> Map.put(:path, Path.dirname(pack_file)) | |||||
|> Map.put(:name, name) | |||||
%__MODULE__{ | |||||
name: local_name, | |||||
path: path, | |||||
files: remote_pack["files"], | |||||
pack_file: Path.join(path, "pack.json") | |||||
} | |||||
end | |||||
defp unzip(archive, pack_info, remote_pack, local_pack) do | |||||
with :ok <- File.mkdir_p!(local_pack.path) do | |||||
files = Enum.map(remote_pack["files"], fn {_, path} -> to_charlist(path) end) | |||||
# Fallback cannot contain a pack.json file | |||||
files = if pack_info[:fallback], do: files, else: ['pack.json' | files] | |||||
:zip.unzip(archive, cwd: to_charlist(local_pack.path), file_list: files) | |||||
end | end | ||||
end | end | ||||
defp from_json(json) do | |||||
map = Jason.decode!(json) | |||||
defp fetch_pack_info(remote_pack, uri, name) do | |||||
case remote_pack["pack"] do | |||||
%{"share-files" => true, "can-download" => true, "download-sha256" => sha} -> | |||||
{:ok, | |||||
%{ | |||||
sha: sha, | |||||
url: URI.merge(uri, "/api/pleroma/emoji/packs/#{name}/archive") |> to_string() | |||||
}} | |||||
%{"fallback-src" => src, "fallback-src-sha256" => sha} when is_binary(src) -> | |||||
{:ok, | |||||
%{ | |||||
sha: sha, | |||||
url: src, | |||||
fallback: true | |||||
}} | |||||
struct(__MODULE__, %{files: map["files"], pack: map["pack"]}) | |||||
_ -> | |||||
{:error, "The pack was not set as shared and there is no fallback src to download from"} | |||||
end | |||||
end | |||||
defp download_archive(url, sha) do | |||||
with {:ok, %{body: archive}} <- Tesla.get(url) do | |||||
if Base.decode16!(sha) == :crypto.hash(:sha256, archive) do | |||||
{:ok, archive} | |||||
else | |||||
{:error, :imvalid_checksum} | |||||
end | |||||
end | |||||
end | |||||
defp fetch_archive(pack) do | |||||
hash = :crypto.hash(:md5, File.read!(pack.pack_file)) | |||||
case Cachex.get!(:emoji_packs_cache, pack.name) do | |||||
%{hash: ^hash, pack_data: archive} -> archive | |||||
_ -> create_archive_and_cache(pack, hash) | |||||
end | |||||
end | |||||
defp fallback_sha_changed?(pack, data) do | |||||
is_binary(data[:"fallback-src"]) and data[:"fallback-src"] != pack.pack["fallback-src"] | |||||
end | |||||
defp update_sha_and_save_metadata(pack, data) do | |||||
with {:ok, %{body: zip}} <- Tesla.get(data[:"fallback-src"]), | |||||
:ok <- validate_has_all_files(pack, zip) do | |||||
fallback_sha = :sha256 |> :crypto.hash(zip) |> Base.encode16() | |||||
data | |||||
|> Map.put("fallback-src-sha256", fallback_sha) | |||||
|> save_metadata(pack) | |||||
end | |||||
end | end | ||||
defp shareable_packs_available?(uri) do | |||||
uri | |||||
|> URI.merge("/.well-known/nodeinfo") | |||||
|> to_string() | |||||
|> Tesla.get!() | |||||
|> Map.get(:body) | |||||
|> Jason.decode!() | |||||
|> Map.get("links") | |||||
|> List.last() | |||||
|> Map.get("href") | |||||
# Get the actual nodeinfo address and fetch it | |||||
|> Tesla.get!() | |||||
|> Map.get(:body) | |||||
|> Jason.decode!() | |||||
|> get_in(["metadata", "features"]) | |||||
|> Enum.member?("shareable_emoji_packs") | |||||
defp validate_has_all_files(pack, zip) do | |||||
with {:ok, f_list} <- :zip.unzip(zip, [:memory]) do | |||||
# Check if all files from the pack.json are in the archive | |||||
pack.files | |||||
|> Enum.all?(fn {_, from_manifest} -> | |||||
List.keyfind(f_list, to_charlist(from_manifest), 0) | |||||
end) | |||||
|> if(do: :ok, else: {:error, :incomplete}) | |||||
end | |||||
end | end | ||||
end | end |
@@ -0,0 +1,390 @@ | |||||
# Pleroma: A lightweight social networking server | |||||
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> | |||||
# SPDX-License-Identifier: AGPL-3.0-only | |||||
defmodule Pleroma.Web.ApiSpec.PleromaEmojiPackOperation do | |||||
alias OpenApiSpex.Operation | |||||
alias OpenApiSpex.Schema | |||||
alias Pleroma.Web.ApiSpec.Schemas.ApiError | |||||
import Pleroma.Web.ApiSpec.Helpers | |||||
def open_api_operation(action) do | |||||
operation = String.to_existing_atom("#{action}_operation") | |||||
apply(__MODULE__, operation, []) | |||||
end | |||||
def remote_operation do | |||||
%Operation{ | |||||
tags: ["Emoji Packs"], | |||||
summary: "Make request to another instance for emoji packs list", | |||||
security: [%{"oAuth" => ["write"]}], | |||||
parameters: [url_param()], | |||||
operationId: "PleromaAPI.EmojiPackController.remote", | |||||
responses: %{ | |||||
200 => emoji_packs_response(), | |||||
500 => Operation.response("Error", "application/json", ApiError) | |||||
} | |||||
} | |||||
end | |||||
def index_operation do | |||||
%Operation{ | |||||
tags: ["Emoji Packs"], | |||||
summary: "Lists local custom emoji packs", | |||||
operationId: "PleromaAPI.EmojiPackController.index", | |||||
responses: %{ | |||||
200 => emoji_packs_response() | |||||
} | |||||
} | |||||
end | |||||
def show_operation do | |||||
%Operation{ | |||||
tags: ["Emoji Packs"], | |||||
summary: "Show emoji pack", | |||||
operationId: "PleromaAPI.EmojiPackController.show", | |||||
parameters: [name_param()], | |||||
responses: %{ | |||||
200 => Operation.response("Emoji Pack", "application/json", emoji_pack()), | |||||
400 => Operation.response("Bad Request", "application/json", ApiError), | |||||
404 => Operation.response("Not Found", "application/json", ApiError) | |||||
} | |||||
} | |||||
end | |||||
def archive_operation do | |||||
%Operation{ | |||||
tags: ["Emoji Packs"], | |||||
summary: "Requests a local pack archive from the instance", | |||||
operationId: "PleromaAPI.EmojiPackController.archive", | |||||
parameters: [name_param()], | |||||
responses: %{ | |||||
200 => | |||||
Operation.response("Archive file", "application/octet-stream", %Schema{ | |||||
type: :string, | |||||
format: :binary | |||||
}), | |||||
403 => Operation.response("Forbidden", "application/json", ApiError), | |||||
404 => Operation.response("Not Found", "application/json", ApiError) | |||||
} | |||||
} | |||||
end | |||||
def download_operation do | |||||
%Operation{ | |||||
tags: ["Emoji Packs"], | |||||
summary: "Download pack from another instance", | |||||
operationId: "PleromaAPI.EmojiPackController.download", | |||||
security: [%{"oAuth" => ["write"]}], | |||||
requestBody: request_body("Parameters", download_request(), required: true), | |||||
responses: %{ | |||||
200 => ok_response(), | |||||
500 => Operation.response("Error", "application/json", ApiError) | |||||
} | |||||
} | |||||
end | |||||
defp download_request do | |||||
%Schema{ | |||||
type: :object, | |||||
required: [:url, :name], | |||||
properties: %{ | |||||
url: %Schema{ | |||||
type: :string, | |||||
format: :uri, | |||||
description: "URL of the instance to download from" | |||||
}, | |||||
name: %Schema{type: :string, format: :uri, description: "Pack Name"}, | |||||
as: %Schema{type: :string, format: :uri, description: "Save as"} | |||||
} | |||||
} | |||||
end | |||||
def create_operation do | |||||
%Operation{ | |||||
tags: ["Emoji Packs"], | |||||
summary: "Create an empty pack", | |||||
operationId: "PleromaAPI.EmojiPackController.create", | |||||
security: [%{"oAuth" => ["write"]}], | |||||
parameters: [name_param()], | |||||
responses: %{ | |||||
200 => ok_response(), | |||||
400 => Operation.response("Not Found", "application/json", ApiError), | |||||
409 => Operation.response("Conflict", "application/json", ApiError), | |||||
500 => Operation.response("Error", "application/json", ApiError) | |||||
} | |||||
} | |||||
end | |||||
def delete_operation do | |||||
%Operation{ | |||||
tags: ["Emoji Packs"], | |||||
summary: "Delete a custom emoji pack", | |||||
operationId: "PleromaAPI.EmojiPackController.delete", | |||||
security: [%{"oAuth" => ["write"]}], | |||||
parameters: [name_param()], | |||||
responses: %{ | |||||
200 => ok_response(), | |||||
400 => Operation.response("Bad Request", "application/json", ApiError), | |||||
404 => Operation.response("Not Found", "application/json", ApiError) | |||||
} | |||||
} | |||||
end | |||||
def update_operation do | |||||
%Operation{ | |||||
tags: ["Emoji Packs"], | |||||
summary: "Updates (replaces) pack metadata", | |||||
operationId: "PleromaAPI.EmojiPackController.update", | |||||
security: [%{"oAuth" => ["write"]}], | |||||
requestBody: request_body("Parameters", update_request(), required: true), | |||||
parameters: [name_param()], | |||||
responses: %{ | |||||
200 => Operation.response("Metadata", "application/json", metadata()), | |||||
400 => Operation.response("Bad Request", "application/json", ApiError) | |||||
} | |||||
} | |||||
end | |||||
def add_file_operation do | |||||
%Operation{ | |||||
tags: ["Emoji Packs"], | |||||
summary: "Add new file to the pack", | |||||
operationId: "PleromaAPI.EmojiPackController.add_file", | |||||
security: [%{"oAuth" => ["write"]}], | |||||
requestBody: request_body("Parameters", add_file_request(), required: true), | |||||
parameters: [name_param()], | |||||
responses: %{ | |||||
200 => Operation.response("Files Object", "application/json", files_object()), | |||||
400 => Operation.response("Bad Request", "application/json", ApiError), | |||||
409 => Operation.response("Conflict", "application/json", ApiError) | |||||
} | |||||
} | |||||
end | |||||
defp add_file_request do | |||||
%Schema{ | |||||
type: :object, | |||||
required: [:file], | |||||
properties: %{ | |||||
file: %Schema{ | |||||
description: | |||||
"File needs to be uploaded with the multipart request or link to remote file", | |||||
anyOf: [ | |||||
%Schema{type: :string, format: :binary}, | |||||
%Schema{type: :string, format: :uri} | |||||
] | |||||
}, | |||||
shortcode: %Schema{ | |||||
type: :string, | |||||
description: | |||||
"Shortcode for new emoji, must be unique for all emoji. If not sended, shortcode will be taken from original filename." | |||||
}, | |||||
filename: %Schema{ | |||||
type: :string, | |||||
description: | |||||
"New emoji file name. If not specified will be taken from original filename." | |||||
} | |||||
} | |||||
} | |||||
end | |||||
def update_file_operation do | |||||
%Operation{ | |||||
tags: ["Emoji Packs"], | |||||
summary: "Add new file to the pack", | |||||
operationId: "PleromaAPI.EmojiPackController.update_file", | |||||
security: [%{"oAuth" => ["write"]}], | |||||
requestBody: request_body("Parameters", update_file_request(), required: true), | |||||
parameters: [name_param()], | |||||
responses: %{ | |||||
200 => Operation.response("Files Object", "application/json", files_object()), | |||||
400 => Operation.response("Bad Request", "application/json", ApiError), | |||||
409 => Operation.response("Conflict", "application/json", ApiError) | |||||
} | |||||
} | |||||
end | |||||
defp update_file_request do | |||||
%Schema{ | |||||
type: :object, | |||||
required: [:shortcode, :new_shortcode, :new_filename], | |||||
properties: %{ | |||||
shortcode: %Schema{ | |||||
type: :string, | |||||
description: "Emoji file shortcode" | |||||
}, | |||||
new_shortcode: %Schema{ | |||||
type: :string, | |||||
description: "New emoji file shortcode" | |||||
}, | |||||
new_filename: %Schema{ | |||||
type: :string, | |||||
description: "New filename for emoji file" | |||||
}, | |||||
force: %Schema{ | |||||
type: :boolean, | |||||
description: "With true value to overwrite existing emoji with new shortcode", | |||||
default: false | |||||
} | |||||
} | |||||
} | |||||
end | |||||
def delete_file_operation do | |||||
%Operation{ | |||||
tags: ["Emoji Packs"], | |||||
summary: "Delete emoji file from pack", | |||||
operationId: "PleromaAPI.EmojiPackController.delete_file", | |||||
security: [%{"oAuth" => ["write"]}], | |||||
parameters: [ | |||||
name_param(), | |||||
Operation.parameter(:shortcode, :query, :string, "File shortcode", | |||||
example: "cofe", | |||||
required: true | |||||
) | |||||
], | |||||
responses: %{ | |||||
200 => Operation.response("Files Object", "application/json", files_object()), | |||||
400 => Operation.response("Bad Request", "application/json", ApiError) | |||||
} | |||||
} | |||||
end | |||||
def import_from_filesystem_operation do | |||||
%Operation{ | |||||
tags: ["Emoji Packs"], | |||||
summary: "Imports packs from filesystem", | |||||
operationId: "PleromaAPI.EmojiPackController.import", | |||||
security: [%{"oAuth" => ["write"]}], | |||||
responses: %{ | |||||
200 => | |||||
Operation.response("Array of imported pack names", "application/json", %Schema{ | |||||
type: :array, | |||||
items: %Schema{type: :string} | |||||
}) | |||||
} | |||||
} | |||||
end | |||||
defp name_param do | |||||
Operation.parameter(:name, :path, :string, "Pack Name", example: "cofe", required: true) | |||||
end | |||||
defp url_param do | |||||
Operation.parameter( | |||||
:url, | |||||
:query, | |||||
%Schema{type: :string, format: :uri}, | |||||
"URL of the instance", | |||||
required: true | |||||
) | |||||
end | |||||
defp ok_response do | |||||
Operation.response("Ok", "application/json", %Schema{type: :string, example: "ok"}) | |||||
end | |||||
defp emoji_packs_response do | |||||
Operation.response( | |||||
"Object with pack names as keys and pack contents as values", | |||||
"application/json", | |||||
%Schema{ | |||||
type: :object, | |||||
additionalProperties: emoji_pack(), | |||||
example: %{ | |||||
"emojos" => emoji_pack().example | |||||
} | |||||
} | |||||
) | |||||
end | |||||
defp emoji_pack do | |||||
%Schema{ | |||||
title: "EmojiPack", | |||||
type: :object, | |||||
properties: %{ | |||||
files: files_object(), | |||||
pack: %Schema{ | |||||
type: :object, | |||||
properties: %{ | |||||
license: %Schema{type: :string}, | |||||
homepage: %Schema{type: :string, format: :uri}, | |||||
description: %Schema{type: :string}, | |||||
"can-download": %Schema{type: :boolean}, | |||||
"share-files": %Schema{type: :boolean}, | |||||
"download-sha256": %Schema{type: :string} | |||||
} | |||||
} | |||||
}, | |||||
example: %{ | |||||
"files" => %{"emacs" => "emacs.png", "guix" => "guix.png"}, | |||||
"pack" => %{ | |||||
"license" => "Test license", | |||||
"homepage" => "https://pleroma.social", | |||||
"description" => "Test description", | |||||
"can-download" => true, | |||||
"share-files" => true, | |||||
"download-sha256" => "57482F30674FD3DE821FF48C81C00DA4D4AF1F300209253684ABA7075E5FC238" | |||||
} | |||||
} | |||||
} | |||||
end | |||||
defp files_object do | |||||
%Schema{ | |||||
type: :object, | |||||
additionalProperties: %Schema{type: :string}, | |||||
description: "Object with emoji names as keys and filenames as values" | |||||
} | |||||
end | |||||
defp update_request do | |||||
%Schema{ | |||||
type: :object, | |||||
properties: %{ | |||||
metadata: %Schema{ | |||||
type: :object, | |||||
description: "Metadata to replace the old one", | |||||
properties: %{ | |||||
license: %Schema{type: :string}, | |||||
homepage: %Schema{type: :string, format: :uri}, | |||||
description: %Schema{type: :string}, | |||||
"fallback-src": %Schema{ | |||||
type: :string, | |||||
format: :uri, | |||||
description: "Fallback url to download pack from" | |||||
}, | |||||
"fallback-src-sha256": %Schema{ | |||||
type: :string, | |||||
description: "SHA256 encoded for fallback pack archive" | |||||
}, | |||||
"share-files": %Schema{type: :boolean, description: "Is pack allowed for sharing?"} | |||||
} | |||||
} | |||||
} | |||||
} | |||||
end | |||||
defp metadata do | |||||
%Schema{ | |||||
type: :object, | |||||
properties: %{ | |||||
license: %Schema{type: :string}, | |||||
homepage: %Schema{type: :string, format: :uri}, | |||||
description: %Schema{type: :string}, | |||||
"fallback-src": %Schema{ | |||||
type: :string, | |||||
format: :uri, | |||||
description: "Fallback url to download pack from" | |||||
}, | |||||
"fallback-src-sha256": %Schema{ | |||||
type: :string, | |||||
description: "SHA256 encoded for fallback pack archive" | |||||
}, | |||||
"share-files": %Schema{type: :boolean, description: "Is pack allowed for sharing?"} | |||||
} | |||||
} | |||||
end | |||||
end |
@@ -1,8 +1,10 @@ | |||||
defmodule Pleroma.Web.PleromaAPI.EmojiAPIController do | |||||
defmodule Pleroma.Web.PleromaAPI.EmojiPackController do | |||||
use Pleroma.Web, :controller | use Pleroma.Web, :controller | ||||
alias Pleroma.Emoji.Pack | alias Pleroma.Emoji.Pack | ||||
plug(Pleroma.Web.ApiSpec.CastAndValidate) | |||||
plug( | plug( | ||||
Pleroma.Plugs.OAuthScopesPlug, | Pleroma.Plugs.OAuthScopesPlug, | ||||
%{scopes: ["write"], admin: true} | %{scopes: ["write"], admin: true} | ||||
@@ -19,39 +21,37 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIController do | |||||
] | ] | ||||
) | ) | ||||
plug( | |||||
:skip_plug, | |||||
[Pleroma.Plugs.OAuthScopesPlug, Pleroma.Plugs.ExpectPublicOrAuthenticatedCheckPlug] | |||||
when action in [:archive, :show, :list] | |||||
) | |||||
@skip_plugs [Pleroma.Plugs.OAuthScopesPlug, Pleroma.Plugs.ExpectPublicOrAuthenticatedCheckPlug] | |||||
plug(:skip_plug, @skip_plugs when action in [:archive, :show, :list]) | |||||
defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.PleromaEmojiPackOperation | |||||
def remote(conn, %{"url" => url}) do | |||||
def remote(conn, %{url: url}) do | |||||
with {:ok, packs} <- Pack.list_remote(url) do | with {:ok, packs} <- Pack.list_remote(url) do | ||||
json(conn, packs) | json(conn, packs) | ||||
else | else | ||||
{:shareable, _} -> | |||||
{:error, :not_shareable} -> | |||||
conn | conn | ||||
|> put_status(:internal_server_error) | |> put_status(:internal_server_error) | ||||
|> json(%{error: "The requested instance does not support sharing emoji packs"}) | |> json(%{error: "The requested instance does not support sharing emoji packs"}) | ||||
end | end | ||||
end | end | ||||
def list(conn, _params) do | |||||
def index(conn, _params) do | |||||
emoji_path = | emoji_path = | ||||
Path.join( | |||||
Pleroma.Config.get!([:instance, :static_dir]), | |||||
"emoji" | |||||
) | |||||
[:instance, :static_dir] | |||||
|> Pleroma.Config.get!() | |||||
|> Path.join("emoji") | |||||
with {:ok, packs} <- Pack.list_local() do | with {:ok, packs} <- Pack.list_local() do | ||||
json(conn, packs) | json(conn, packs) | ||||
else | else | ||||
{:create_dir, {:error, e}} -> | |||||
{:error, :create_dir, e} -> | |||||
conn | conn | ||||
|> put_status(:internal_server_error) | |> put_status(:internal_server_error) | ||||
|> json(%{error: "Failed to create the emoji pack directory at #{emoji_path}: #{e}"}) | |> json(%{error: "Failed to create the emoji pack directory at #{emoji_path}: #{e}"}) | ||||
{:ls, {:error, e}} -> | |||||
{:error, :ls, e} -> | |||||
conn | conn | ||||
|> put_status(:internal_server_error) | |> put_status(:internal_server_error) | ||||
|> json(%{ | |> json(%{ | ||||
@@ -60,13 +60,13 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIController do | |||||
end | end | ||||
end | end | ||||
def show(conn, %{"name" => name}) do | |||||
def show(conn, %{name: name}) do | |||||
name = String.trim(name) | name = String.trim(name) | ||||
with {:ok, pack} <- Pack.show(name) do | with {:ok, pack} <- Pack.show(name) do | ||||
json(conn, pack) | json(conn, pack) | ||||
else | else | ||||
{:loaded, _} -> | |||||
{:error, :not_found} -> | |||||
conn | conn | ||||
|> put_status(:not_found) | |> put_status(:not_found) | ||||
|> json(%{error: "Pack #{name} does not exist"}) | |> json(%{error: "Pack #{name} does not exist"}) | ||||
@@ -78,11 +78,11 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIController do | |||||
end | end | ||||
end | end | ||||
def archive(conn, %{"name" => name}) do | |||||
def archive(conn, %{name: name}) do | |||||
with {:ok, archive} <- Pack.get_archive(name) do | with {:ok, archive} <- Pack.get_archive(name) do | ||||
send_download(conn, {:binary, archive}, filename: "#{name}.zip") | send_download(conn, {:binary, archive}, filename: "#{name}.zip") | ||||
else | else | ||||
{:can_download?, _} -> | |||||
{:error, :cant_download} -> | |||||
conn | conn | ||||
|> put_status(:forbidden) | |> put_status(:forbidden) | ||||
|> json(%{ | |> json(%{ | ||||
@@ -90,23 +90,23 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIController do | |||||
"Pack #{name} cannot be downloaded from this instance, either pack sharing was disabled for this pack or some files are missing" | "Pack #{name} cannot be downloaded from this instance, either pack sharing was disabled for this pack or some files are missing" | ||||
}) | }) | ||||
{:exists?, _} -> | |||||
{:error, :not_found} -> | |||||
conn | conn | ||||
|> put_status(:not_found) | |> put_status(:not_found) | ||||
|> json(%{error: "Pack #{name} does not exist"}) | |> json(%{error: "Pack #{name} does not exist"}) | ||||
end | end | ||||
end | end | ||||
def download(conn, %{"url" => url, "name" => name} = params) do | |||||
with :ok <- Pack.download(name, url, params["as"]) do | |||||
def download(%{body_params: %{url: url, name: name} = params} = conn, _) do | |||||
with {:ok, _pack} <- Pack.download(name, url, params[:as]) do | |||||
json(conn, "ok") | json(conn, "ok") | ||||
else | else | ||||
{:shareable, _} -> | |||||
{:error, :not_shareable} -> | |||||
conn | conn | ||||
|> put_status(:internal_server_error) | |> put_status(:internal_server_error) | ||||
|> json(%{error: "The requested instance does not support sharing emoji packs"}) | |> json(%{error: "The requested instance does not support sharing emoji packs"}) | ||||
{:checksum, _} -> | |||||
{:error, :imvalid_checksum} -> | |||||
conn | conn | ||||
|> put_status(:internal_server_error) | |> put_status(:internal_server_error) | ||||
|> json(%{error: "SHA256 for the pack doesn't match the one sent by the server"}) | |> json(%{error: "SHA256 for the pack doesn't match the one sent by the server"}) | ||||
@@ -118,10 +118,10 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIController do | |||||
end | end | ||||
end | end | ||||
def create(conn, %{"name" => name}) do | |||||
def create(conn, %{name: name}) do | |||||
name = String.trim(name) | name = String.trim(name) | ||||
with :ok <- Pack.create(name) do | |||||
with {:ok, _pack} <- Pack.create(name) do | |||||
json(conn, "ok") | json(conn, "ok") | ||||
else | else | ||||
{:error, :eexist} -> | {:error, :eexist} -> | ||||
@@ -143,7 +143,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIController do | |||||
end | end | ||||
end | end | ||||
def delete(conn, %{"name" => name}) do | |||||
def delete(conn, %{name: name}) do | |||||
name = String.trim(name) | name = String.trim(name) | ||||
with {:ok, deleted} when deleted != [] <- Pack.delete(name) do | with {:ok, deleted} when deleted != [] <- Pack.delete(name) do | ||||
@@ -166,11 +166,11 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIController do | |||||
end | end | ||||
end | end | ||||
def update(conn, %{"name" => name, "metadata" => metadata}) do | |||||
def update(%{body_params: %{metadata: metadata}} = conn, %{name: name}) do | |||||
with {:ok, pack} <- Pack.update_metadata(name, metadata) do | with {:ok, pack} <- Pack.update_metadata(name, metadata) do | ||||
json(conn, pack.pack) | json(conn, pack.pack) | ||||
else | else | ||||
{:has_all_files?, _} -> | |||||
{:error, :incomplete} -> | |||||
conn | conn | ||||
|> put_status(:bad_request) | |> put_status(:bad_request) | ||||
|> json(%{error: "The fallback archive does not have all files specified in pack.json"}) | |> json(%{error: "The fallback archive does not have all files specified in pack.json"}) | ||||
@@ -184,19 +184,19 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIController do | |||||
end | end | ||||
end | end | ||||
def add_file(conn, %{"name" => name} = params) do | |||||
filename = params["filename"] || get_filename(params["file"]) | |||||
shortcode = params["shortcode"] || Path.basename(filename, Path.extname(filename)) | |||||
def add_file(%{body_params: params} = conn, %{name: name}) do | |||||
filename = params[:filename] || get_filename(params[:file]) | |||||
shortcode = params[:shortcode] || Path.basename(filename, Path.extname(filename)) | |||||
with {:ok, pack} <- Pack.add_file(name, shortcode, filename, params["file"]) do | |||||
with {:ok, pack} <- Pack.add_file(name, shortcode, filename, params[:file]) do | |||||
json(conn, pack.files) | json(conn, pack.files) | ||||
else | else | ||||
{:exists, _} -> | |||||
{:error, :already_exists} -> | |||||
conn | conn | ||||
|> put_status(:conflict) | |> put_status(:conflict) | ||||
|> json(%{error: "An emoji with the \"#{shortcode}\" shortcode already exists"}) | |> json(%{error: "An emoji with the \"#{shortcode}\" shortcode already exists"}) | ||||
{:loaded, _} -> | |||||
{:error, :not_found} -> | |||||
conn | conn | ||||
|> put_status(:bad_request) | |> put_status(:bad_request) | ||||
|> json(%{error: "pack \"#{name}\" is not found"}) | |> json(%{error: "pack \"#{name}\" is not found"}) | ||||
@@ -215,20 +215,20 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIController do | |||||
end | end | ||||
end | end | ||||
def update_file(conn, %{"name" => name, "shortcode" => shortcode} = params) do | |||||
new_shortcode = params["new_shortcode"] | |||||
new_filename = params["new_filename"] | |||||
force = params["force"] == true | |||||
def update_file(%{body_params: %{shortcode: shortcode} = params} = conn, %{name: name}) do | |||||
new_shortcode = params[:new_shortcode] | |||||
new_filename = params[:new_filename] | |||||
force = params[:force] | |||||
with {:ok, pack} <- Pack.update_file(name, shortcode, new_shortcode, new_filename, force) do | with {:ok, pack} <- Pack.update_file(name, shortcode, new_shortcode, new_filename, force) do | ||||
json(conn, pack.files) | json(conn, pack.files) | ||||
else | else | ||||
{:exists, _} -> | |||||
{:error, :doesnt_exist} -> | |||||
conn | conn | ||||
|> put_status(:bad_request) | |> put_status(:bad_request) | ||||
|> json(%{error: "Emoji \"#{shortcode}\" does not exist"}) | |> json(%{error: "Emoji \"#{shortcode}\" does not exist"}) | ||||
{:not_used, _} -> | |||||
{:error, :already_exists} -> | |||||
conn | conn | ||||
|> put_status(:conflict) | |> put_status(:conflict) | ||||
|> json(%{ | |> json(%{ | ||||
@@ -236,7 +236,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIController do | |||||
"New shortcode \"#{new_shortcode}\" is already used. If you want to override emoji use 'force' option" | "New shortcode \"#{new_shortcode}\" is already used. If you want to override emoji use 'force' option" | ||||
}) | }) | ||||
{:loaded, _} -> | |||||
{:error, :not_found} -> | |||||
conn | conn | ||||
|> put_status(:bad_request) | |> put_status(:bad_request) | ||||
|> json(%{error: "pack \"#{name}\" is not found"}) | |> json(%{error: "pack \"#{name}\" is not found"}) | ||||
@@ -255,16 +255,16 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIController do | |||||
end | end | ||||
end | end | ||||
def delete_file(conn, %{"name" => name, "shortcode" => shortcode}) do | |||||
def delete_file(conn, %{name: name, shortcode: shortcode}) do | |||||
with {:ok, pack} <- Pack.delete_file(name, shortcode) do | with {:ok, pack} <- Pack.delete_file(name, shortcode) do | ||||
json(conn, pack.files) | json(conn, pack.files) | ||||
else | else | ||||
{:exists, _} -> | |||||
{:error, :doesnt_exist} -> | |||||
conn | conn | ||||
|> put_status(:bad_request) | |> put_status(:bad_request) | ||||
|> json(%{error: "Emoji \"#{shortcode}\" does not exist"}) | |> json(%{error: "Emoji \"#{shortcode}\" does not exist"}) | ||||
{:loaded, _} -> | |||||
{:error, :not_found} -> | |||||
conn | conn | ||||
|> put_status(:bad_request) | |> put_status(:bad_request) | ||||
|> json(%{error: "pack \"#{name}\" is not found"}) | |> json(%{error: "pack \"#{name}\" is not found"}) |
@@ -216,24 +216,25 @@ defmodule Pleroma.Web.Router do | |||||
scope "/packs" do | scope "/packs" do | ||||
pipe_through(:admin_api) | pipe_through(:admin_api) | ||||
get("/import", EmojiAPIController, :import_from_filesystem) | |||||
get("/remote", EmojiAPIController, :remote) | |||||
post("/download", EmojiAPIController, :download) | |||||
get("/import", EmojiPackController, :import_from_filesystem) | |||||
get("/remote", EmojiPackController, :remote) | |||||
post("/download", EmojiPackController, :download) | |||||
post("/:name", EmojiAPIController, :create) | |||||
patch("/:name", EmojiAPIController, :update) | |||||
delete("/:name", EmojiAPIController, :delete) | |||||
post("/:name", EmojiPackController, :create) | |||||
patch("/:name", EmojiPackController, :update) | |||||
delete("/:name", EmojiPackController, :delete) | |||||
post("/:name/files", EmojiAPIController, :add_file) | |||||
patch("/:name/files", EmojiAPIController, :update_file) | |||||
delete("/:name/files", EmojiAPIController, :delete_file) | |||||
post("/:name/files", EmojiPackController, :add_file) | |||||
patch("/:name/files", EmojiPackController, :update_file) | |||||
delete("/:name/files", EmojiPackController, :delete_file) | |||||
end | end | ||||
# Pack info / downloading | # Pack info / downloading | ||||
scope "/packs" do | scope "/packs" do | ||||
get("/", EmojiAPIController, :list) | |||||
get("/:name", EmojiAPIController, :show) | |||||
get("/:name/archive", EmojiAPIController, :archive) | |||||
pipe_through(:api) | |||||
get("/", EmojiPackController, :index) | |||||
get("/:name", EmojiPackController, :show) | |||||
get("/:name/archive", EmojiPackController, :archive) | |||||
end | end | ||||
end | end | ||||
@@ -28,7 +28,7 @@ defmodule Pleroma.Web.ApiSpec.SchemaExamplesTest do | |||||
end | end | ||||
end | end | ||||
for {status, response} <- operation.responses do | |||||
for {status, response} <- operation.responses, is_map(response.content[@content_type]) do | |||||
describe "#{operation.operationId} - #{status} Response" do | describe "#{operation.operationId} - #{status} Response" do | ||||
@schema resolve_schema(response.content[@content_type].schema) | @schema resolve_schema(response.content[@content_type].schema) | ||||
@@ -2,7 +2,7 @@ | |||||
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> | # Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> | ||||
# SPDX-License-Identifier: AGPL-3.0-only | # SPDX-License-Identifier: AGPL-3.0-only | ||||
defmodule Pleroma.Web.PleromaAPI.EmojiAPIControllerTest do | |||||
defmodule Pleroma.Web.PleromaAPI.EmojiPackControllerTest do | |||||
use Pleroma.Web.ConnCase | use Pleroma.Web.ConnCase | ||||
import Tesla.Mock | import Tesla.Mock | ||||
@@ -28,7 +28,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIControllerTest do | |||||
end | end | ||||
test "GET /api/pleroma/emoji/packs", %{conn: conn} do | test "GET /api/pleroma/emoji/packs", %{conn: conn} do | ||||
resp = conn |> get("/api/pleroma/emoji/packs") |> json_response(200) | |||||
resp = conn |> get("/api/pleroma/emoji/packs") |> json_response_and_validate_schema(200) | |||||
shared = resp["test_pack"] | shared = resp["test_pack"] | ||||
assert shared["files"] == %{"blank" => "blank.png"} | assert shared["files"] == %{"blank" => "blank.png"} | ||||
@@ -46,7 +46,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIControllerTest do | |||||
resp = | resp = | ||||
conn | conn | ||||
|> get("/api/pleroma/emoji/packs") | |> get("/api/pleroma/emoji/packs") | ||||
|> json_response(200) | |||||
|> json_response_and_validate_schema(200) | |||||
mock(fn | mock(fn | ||||
%{method: :get, url: "https://example.com/.well-known/nodeinfo"} -> | %{method: :get, url: "https://example.com/.well-known/nodeinfo"} -> | ||||
@@ -60,10 +60,8 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIControllerTest do | |||||
end) | end) | ||||
assert admin_conn | assert admin_conn | ||||
|> get("/api/pleroma/emoji/packs/remote", %{ | |||||
url: "https://example.com" | |||||
}) | |||||
|> json_response(200) == resp | |||||
|> get("/api/pleroma/emoji/packs/remote?url=https://example.com") | |||||
|> json_response_and_validate_schema(200) == resp | |||||
end | end | ||||
test "non shareable instance", %{admin_conn: admin_conn} do | test "non shareable instance", %{admin_conn: admin_conn} do | ||||
@@ -76,8 +74,8 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIControllerTest do | |||||
end) | end) | ||||
assert admin_conn | assert admin_conn | ||||
|> get("/api/pleroma/emoji/packs/remote", %{url: "https://example.com"}) | |||||
|> json_response(500) == %{ | |||||
|> get("/api/pleroma/emoji/packs/remote?url=https://example.com") | |||||
|> json_response_and_validate_schema(500) == %{ | |||||
"error" => "The requested instance does not support sharing emoji packs" | "error" => "The requested instance does not support sharing emoji packs" | ||||
} | } | ||||
end | end | ||||
@@ -99,7 +97,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIControllerTest do | |||||
test "non existing pack", %{conn: conn} do | test "non existing pack", %{conn: conn} do | ||||
assert conn | assert conn | ||||
|> get("/api/pleroma/emoji/packs/test_pack_for_import/archive") | |> get("/api/pleroma/emoji/packs/test_pack_for_import/archive") | ||||
|> json_response(:not_found) == %{ | |||||
|> json_response_and_validate_schema(:not_found) == %{ | |||||
"error" => "Pack test_pack_for_import does not exist" | "error" => "Pack test_pack_for_import does not exist" | ||||
} | } | ||||
end | end | ||||
@@ -107,7 +105,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIControllerTest do | |||||
test "non downloadable pack", %{conn: conn} do | test "non downloadable pack", %{conn: conn} do | ||||
assert conn | assert conn | ||||
|> get("/api/pleroma/emoji/packs/test_pack_nonshared/archive") | |> get("/api/pleroma/emoji/packs/test_pack_nonshared/archive") | ||||
|> json_response(:forbidden) == %{ | |||||
|> json_response_and_validate_schema(:forbidden) == %{ | |||||
"error" => | "error" => | ||||
"Pack test_pack_nonshared cannot be downloaded from this instance, either pack sharing was disabled for this pack or some files are missing" | "Pack test_pack_nonshared cannot be downloaded from this instance, either pack sharing was disabled for this pack or some files are missing" | ||||
} | } | ||||
@@ -132,7 +130,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIControllerTest do | |||||
} -> | } -> | ||||
conn | conn | ||||
|> get("/api/pleroma/emoji/packs/test_pack") | |> get("/api/pleroma/emoji/packs/test_pack") | ||||
|> json_response(200) | |||||
|> json_response_and_validate_schema(200) | |||||
|> json() | |> json() | ||||
%{ | %{ | ||||
@@ -150,7 +148,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIControllerTest do | |||||
} -> | } -> | ||||
conn | conn | ||||
|> get("/api/pleroma/emoji/packs/test_pack_nonshared") | |> get("/api/pleroma/emoji/packs/test_pack_nonshared") | ||||
|> json_response(200) | |||||
|> json_response_and_validate_schema(200) | |||||
|> json() | |> json() | ||||
%{ | %{ | ||||
@@ -161,23 +159,25 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIControllerTest do | |||||
end) | end) | ||||
assert admin_conn | assert admin_conn | ||||
|> put_req_header("content-type", "multipart/form-data") | |||||
|> post("/api/pleroma/emoji/packs/download", %{ | |> post("/api/pleroma/emoji/packs/download", %{ | ||||
url: "https://example.com", | url: "https://example.com", | ||||
name: "test_pack", | name: "test_pack", | ||||
as: "test_pack2" | as: "test_pack2" | ||||
}) | }) | ||||
|> json_response(200) == "ok" | |||||
|> json_response_and_validate_schema(200) == "ok" | |||||
assert File.exists?("#{@emoji_path}/test_pack2/pack.json") | assert File.exists?("#{@emoji_path}/test_pack2/pack.json") | ||||
assert File.exists?("#{@emoji_path}/test_pack2/blank.png") | assert File.exists?("#{@emoji_path}/test_pack2/blank.png") | ||||
assert admin_conn | assert admin_conn | ||||
|> delete("/api/pleroma/emoji/packs/test_pack2") | |> delete("/api/pleroma/emoji/packs/test_pack2") | ||||
|> json_response(200) == "ok" | |||||
|> json_response_and_validate_schema(200) == "ok" | |||||
refute File.exists?("#{@emoji_path}/test_pack2") | refute File.exists?("#{@emoji_path}/test_pack2") | ||||
assert admin_conn | assert admin_conn | ||||
|> put_req_header("content-type", "multipart/form-data") | |||||
|> post( | |> post( | ||||
"/api/pleroma/emoji/packs/download", | "/api/pleroma/emoji/packs/download", | ||||
%{ | %{ | ||||
@@ -186,14 +186,14 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIControllerTest do | |||||
as: "test_pack_nonshared2" | as: "test_pack_nonshared2" | ||||
} | } | ||||
) | ) | ||||
|> json_response(200) == "ok" | |||||
|> json_response_and_validate_schema(200) == "ok" | |||||
assert File.exists?("#{@emoji_path}/test_pack_nonshared2/pack.json") | assert File.exists?("#{@emoji_path}/test_pack_nonshared2/pack.json") | ||||
assert File.exists?("#{@emoji_path}/test_pack_nonshared2/blank.png") | assert File.exists?("#{@emoji_path}/test_pack_nonshared2/blank.png") | ||||
assert admin_conn | assert admin_conn | ||||
|> delete("/api/pleroma/emoji/packs/test_pack_nonshared2") | |> delete("/api/pleroma/emoji/packs/test_pack_nonshared2") | ||||
|> json_response(200) == "ok" | |||||
|> json_response_and_validate_schema(200) == "ok" | |||||
refute File.exists?("#{@emoji_path}/test_pack_nonshared2") | refute File.exists?("#{@emoji_path}/test_pack_nonshared2") | ||||
end | end | ||||
@@ -208,6 +208,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIControllerTest do | |||||
end) | end) | ||||
assert admin_conn | assert admin_conn | ||||
|> put_req_header("content-type", "multipart/form-data") | |||||
|> post( | |> post( | ||||
"/api/pleroma/emoji/packs/download", | "/api/pleroma/emoji/packs/download", | ||||
%{ | %{ | ||||
@@ -216,7 +217,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIControllerTest do | |||||
as: "test_pack2" | as: "test_pack2" | ||||
} | } | ||||
) | ) | ||||
|> json_response(500) == %{ | |||||
|> json_response_and_validate_schema(500) == %{ | |||||
"error" => "The requested instance does not support sharing emoji packs" | "error" => "The requested instance does not support sharing emoji packs" | ||||
} | } | ||||
end | end | ||||
@@ -233,10 +234,8 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIControllerTest do | |||||
method: :get, | method: :get, | ||||
url: "https://example.com/api/pleroma/emoji/packs/pack_bad_sha" | url: "https://example.com/api/pleroma/emoji/packs/pack_bad_sha" | ||||
} -> | } -> | ||||
%Tesla.Env{ | |||||
status: 200, | |||||
body: Pleroma.Emoji.Pack.load_pack("pack_bad_sha") |> Jason.encode!() | |||||
} | |||||
{:ok, pack} = Pleroma.Emoji.Pack.load_pack("pack_bad_sha") | |||||
%Tesla.Env{status: 200, body: Jason.encode!(pack)} | |||||
%{ | %{ | ||||
method: :get, | method: :get, | ||||
@@ -249,12 +248,13 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIControllerTest do | |||||
end) | end) | ||||
assert admin_conn | assert admin_conn | ||||
|> put_req_header("content-type", "multipart/form-data") | |||||
|> post("/api/pleroma/emoji/packs/download", %{ | |> post("/api/pleroma/emoji/packs/download", %{ | ||||
url: "https://example.com", | url: "https://example.com", | ||||
name: "pack_bad_sha", | name: "pack_bad_sha", | ||||
as: "pack_bad_sha2" | as: "pack_bad_sha2" | ||||
}) | }) | ||||
|> json_response(:internal_server_error) == %{ | |||||
|> json_response_and_validate_schema(:internal_server_error) == %{ | |||||
"error" => "SHA256 for the pack doesn't match the one sent by the server" | "error" => "SHA256 for the pack doesn't match the one sent by the server" | ||||
} | } | ||||
end | end | ||||
@@ -271,19 +271,18 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIControllerTest do | |||||
method: :get, | method: :get, | ||||
url: "https://example.com/api/pleroma/emoji/packs/test_pack" | url: "https://example.com/api/pleroma/emoji/packs/test_pack" | ||||
} -> | } -> | ||||
%Tesla.Env{ | |||||
status: 200, | |||||
body: Pleroma.Emoji.Pack.load_pack("test_pack") |> Jason.encode!() | |||||
} | |||||
{:ok, pack} = Pleroma.Emoji.Pack.load_pack("test_pack") | |||||
%Tesla.Env{status: 200, body: Jason.encode!(pack)} | |||||
end) | end) | ||||
assert admin_conn | assert admin_conn | ||||
|> put_req_header("content-type", "multipart/form-data") | |||||
|> post("/api/pleroma/emoji/packs/download", %{ | |> post("/api/pleroma/emoji/packs/download", %{ | ||||
url: "https://example.com", | url: "https://example.com", | ||||
name: "test_pack", | name: "test_pack", | ||||
as: "test_pack2" | as: "test_pack2" | ||||
}) | }) | ||||
|> json_response(:internal_server_error) == %{ | |||||
|> json_response_and_validate_schema(:internal_server_error) == %{ | |||||
"error" => | "error" => | ||||
"The pack was not set as shared and there is no fallback src to download from" | "The pack was not set as shared and there is no fallback src to download from" | ||||
} | } | ||||
@@ -311,8 +310,9 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIControllerTest do | |||||
test "for a pack without a fallback source", ctx do | test "for a pack without a fallback source", ctx do | ||||
assert ctx[:admin_conn] | assert ctx[:admin_conn] | ||||
|> put_req_header("content-type", "multipart/form-data") | |||||
|> patch("/api/pleroma/emoji/packs/test_pack", %{"metadata" => ctx[:new_data]}) | |> patch("/api/pleroma/emoji/packs/test_pack", %{"metadata" => ctx[:new_data]}) | ||||
|> json_response(200) == ctx[:new_data] | |||||
|> json_response_and_validate_schema(200) == ctx[:new_data] | |||||
assert Jason.decode!(File.read!(ctx[:pack_file]))["pack"] == ctx[:new_data] | assert Jason.decode!(File.read!(ctx[:pack_file]))["pack"] == ctx[:new_data] | ||||
end | end | ||||
@@ -336,8 +336,9 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIControllerTest do | |||||
) | ) | ||||
assert ctx[:admin_conn] | assert ctx[:admin_conn] | ||||
|> put_req_header("content-type", "multipart/form-data") | |||||
|> patch("/api/pleroma/emoji/packs/test_pack", %{metadata: new_data}) | |> patch("/api/pleroma/emoji/packs/test_pack", %{metadata: new_data}) | ||||
|> json_response(200) == new_data_with_sha | |||||
|> json_response_and_validate_schema(200) == new_data_with_sha | |||||
assert Jason.decode!(File.read!(ctx[:pack_file]))["pack"] == new_data_with_sha | assert Jason.decode!(File.read!(ctx[:pack_file]))["pack"] == new_data_with_sha | ||||
end | end | ||||
@@ -355,8 +356,9 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIControllerTest do | |||||
new_data = Map.put(ctx[:new_data], "fallback-src", "https://nonshared-pack") | new_data = Map.put(ctx[:new_data], "fallback-src", "https://nonshared-pack") | ||||
assert ctx[:admin_conn] | assert ctx[:admin_conn] | ||||
|> put_req_header("content-type", "multipart/form-data") | |||||
|> patch("/api/pleroma/emoji/packs/test_pack", %{metadata: new_data}) | |> patch("/api/pleroma/emoji/packs/test_pack", %{metadata: new_data}) | ||||
|> json_response(:bad_request) == %{ | |||||
|> json_response_and_validate_schema(:bad_request) == %{ | |||||
"error" => "The fallback archive does not have all files specified in pack.json" | "error" => "The fallback archive does not have all files specified in pack.json" | ||||
} | } | ||||
end | end | ||||
@@ -376,6 +378,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIControllerTest do | |||||
test "create shortcode exists", %{admin_conn: admin_conn} do | test "create shortcode exists", %{admin_conn: admin_conn} do | ||||
assert admin_conn | assert admin_conn | ||||
|> put_req_header("content-type", "multipart/form-data") | |||||
|> post("/api/pleroma/emoji/packs/test_pack/files", %{ | |> post("/api/pleroma/emoji/packs/test_pack/files", %{ | ||||
shortcode: "blank", | shortcode: "blank", | ||||
filename: "dir/blank.png", | filename: "dir/blank.png", | ||||
@@ -384,7 +387,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIControllerTest do | |||||
path: "#{@emoji_path}/test_pack/blank.png" | path: "#{@emoji_path}/test_pack/blank.png" | ||||
} | } | ||||
}) | }) | ||||
|> json_response(:conflict) == %{ | |||||
|> json_response_and_validate_schema(:conflict) == %{ | |||||
"error" => "An emoji with the \"blank\" shortcode already exists" | "error" => "An emoji with the \"blank\" shortcode already exists" | ||||
} | } | ||||
end | end | ||||
@@ -393,6 +396,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIControllerTest do | |||||
on_exit(fn -> File.rm_rf!("#{@emoji_path}/test_pack/dir/") end) | on_exit(fn -> File.rm_rf!("#{@emoji_path}/test_pack/dir/") end) | ||||
assert admin_conn | assert admin_conn | ||||
|> put_req_header("content-type", "multipart/form-data") | |||||
|> post("/api/pleroma/emoji/packs/test_pack/files", %{ | |> post("/api/pleroma/emoji/packs/test_pack/files", %{ | ||||
shortcode: "blank2", | shortcode: "blank2", | ||||
filename: "dir/blank.png", | filename: "dir/blank.png", | ||||
@@ -401,17 +405,21 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIControllerTest do | |||||
path: "#{@emoji_path}/test_pack/blank.png" | path: "#{@emoji_path}/test_pack/blank.png" | ||||
} | } | ||||
}) | }) | ||||
|> json_response(200) == %{"blank" => "blank.png", "blank2" => "dir/blank.png"} | |||||
|> json_response_and_validate_schema(200) == %{ | |||||
"blank" => "blank.png", | |||||
"blank2" => "dir/blank.png" | |||||
} | |||||
assert File.exists?("#{@emoji_path}/test_pack/dir/blank.png") | assert File.exists?("#{@emoji_path}/test_pack/dir/blank.png") | ||||
assert admin_conn | assert admin_conn | ||||
|> put_req_header("content-type", "multipart/form-data") | |||||
|> patch("/api/pleroma/emoji/packs/test_pack/files", %{ | |> patch("/api/pleroma/emoji/packs/test_pack/files", %{ | ||||
shortcode: "blank", | shortcode: "blank", | ||||
new_shortcode: "blank2", | new_shortcode: "blank2", | ||||
new_filename: "dir_2/blank_3.png" | new_filename: "dir_2/blank_3.png" | ||||
}) | }) | ||||
|> json_response(:conflict) == %{ | |||||
|> json_response_and_validate_schema(:conflict) == %{ | |||||
"error" => | "error" => | ||||
"New shortcode \"blank2\" is already used. If you want to override emoji use 'force' option" | "New shortcode \"blank2\" is already used. If you want to override emoji use 'force' option" | ||||
} | } | ||||
@@ -421,6 +429,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIControllerTest do | |||||
on_exit(fn -> File.rm_rf!("#{@emoji_path}/test_pack/dir_2/") end) | on_exit(fn -> File.rm_rf!("#{@emoji_path}/test_pack/dir_2/") end) | ||||
assert admin_conn | assert admin_conn | ||||
|> put_req_header("content-type", "multipart/form-data") | |||||
|> post("/api/pleroma/emoji/packs/test_pack/files", %{ | |> post("/api/pleroma/emoji/packs/test_pack/files", %{ | ||||
shortcode: "blank2", | shortcode: "blank2", | ||||
filename: "dir/blank.png", | filename: "dir/blank.png", | ||||
@@ -429,18 +438,22 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIControllerTest do | |||||
path: "#{@emoji_path}/test_pack/blank.png" | path: "#{@emoji_path}/test_pack/blank.png" | ||||
} | } | ||||
}) | }) | ||||
|> json_response(200) == %{"blank" => "blank.png", "blank2" => "dir/blank.png"} | |||||
|> json_response_and_validate_schema(200) == %{ | |||||
"blank" => "blank.png", | |||||
"blank2" => "dir/blank.png" | |||||
} | |||||
assert File.exists?("#{@emoji_path}/test_pack/dir/blank.png") | assert File.exists?("#{@emoji_path}/test_pack/dir/blank.png") | ||||
assert admin_conn | assert admin_conn | ||||
|> put_req_header("content-type", "multipart/form-data") | |||||
|> patch("/api/pleroma/emoji/packs/test_pack/files", %{ | |> patch("/api/pleroma/emoji/packs/test_pack/files", %{ | ||||
shortcode: "blank2", | shortcode: "blank2", | ||||
new_shortcode: "blank3", | new_shortcode: "blank3", | ||||
new_filename: "dir_2/blank_3.png", | new_filename: "dir_2/blank_3.png", | ||||
force: true | force: true | ||||
}) | }) | ||||
|> json_response(200) == %{ | |||||
|> json_response_and_validate_schema(200) == %{ | |||||
"blank" => "blank.png", | "blank" => "blank.png", | ||||
"blank3" => "dir_2/blank_3.png" | "blank3" => "dir_2/blank_3.png" | ||||
} | } | ||||
@@ -450,6 +463,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIControllerTest do | |||||
test "with empty filename", %{admin_conn: admin_conn} do | test "with empty filename", %{admin_conn: admin_conn} do | ||||
assert admin_conn | assert admin_conn | ||||
|> put_req_header("content-type", "multipart/form-data") | |||||
|> post("/api/pleroma/emoji/packs/test_pack/files", %{ | |> post("/api/pleroma/emoji/packs/test_pack/files", %{ | ||||
shortcode: "blank2", | shortcode: "blank2", | ||||
filename: "", | filename: "", | ||||
@@ -458,13 +472,14 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIControllerTest do | |||||
path: "#{@emoji_path}/test_pack/blank.png" | path: "#{@emoji_path}/test_pack/blank.png" | ||||
} | } | ||||
}) | }) | ||||
|> json_response(:bad_request) == %{ | |||||
|> json_response_and_validate_schema(:bad_request) == %{ | |||||
"error" => "pack name, shortcode or filename cannot be empty" | "error" => "pack name, shortcode or filename cannot be empty" | ||||
} | } | ||||
end | end | ||||
test "add file with not loaded pack", %{admin_conn: admin_conn} do | test "add file with not loaded pack", %{admin_conn: admin_conn} do | ||||
assert admin_conn | assert admin_conn | ||||
|> put_req_header("content-type", "multipart/form-data") | |||||
|> post("/api/pleroma/emoji/packs/not_loaded/files", %{ | |> post("/api/pleroma/emoji/packs/not_loaded/files", %{ | ||||
shortcode: "blank2", | shortcode: "blank2", | ||||
filename: "dir/blank.png", | filename: "dir/blank.png", | ||||
@@ -473,37 +488,43 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIControllerTest do | |||||
path: "#{@emoji_path}/test_pack/blank.png" | path: "#{@emoji_path}/test_pack/blank.png" | ||||
} | } | ||||
}) | }) | ||||
|> json_response(:bad_request) == %{ | |||||
|> json_response_and_validate_schema(:bad_request) == %{ | |||||
"error" => "pack \"not_loaded\" is not found" | "error" => "pack \"not_loaded\" is not found" | ||||
} | } | ||||
end | end | ||||
test "remove file with not loaded pack", %{admin_conn: admin_conn} do | test "remove file with not loaded pack", %{admin_conn: admin_conn} do | ||||
assert admin_conn | assert admin_conn | ||||
|> delete("/api/pleroma/emoji/packs/not_loaded/files", %{shortcode: "blank3"}) | |||||
|> json_response(:bad_request) == %{"error" => "pack \"not_loaded\" is not found"} | |||||
|> delete("/api/pleroma/emoji/packs/not_loaded/files?shortcode=blank3") | |||||
|> json_response_and_validate_schema(:bad_request) == %{ | |||||
"error" => "pack \"not_loaded\" is not found" | |||||
} | |||||
end | end | ||||
test "remove file with empty shortcode", %{admin_conn: admin_conn} do | test "remove file with empty shortcode", %{admin_conn: admin_conn} do | ||||
assert admin_conn | assert admin_conn | ||||
|> delete("/api/pleroma/emoji/packs/not_loaded/files", %{shortcode: ""}) | |||||
|> json_response(:bad_request) == %{ | |||||
|> delete("/api/pleroma/emoji/packs/not_loaded/files?shortcode=") | |||||
|> json_response_and_validate_schema(:bad_request) == %{ | |||||
"error" => "pack name or shortcode cannot be empty" | "error" => "pack name or shortcode cannot be empty" | ||||
} | } | ||||
end | end | ||||
test "update file with not loaded pack", %{admin_conn: admin_conn} do | test "update file with not loaded pack", %{admin_conn: admin_conn} do | ||||
assert admin_conn | assert admin_conn | ||||
|> put_req_header("content-type", "multipart/form-data") | |||||
|> patch("/api/pleroma/emoji/packs/not_loaded/files", %{ | |> patch("/api/pleroma/emoji/packs/not_loaded/files", %{ | ||||
shortcode: "blank4", | shortcode: "blank4", | ||||
new_shortcode: "blank3", | new_shortcode: "blank3", | ||||
new_filename: "dir_2/blank_3.png" | new_filename: "dir_2/blank_3.png" | ||||
}) | }) | ||||
|> json_response(:bad_request) == %{"error" => "pack \"not_loaded\" is not found"} | |||||
|> json_response_and_validate_schema(:bad_request) == %{ | |||||
"error" => "pack \"not_loaded\" is not found" | |||||
} | |||||
end | end | ||||
test "new with shortcode as file with update", %{admin_conn: admin_conn} do | test "new with shortcode as file with update", %{admin_conn: admin_conn} do | ||||
assert admin_conn | assert admin_conn | ||||
|> put_req_header("content-type", "multipart/form-data") | |||||
|> post("/api/pleroma/emoji/packs/test_pack/files", %{ | |> post("/api/pleroma/emoji/packs/test_pack/files", %{ | ||||
shortcode: "blank4", | shortcode: "blank4", | ||||
filename: "dir/blank.png", | filename: "dir/blank.png", | ||||
@@ -512,24 +533,31 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIControllerTest do | |||||
path: "#{@emoji_path}/test_pack/blank.png" | path: "#{@emoji_path}/test_pack/blank.png" | ||||
} | } | ||||
}) | }) | ||||
|> json_response(200) == %{"blank" => "blank.png", "blank4" => "dir/blank.png"} | |||||
|> json_response_and_validate_schema(200) == %{ | |||||
"blank" => "blank.png", | |||||
"blank4" => "dir/blank.png" | |||||
} | |||||
assert File.exists?("#{@emoji_path}/test_pack/dir/blank.png") | assert File.exists?("#{@emoji_path}/test_pack/dir/blank.png") | ||||
assert admin_conn | assert admin_conn | ||||
|> put_req_header("content-type", "multipart/form-data") | |||||
|> patch("/api/pleroma/emoji/packs/test_pack/files", %{ | |> patch("/api/pleroma/emoji/packs/test_pack/files", %{ | ||||
shortcode: "blank4", | shortcode: "blank4", | ||||
new_shortcode: "blank3", | new_shortcode: "blank3", | ||||
new_filename: "dir_2/blank_3.png" | new_filename: "dir_2/blank_3.png" | ||||
}) | }) | ||||
|> json_response(200) == %{"blank3" => "dir_2/blank_3.png", "blank" => "blank.png"} | |||||
|> json_response_and_validate_schema(200) == %{ | |||||
"blank3" => "dir_2/blank_3.png", | |||||
"blank" => "blank.png" | |||||
} | |||||
refute File.exists?("#{@emoji_path}/test_pack/dir/") | refute File.exists?("#{@emoji_path}/test_pack/dir/") | ||||
assert File.exists?("#{@emoji_path}/test_pack/dir_2/blank_3.png") | assert File.exists?("#{@emoji_path}/test_pack/dir_2/blank_3.png") | ||||
assert admin_conn | assert admin_conn | ||||
|> delete("/api/pleroma/emoji/packs/test_pack/files", %{shortcode: "blank3"}) | |||||
|> json_response(200) == %{"blank" => "blank.png"} | |||||
|> delete("/api/pleroma/emoji/packs/test_pack/files?shortcode=blank3") | |||||
|> json_response_and_validate_schema(200) == %{"blank" => "blank.png"} | |||||
refute File.exists?("#{@emoji_path}/test_pack/dir_2/") | refute File.exists?("#{@emoji_path}/test_pack/dir_2/") | ||||
@@ -546,11 +574,12 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIControllerTest do | |||||
end) | end) | ||||
assert admin_conn | assert admin_conn | ||||
|> put_req_header("content-type", "multipart/form-data") | |||||
|> post("/api/pleroma/emoji/packs/test_pack/files", %{ | |> post("/api/pleroma/emoji/packs/test_pack/files", %{ | ||||
shortcode: "blank_url", | shortcode: "blank_url", | ||||
file: "https://test-blank/blank_url.png" | file: "https://test-blank/blank_url.png" | ||||
}) | }) | ||||
|> json_response(200) == %{ | |||||
|> json_response_and_validate_schema(200) == %{ | |||||
"blank_url" => "blank_url.png", | "blank_url" => "blank_url.png", | ||||
"blank" => "blank.png" | "blank" => "blank.png" | ||||
} | } | ||||
@@ -564,40 +593,51 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIControllerTest do | |||||
on_exit(fn -> File.rm_rf!("#{@emoji_path}/test_pack/shortcode.png") end) | on_exit(fn -> File.rm_rf!("#{@emoji_path}/test_pack/shortcode.png") end) | ||||
assert admin_conn | assert admin_conn | ||||
|> put_req_header("content-type", "multipart/form-data") | |||||
|> post("/api/pleroma/emoji/packs/test_pack/files", %{ | |> post("/api/pleroma/emoji/packs/test_pack/files", %{ | ||||
file: %Plug.Upload{ | file: %Plug.Upload{ | ||||
filename: "shortcode.png", | filename: "shortcode.png", | ||||
path: "#{Pleroma.Config.get([:instance, :static_dir])}/add/shortcode.png" | path: "#{Pleroma.Config.get([:instance, :static_dir])}/add/shortcode.png" | ||||
} | } | ||||
}) | }) | ||||
|> json_response(200) == %{"shortcode" => "shortcode.png", "blank" => "blank.png"} | |||||
|> json_response_and_validate_schema(200) == %{ | |||||
"shortcode" => "shortcode.png", | |||||
"blank" => "blank.png" | |||||
} | |||||
end | end | ||||
test "remove non existing shortcode in pack.json", %{admin_conn: admin_conn} do | test "remove non existing shortcode in pack.json", %{admin_conn: admin_conn} do | ||||
assert admin_conn | assert admin_conn | ||||
|> delete("/api/pleroma/emoji/packs/test_pack/files", %{shortcode: "blank2"}) | |||||
|> json_response(:bad_request) == %{"error" => "Emoji \"blank2\" does not exist"} | |||||
|> delete("/api/pleroma/emoji/packs/test_pack/files?shortcode=blank2") | |||||
|> json_response_and_validate_schema(:bad_request) == %{ | |||||
"error" => "Emoji \"blank2\" does not exist" | |||||
} | |||||
end | end | ||||
test "update non existing emoji", %{admin_conn: admin_conn} do | test "update non existing emoji", %{admin_conn: admin_conn} do | ||||
assert admin_conn | assert admin_conn | ||||
|> put_req_header("content-type", "multipart/form-data") | |||||
|> patch("/api/pleroma/emoji/packs/test_pack/files", %{ | |> patch("/api/pleroma/emoji/packs/test_pack/files", %{ | ||||
shortcode: "blank2", | shortcode: "blank2", | ||||
new_shortcode: "blank3", | new_shortcode: "blank3", | ||||
new_filename: "dir_2/blank_3.png" | new_filename: "dir_2/blank_3.png" | ||||
}) | }) | ||||
|> json_response(:bad_request) == %{"error" => "Emoji \"blank2\" does not exist"} | |||||
|> json_response_and_validate_schema(:bad_request) == %{ | |||||
"error" => "Emoji \"blank2\" does not exist" | |||||
} | |||||
end | end | ||||
test "update with empty shortcode", %{admin_conn: admin_conn} do | test "update with empty shortcode", %{admin_conn: admin_conn} do | ||||
assert admin_conn | |||||
|> patch("/api/pleroma/emoji/packs/test_pack/files", %{ | |||||
shortcode: "blank", | |||||
new_filename: "dir_2/blank_3.png" | |||||
}) | |||||
|> json_response(:bad_request) == %{ | |||||
"error" => "new_shortcode or new_filename cannot be empty" | |||||
} | |||||
assert %{ | |||||
"error" => "Missing field: new_shortcode." | |||||
} = | |||||
admin_conn | |||||
|> put_req_header("content-type", "multipart/form-data") | |||||
|> patch("/api/pleroma/emoji/packs/test_pack/files", %{ | |||||
shortcode: "blank", | |||||
new_filename: "dir_2/blank_3.png" | |||||
}) | |||||
|> json_response_and_validate_schema(:bad_request) | |||||
end | end | ||||
end | end | ||||
@@ -605,7 +645,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIControllerTest do | |||||
test "creating and deleting a pack", %{admin_conn: admin_conn} do | test "creating and deleting a pack", %{admin_conn: admin_conn} do | ||||
assert admin_conn | assert admin_conn | ||||
|> post("/api/pleroma/emoji/packs/test_created") | |> post("/api/pleroma/emoji/packs/test_created") | ||||
|> json_response(200) == "ok" | |||||
|> json_response_and_validate_schema(200) == "ok" | |||||
assert File.exists?("#{@emoji_path}/test_created/pack.json") | assert File.exists?("#{@emoji_path}/test_created/pack.json") | ||||
@@ -616,7 +656,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIControllerTest do | |||||
assert admin_conn | assert admin_conn | ||||
|> delete("/api/pleroma/emoji/packs/test_created") | |> delete("/api/pleroma/emoji/packs/test_created") | ||||
|> json_response(200) == "ok" | |||||
|> json_response_and_validate_schema(200) == "ok" | |||||
refute File.exists?("#{@emoji_path}/test_created/pack.json") | refute File.exists?("#{@emoji_path}/test_created/pack.json") | ||||
end | end | ||||
@@ -629,7 +669,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIControllerTest do | |||||
assert admin_conn | assert admin_conn | ||||
|> post("/api/pleroma/emoji/packs/test_created") | |> post("/api/pleroma/emoji/packs/test_created") | ||||
|> json_response(:conflict) == %{ | |||||
|> json_response_and_validate_schema(:conflict) == %{ | |||||
"error" => "A pack named \"test_created\" already exists" | "error" => "A pack named \"test_created\" already exists" | ||||
} | } | ||||
@@ -639,20 +679,26 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIControllerTest do | |||||
test "with empty name", %{admin_conn: admin_conn} do | test "with empty name", %{admin_conn: admin_conn} do | ||||
assert admin_conn | assert admin_conn | ||||
|> post("/api/pleroma/emoji/packs/ ") | |> post("/api/pleroma/emoji/packs/ ") | ||||
|> json_response(:bad_request) == %{"error" => "pack name cannot be empty"} | |||||
|> json_response_and_validate_schema(:bad_request) == %{ | |||||
"error" => "pack name cannot be empty" | |||||
} | |||||
end | end | ||||
end | end | ||||
test "deleting nonexisting pack", %{admin_conn: admin_conn} do | test "deleting nonexisting pack", %{admin_conn: admin_conn} do | ||||
assert admin_conn | assert admin_conn | ||||
|> delete("/api/pleroma/emoji/packs/non_existing") | |> delete("/api/pleroma/emoji/packs/non_existing") | ||||
|> json_response(:not_found) == %{"error" => "Pack non_existing does not exist"} | |||||
|> json_response_and_validate_schema(:not_found) == %{ | |||||
"error" => "Pack non_existing does not exist" | |||||
} | |||||
end | end | ||||
test "deleting with empty name", %{admin_conn: admin_conn} do | test "deleting with empty name", %{admin_conn: admin_conn} do | ||||
assert admin_conn | assert admin_conn | ||||
|> delete("/api/pleroma/emoji/packs/ ") | |> delete("/api/pleroma/emoji/packs/ ") | ||||
|> json_response(:bad_request) == %{"error" => "pack name cannot be empty"} | |||||
|> json_response_and_validate_schema(:bad_request) == %{ | |||||
"error" => "pack name cannot be empty" | |||||
} | |||||
end | end | ||||
test "filesystem import", %{admin_conn: admin_conn, conn: conn} do | test "filesystem import", %{admin_conn: admin_conn, conn: conn} do | ||||
@@ -661,15 +707,15 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIControllerTest do | |||||
File.rm!("#{@emoji_path}/test_pack_for_import/pack.json") | File.rm!("#{@emoji_path}/test_pack_for_import/pack.json") | ||||
end) | end) | ||||
resp = conn |> get("/api/pleroma/emoji/packs") |> json_response(200) | |||||
resp = conn |> get("/api/pleroma/emoji/packs") |> json_response_and_validate_schema(200) | |||||
refute Map.has_key?(resp, "test_pack_for_import") | refute Map.has_key?(resp, "test_pack_for_import") | ||||
assert admin_conn | assert admin_conn | ||||
|> get("/api/pleroma/emoji/packs/import") | |> get("/api/pleroma/emoji/packs/import") | ||||
|> json_response(200) == ["test_pack_for_import"] | |||||
|> json_response_and_validate_schema(200) == ["test_pack_for_import"] | |||||
resp = conn |> get("/api/pleroma/emoji/packs") |> json_response(200) | |||||
resp = conn |> get("/api/pleroma/emoji/packs") |> json_response_and_validate_schema(200) | |||||
assert resp["test_pack_for_import"]["files"] == %{"blank" => "blank.png"} | assert resp["test_pack_for_import"]["files"] == %{"blank" => "blank.png"} | ||||
File.rm!("#{@emoji_path}/test_pack_for_import/pack.json") | File.rm!("#{@emoji_path}/test_pack_for_import/pack.json") | ||||
@@ -686,9 +732,9 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIControllerTest do | |||||
assert admin_conn | assert admin_conn | ||||
|> get("/api/pleroma/emoji/packs/import") | |> get("/api/pleroma/emoji/packs/import") | ||||
|> json_response(200) == ["test_pack_for_import"] | |||||
|> json_response_and_validate_schema(200) == ["test_pack_for_import"] | |||||
resp = conn |> get("/api/pleroma/emoji/packs") |> json_response(200) | |||||
resp = conn |> get("/api/pleroma/emoji/packs") |> json_response_and_validate_schema(200) | |||||
assert resp["test_pack_for_import"]["files"] == %{ | assert resp["test_pack_for_import"]["files"] == %{ | ||||
"blank" => "blank.png", | "blank" => "blank.png", | ||||
@@ -712,19 +758,23 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIControllerTest do | |||||
} = | } = | ||||
conn | conn | ||||
|> get("/api/pleroma/emoji/packs/test_pack") | |> get("/api/pleroma/emoji/packs/test_pack") | ||||
|> json_response(200) | |||||
|> json_response_and_validate_schema(200) | |||||
end | end | ||||
test "non existing pack", %{conn: conn} do | test "non existing pack", %{conn: conn} do | ||||
assert conn | assert conn | ||||
|> get("/api/pleroma/emoji/packs/non_existing") | |> get("/api/pleroma/emoji/packs/non_existing") | ||||
|> json_response(:not_found) == %{"error" => "Pack non_existing does not exist"} | |||||
|> json_response_and_validate_schema(:not_found) == %{ | |||||
"error" => "Pack non_existing does not exist" | |||||
} | |||||
end | end | ||||
test "error name", %{conn: conn} do | test "error name", %{conn: conn} do | ||||
assert conn | assert conn | ||||
|> get("/api/pleroma/emoji/packs/ ") | |> get("/api/pleroma/emoji/packs/ ") | ||||
|> json_response(:bad_request) == %{"error" => "pack name cannot be empty"} | |||||
|> json_response_and_validate_schema(:bad_request) == %{ | |||||
"error" => "pack name cannot be empty" | |||||
} | |||||
end | end | ||||
end | end | ||||
end | end |