From 1830b6aae5e3fa0dfebcadd6f4b78871f702dd2d Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Fri, 13 Nov 2020 15:13:14 +0300 Subject: [PATCH] added error messages for posix error code --- lib/pleroma/emoji/pack.ex | 55 ++++--- lib/pleroma/utils.ex | 16 ++ .../controllers/emoji_file_controller.ex | 37 +++-- .../controllers/emoji_pack_controller.ex | 63 +++++--- priv/gettext/en/LC_MESSAGES/posix_errors.po | 141 +++++++++++++++++ priv/gettext/posix_errors.pot | 149 ++++++++++++++++++ 6 files changed, 412 insertions(+), 49 deletions(-) create mode 100644 priv/gettext/en/LC_MESSAGES/posix_errors.po create mode 100644 priv/gettext/posix_errors.pot diff --git a/lib/pleroma/emoji/pack.ex b/lib/pleroma/emoji/pack.ex index ca58e5432..4f4e84bfe 100644 --- a/lib/pleroma/emoji/pack.ex +++ b/lib/pleroma/emoji/pack.ex @@ -22,14 +22,14 @@ defmodule Pleroma.Emoji.Pack do alias Pleroma.Emoji alias Pleroma.Emoji.Pack + alias Pleroma.Utils @spec create(String.t()) :: {:ok, t()} | {:error, File.posix()} | {:error, :empty_values} 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(%__MODULE__{pack_file: Path.join(dir, "pack.json")}) end end @@ -94,7 +94,7 @@ defp unpack_zip_emojies(zip_files) do def add_file(%Pack{} = pack, _, _, %Plug.Upload{content_type: "application/zip"} = file) do with {:ok, zip_files} <- :zip.table(to_charlist(file.path)), [_ | _] = emojies <- unpack_zip_emojies(zip_files), - {:ok, tmp_dir} <- Pleroma.Utils.tmp_dir("emoji") do + {:ok, tmp_dir} <- Utils.tmp_dir("emoji") do try do {:ok, _emoji_files} = :zip.unzip( @@ -282,18 +282,21 @@ def update_metadata(name, data) do end end - @spec load_pack(String.t()) :: {:ok, t()} | {:error, :not_found} + @spec load_pack(String.t()) :: {:ok, t()} | {:error, :file.posix()} def load_pack(name) do pack_file = Path.join([emoji_path(), name, "pack.json"]) - if File.exists?(pack_file) do + with {:ok, _} <- File.stat(pack_file), + {:ok, pack_data} <- File.read(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) + from_json( + pack_data, + %{ + pack_file: pack_file, + path: Path.dirname(pack_file), + name: name + } + ) files_count = pack.files @@ -301,8 +304,6 @@ def load_pack(name) do |> length() {:ok, Map.put(pack, :files_count, files_count)} - else - {:error, :not_found} end end @@ -434,10 +435,17 @@ defp save_pack(pack) do end end - defp from_json(json) do + defp from_json(json, attrs) do map = Jason.decode!(json) - struct(__MODULE__, %{files: map["files"], pack: map["pack"]}) + pack_attrs = + attrs + |> Map.merge(%{ + files: map["files"], + pack: map["pack"] + }) + + struct(__MODULE__, pack_attrs) end defp validate_shareable_packs_available(uri) do @@ -491,10 +499,10 @@ defp rename_file(pack, filename, new_filename) do end defp create_subdirs(file_path) do - if String.contains?(file_path, "/") do - file_path - |> Path.dirname() - |> File.mkdir_p!() + with true <- String.contains?(file_path, "/"), + path <- Path.dirname(file_path), + false <- File.exists?(path) do + File.mkdir_p!(path) end end @@ -518,10 +526,15 @@ defp remove_dir_if_empty(emoji, filename) do defp get_filename(pack, shortcode) do with %{^shortcode => filename} when is_binary(filename) <- pack.files, - true <- pack.path |> Path.join(filename) |> File.exists?() do + file_path <- Path.join(pack.path, filename), + {:ok, _} <- File.stat(file_path) do {:ok, filename} else - _ -> {:error, :doesnt_exist} + {:error, _} = error -> + error + + _ -> + {:error, :doesnt_exist} end end diff --git a/lib/pleroma/utils.ex b/lib/pleroma/utils.ex index e95766223..fa75a8c99 100644 --- a/lib/pleroma/utils.ex +++ b/lib/pleroma/utils.ex @@ -3,6 +3,14 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Utils do + @posix_error_codes ~w( + eacces eagain ebadf ebadmsg ebusy edeadlk edeadlock edquot eexist efault + efbig eftype eintr einval eio eisdir eloop emfile emlink emultihop + enametoolong enfile enobufs enodev enolck enolink enoent enomem enospc + enosr enostr enosys enotblk enotdir enotsup enxio eopnotsupp eoverflow + eperm epipe erange erofs espipe esrch estale etxtbsy exdev + )a + def compile_dir(dir) when is_binary(dir) do dir |> File.ls!() @@ -44,4 +52,12 @@ def tmp_dir(prefix \\ "") do error -> error end end + + @spec posix_error_message(atom()) :: binary() + def posix_error_message(code) when code in @posix_error_codes do + error_message = Gettext.dgettext(Pleroma.Web.Gettext, "posix_errors", "#{code}") + "(POSIX error: #{error_message})" + end + + def posix_error_message(_), do: "" end diff --git a/lib/pleroma/web/pleroma_api/controllers/emoji_file_controller.ex b/lib/pleroma/web/pleroma_api/controllers/emoji_file_controller.ex index 428c97de6..c15980ff0 100644 --- a/lib/pleroma/web/pleroma_api/controllers/emoji_file_controller.ex +++ b/lib/pleroma/web/pleroma_api/controllers/emoji_file_controller.ex @@ -42,7 +42,10 @@ def create(%{body_params: params} = conn, %{name: pack_name}) do |> json(%{error: "pack name, shortcode or filename cannot be empty"}) {:error, _} = error -> - handle_error(conn, error, %{pack_name: pack_name}) + handle_error(conn, error, %{ + pack_name: pack_name, + message: "Unexpected error occurred while adding file to pack." + }) end end @@ -69,7 +72,11 @@ def update(%{body_params: %{shortcode: shortcode} = params} = conn, %{name: pack |> json(%{error: "new_shortcode or new_filename cannot be empty"}) {:error, _} = error -> - handle_error(conn, error, %{pack_name: pack_name, code: shortcode}) + handle_error(conn, error, %{ + pack_name: pack_name, + code: shortcode, + message: "Unexpected error occurred while updating." + }) end end @@ -84,7 +91,11 @@ def delete(conn, %{name: pack_name, shortcode: shortcode}) do |> json(%{error: "pack name or shortcode cannot be empty"}) {:error, _} = error -> - handle_error(conn, error, %{pack_name: pack_name, code: shortcode}) + handle_error(conn, error, %{ + pack_name: pack_name, + code: shortcode, + message: "Unexpected error occurred while deleting emoji file." + }) end end @@ -94,18 +105,24 @@ defp handle_error(conn, {:error, :doesnt_exist}, %{code: emoji_code}) do |> json(%{error: "Emoji \"#{emoji_code}\" does not exist"}) end - defp handle_error(conn, {:error, :not_found}, %{pack_name: pack_name}) do + defp handle_error(conn, {:error, :enoent}, %{pack_name: pack_name}) do conn |> put_status(:not_found) |> json(%{error: "pack \"#{pack_name}\" is not found"}) end - defp handle_error(conn, {:error, _}, _) do - render_error( - conn, - :internal_server_error, - "Unexpected error occurred while adding file to pack." - ) + defp handle_error(conn, {:error, error}, opts) do + message = + [ + Map.get(opts, :message, "Unexpected error occurred."), + Pleroma.Utils.posix_error_message(error) + ] + |> Enum.join(" ") + |> String.trim() + + conn + |> put_status(:internal_server_error) + |> json(%{error: message}) end defp get_filename(%Plug.Upload{filename: filename}), do: filename diff --git a/lib/pleroma/web/pleroma_api/controllers/emoji_pack_controller.ex b/lib/pleroma/web/pleroma_api/controllers/emoji_pack_controller.ex index a9accc5af..2fb29d34e 100644 --- a/lib/pleroma/web/pleroma_api/controllers/emoji_pack_controller.ex +++ b/lib/pleroma/web/pleroma_api/controllers/emoji_pack_controller.ex @@ -71,7 +71,7 @@ def show(conn, %{name: name, page: page, page_size: page_size}) do with {:ok, pack} <- Pack.show(name: name, page: page, page_size: page_size) do json(conn, pack) else - {:error, :not_found} -> + {:error, :enoent} -> conn |> put_status(:not_found) |> json(%{error: "Pack #{name} does not exist"}) @@ -80,6 +80,17 @@ def show(conn, %{name: name, page: page, page_size: page_size}) do conn |> put_status(:bad_request) |> json(%{error: "pack name cannot be empty"}) + + {:error, error} -> + error_message = + add_posix_error( + "Failed to get the contents of the `#{name}` pack.", + error + ) + + conn + |> put_status(:internal_server_error) + |> json(%{error: error_message}) end end @@ -95,7 +106,7 @@ def archive(conn, %{name: name}) do "Pack #{name} cannot be downloaded from this instance, either pack sharing was disabled for this pack or some files are missing" }) - {:error, :not_found} -> + {:error, :enoent} -> conn |> put_status(:not_found) |> json(%{error: "Pack #{name} does not exist"}) @@ -116,10 +127,10 @@ def download(%{body_params: %{url: url, name: name} = params} = conn, _) do |> put_status(:internal_server_error) |> json(%{error: "SHA256 for the pack doesn't match the one sent by the server"}) - {:error, e} -> + {:error, error} -> conn |> put_status(:internal_server_error) - |> json(%{error: e}) + |> json(%{error: error}) end end @@ -139,12 +150,16 @@ def create(conn, %{name: name}) do |> put_status(:bad_request) |> json(%{error: "pack name cannot be empty"}) - {:error, _} -> - render_error( - conn, - :internal_server_error, - "Unexpected error occurred while creating pack." - ) + {:error, error} -> + error_message = + add_posix_error( + "Unexpected error occurred while creating pack.", + error + ) + + conn + |> put_status(:internal_server_error) + |> json(%{error: error_message}) end end @@ -164,10 +179,12 @@ def delete(conn, %{name: name}) do |> put_status(:bad_request) |> json(%{error: "pack name cannot be empty"}) - {:error, _, _} -> + {:error, error, _} -> + error_message = add_posix_error("Couldn't delete the pack #{name}", error) + conn |> put_status(:internal_server_error) - |> json(%{error: "Couldn't delete the pack #{name}"}) + |> json(%{error: error_message}) end end @@ -180,12 +197,16 @@ def update(%{body_params: %{metadata: metadata}} = conn, %{name: name}) do |> put_status(:bad_request) |> json(%{error: "The fallback archive does not have all files specified in pack.json"}) - {:error, _} -> - render_error( - conn, - :internal_server_error, - "Unexpected error occurred while updating pack metadata." - ) + {:error, error} -> + error_message = + add_posix_error( + "Unexpected error occurred while updating pack metadata.", + error + ) + + conn + |> put_status(:internal_server_error) + |> json(%{error: error_message}) end end @@ -204,4 +225,10 @@ def import_from_filesystem(conn, _params) do |> json(%{error: "Error accessing emoji pack directory"}) end end + + defp add_posix_error(msg, error) do + [msg, Pleroma.Utils.posix_error_message(error)] + |> Enum.join(" ") + |> String.trim() + end end diff --git a/priv/gettext/en/LC_MESSAGES/posix_errors.po b/priv/gettext/en/LC_MESSAGES/posix_errors.po new file mode 100644 index 000000000..1ecaf8e5f --- /dev/null +++ b/priv/gettext/en/LC_MESSAGES/posix_errors.po @@ -0,0 +1,141 @@ +## This file is a PO Template file. +msgid "eperm" +msgstr "Operation not permitted" + +msgid "eacces" +msgstr "Permission denied" + +msgid "eagain" +msgstr "Resource temporarily unavailable" + +msgid "ebadf" +msgstr "Bad file descriptor" + +msgid "ebadmsg" +msgstr "Bad message" + +msgid "ebusy" +msgstr "Device or resource busy" + +msgid "edeadlk" +msgstr "Resource deadlock avoided" + +msgid "edeadlock" +msgstr "Resource deadlock avoided" + +msgid "edquot" +msgstr "Disk quota exceeded" + +msgid "eexist" +msgstr "File exists" + +msgid "efault" +msgstr "Bad address" + +msgid "efbig" +msgstr "File too large" + +msgid "eftype" +msgstr "Inappropriate file type or format" + +msgid "eintr" +msgstr "Interrupted system call" + +msgid "einval" +msgstr "Invalid argument" + +msgid "eio" +msgstr "Input/output error" + +msgid "eisdir" +msgstr "Is a directory" + +msgid "eloop" +msgstr "Too many levels of symbolic links" + +msgid "emfile" +msgstr "Too many open files" + +msgid "emlink" +msgstr "Too many links" + +msgid "emultihop" +msgstr "Multihop attempted" + +msgid "enametoolong" +msgstr "File name too long" + +msgid "enfile" +msgstr "Too many open files in system" + +msgid "enobufs" +msgstr "No buffer space available" + +msgid "enodev" +msgstr "No such device" + +msgid "enolck" +msgstr "No locks available" + +msgid "enolink" +msgstr "Link has been severed" + +msgid "enoent" +msgstr "No such file or directory" + +msgid "enomem" +msgstr "Cannot allocate memory" + +msgid "enospc" +msgstr "No space left on device" + +msgid "enosr" +msgstr "Out of streams resources" + +msgid "enostr" +msgstr "Device not a stream" + +msgid "enosys" +msgstr "Function not implemented" + +msgid "enotblk" +msgstr "Block device required" + +msgid "enotdir" +msgstr "Not a directory" + +msgid "enotsup" +msgstr "Operation not supported" + +msgid "enxio" +msgstr "No such device or address" + +msgid "eopnotsupp" +msgstr "Operation not supported" + +msgid "eoverflow" +msgstr "Value too large for defined data type" + +msgid "epipe" +msgstr "Broken pipe" + +msgid "erange" +msgstr "Numerical result out of range" + +msgid "erofs" +msgstr "Read-only file system" + +msgid "espipe" +msgstr "Illegal seek" + +msgid "esrch" +msgstr "No such process" + +msgid "estale" +msgstr "Stale file handle" + +msgid "etxtbsy" +msgstr "Text file busy" + +msgid "exdev" +msgstr "Invalid cross-device link" diff --git a/priv/gettext/posix_errors.pot b/priv/gettext/posix_errors.pot new file mode 100644 index 000000000..c9f593944 --- /dev/null +++ b/priv/gettext/posix_errors.pot @@ -0,0 +1,149 @@ +## This file is a PO Template file. +## +## `msgid`s here are often extracted from source code. +## Add new translations manually only if they're dynamic +## translations that can't be statically extracted. +## +## Run `mix gettext.extract` to bring this file up to +## date. Leave `msgstr`s empty as changing them here as no +## effect: edit them in PO (`.po`) files instead. +msgid "eperm" +msgstr "" + +msgid "eacces" +msgstr "" + +msgid "eagain" +msgstr "" + +msgid "ebadf" +msgstr "" + +msgid "ebadmsg" +msgstr "" + +msgid "ebusy" +msgstr "" + +msgid "edeadlk" +msgstr "" + +msgid "edeadlock" +msgstr "" + +msgid "edquot" +msgstr "" + +msgid "eexist" +msgstr "" + +msgid "efault" +msgstr "" + +msgid "efbig" +msgstr "" + +msgid "eftype" +msgstr "" + +msgid "eintr" +msgstr "" + +msgid "einval" +msgstr "" + +msgid "eio" +msgstr "" + +msgid "eisdir" +msgstr "" + +msgid "eloop" +msgstr "" + +msgid "emfile" +msgstr "" + +msgid "emlink" +msgstr "" + +msgid "emultihop" +msgstr "" + +msgid "enametoolong" +msgstr "" + +msgid "enfile" +msgstr "" + +msgid "enobufs" +msgstr "" + +msgid "enodev" +msgstr "" + +msgid "enolck" +msgstr "" + +msgid "enolink" +msgstr "" + +msgid "enoent" +msgstr "" + +msgid "enomem" +msgstr "" + +msgid "enospc" +msgstr "" + +msgid "enosr" +msgstr "" + +msgid "enostr" +msgstr "" + +msgid "enosys" +msgstr "" + +msgid "enotblk" +msgstr "" + +msgid "enotdir" +msgstr "" + +msgid "enotsup" +msgstr "" + +msgid "enxio" +msgstr "" + +msgid "eopnotsupp" +msgstr "" + +msgid "eoverflow" +msgstr "" + +msgid "epipe" +msgstr "" + +msgid "erange" +msgstr "" + +msgid "erofs" +msgstr "" + +msgid "espipe" +msgstr "" + +msgid "esrch" +msgstr "" + +msgid "estale" +msgstr "" + +msgid "etxtbsy" +msgstr "" + +msgid "exdev" +msgstr ""