# Pleroma: A lightweight social networking server # Copyright © 2017-2022 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.PleromaAPI.EmojiFileController do use Pleroma.Web, :controller alias Pleroma.Emoji.Pack alias Pleroma.Web.ApiSpec plug(Pleroma.Web.ApiSpec.CastAndValidate, replace_params: false) plug( Pleroma.Web.Plugs.OAuthScopesPlug, %{scopes: ["admin:write"]} when action in [ :create, :update, :delete ] ) defdelegate open_api_operation(action), to: ApiSpec.PleromaEmojiFileOperation def create( %{private: %{open_api_spex: %{body_params: params, params: %{name: pack_name}}}} = conn, _ ) do filename = params[:filename] || get_filename(params[:file]) shortcode = params[:shortcode] || Path.basename(filename, Path.extname(filename)) with {:ok, pack} <- Pack.load_pack(pack_name), {:ok, file} <- get_file(params[:file]), {:ok, pack} <- Pack.add_file(pack, shortcode, filename, file) do json(conn, pack.files) else {:error, :already_exists} -> conn |> put_status(:conflict) |> json(%{error: "An emoji with the \"#{shortcode}\" shortcode already exists"}) {:error, :empty_values} -> conn |> put_status(:unprocessable_entity) |> json(%{error: "pack name, shortcode or filename cannot be empty"}) {:error, _} = error -> handle_error(conn, error, %{ pack_name: pack_name, message: "Unexpected error occurred while adding file to pack." }) end end def update( %{ private: %{ open_api_spex: %{ body_params: %{shortcode: shortcode} = params, params: %{name: pack_name} } } } = conn, _ ) do new_shortcode = params[:new_shortcode] new_filename = params[:new_filename] force = params[:force] with {:ok, pack} <- Pack.load_pack(pack_name), {:ok, pack} <- Pack.update_file(pack, shortcode, new_shortcode, new_filename, force) do json(conn, pack.files) else {:error, :already_exists} -> conn |> put_status(:conflict) |> json(%{ error: "New shortcode \"#{new_shortcode}\" is already used. If you want to override emoji use 'force' option" }) {:error, :empty_values} -> conn |> put_status(:unprocessable_entity) |> json(%{error: "new_shortcode or new_filename cannot be empty"}) {:error, _} = error -> handle_error(conn, error, %{ pack_name: pack_name, code: shortcode, message: "Unexpected error occurred while updating." }) end end def delete( %{private: %{open_api_spex: %{params: %{name: pack_name, shortcode: shortcode}}}} = conn, _ ) do with {:ok, pack} <- Pack.load_pack(pack_name), {:ok, pack} <- Pack.delete_file(pack, shortcode) do json(conn, pack.files) else {:error, :empty_values} -> conn |> put_status(:unprocessable_entity) |> json(%{error: "pack name or shortcode cannot be empty"}) {:error, _} = error -> handle_error(conn, error, %{ pack_name: pack_name, code: shortcode, message: "Unexpected error occurred while deleting emoji file." }) end end defp handle_error(conn, {:error, :doesnt_exist}, %{code: emoji_code}) do conn |> put_status(:bad_request) |> json(%{error: "Emoji \"#{emoji_code}\" does not exist"}) end 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, 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 defp get_filename(url) when is_binary(url), do: Path.basename(url) def get_file(%Plug.Upload{} = file), do: {:ok, file} def get_file(url) when is_binary(url) do with {:ok, %Tesla.Env{body: body, status: code, headers: headers}} when code in 200..299 <- Pleroma.HTTP.get(url) do path = Plug.Upload.random_file!("emoji") content_type = case List.keyfind(headers, "content-type", 0) do {"content-type", value} -> value nil -> nil end File.write(path, body) {:ok, %Plug.Upload{ filename: Path.basename(url), path: path, content_type: content_type }} end end end