Merge branch 'smol-test' into 'develop'
authorlain <lain@soykaf.club>
Thu, 24 Sep 2020 09:41:28 +0000 (09:41 +0000)
committerlain <lain@soykaf.club>
Thu, 24 Sep 2020 09:41:28 +0000 (09:41 +0000)
CommonAPI test: Add test for polls

See merge request pleroma/pleroma!3028

27 files changed:
CHANGELOG.md
lib/pleroma/chat.ex
lib/pleroma/emails/mailer.ex
lib/pleroma/emoji.ex
lib/pleroma/emoji/pack.ex
lib/pleroma/user/query.ex
lib/pleroma/utils.ex
lib/pleroma/web/api_spec/operations/chat_operation.ex
lib/pleroma/web/api_spec/operations/pleroma_emoji_file_operation.ex [new file with mode: 0644]
lib/pleroma/web/api_spec/operations/pleroma_emoji_pack_operation.ex
lib/pleroma/web/controller_helper.ex
lib/pleroma/web/mastodon_api/controllers/auth_controller.ex
lib/pleroma/web/pleroma_api/controllers/chat_controller.ex
lib/pleroma/web/pleroma_api/controllers/emoji_file_controller.ex [new file with mode: 0644]
lib/pleroma/web/pleroma_api/controllers/emoji_pack_controller.ex
lib/pleroma/web/router.ex
test/emoji/pack_test.exs [new file with mode: 0644]
test/fixtures/emojis.zip [new file with mode: 0644]
test/fixtures/empty.zip [new file with mode: 0644]
test/user/query_test.exs [new file with mode: 0644]
test/user_test.exs
test/utils_test.exs [new file with mode: 0644]
test/web/admin_api/controllers/admin_api_controller_test.exs
test/web/mastodon_api/controllers/auth_controller_test.exs
test/web/pleroma_api/controllers/chat_controller_test.exs
test/web/pleroma_api/controllers/emoji_file_controller_test.exs [new file with mode: 0644]
test/web/pleroma_api/controllers/emoji_pack_controller_test.exs

index e61b1d14443ac71247cea97215b5b3b13138d645..5f5d01af34e94be5b8781931aa0d42951db004b6 100644 (file)
@@ -5,9 +5,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
 
 ## Unreleased
 
-### Added
-- Experimental websocket-based federation between Pleroma instances.
-
 ### Changed
 
 - Renamed `:await_up_timeout` in `:connections_pool` namespace to `:connect_timeout`, old name is deprecated.
@@ -19,6 +16,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
 ### Added
 - Media preview proxy (requires media proxy be enabled; see `:media_preview_proxy` config for more details).
 - Pleroma API: Importing the mutes users from CSV files.
+- Experimental websocket-based federation between Pleroma instances.
+- Admin API: Importing emoji from a zip file
 
 ### Removed
 
@@ -28,6 +27,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
 - Removed `:managed_config` option. In practice, it was accidentally removed with 2.0.0 release when frontends were
 switched to a new configuration mechanism, however it was not officially removed until now.
 
+### Fixed
+
+- Add documented-but-missing chat pagination.
+- Allow sending out emails again.
 
 ## [2.1.2] - 2020-09-17
 
index 84f8806a084c1ad957bc477af6d6b3ac8c88fd7f..28007cd9f4b945795d0774182342395ee47c85e6 100644 (file)
@@ -18,6 +18,7 @@ defmodule Pleroma.Chat do
   It is a helper only, to make it easy to display a list of chats with other people, ordered by last bump. The actual messages are retrieved by querying the recipients of the ChatMessages.
   """
 
+  @type t :: %__MODULE__{}
   @primary_key {:id, FlakeId.Ecto.CompatType, autogenerate: true}
 
   schema "chats" do
@@ -41,16 +42,28 @@ defmodule Pleroma.Chat do
     |> unique_constraint(:user_id, name: :chats_user_id_recipient_index)
   end
 
+  @spec get_by_user_and_id(User.t(), FlakeId.Ecto.CompatType.t()) ::
+          {:ok, t()} | {:error, :not_found}
+  def get_by_user_and_id(%User{id: user_id}, id) do
+    from(c in __MODULE__,
+      where: c.id == ^id,
+      where: c.user_id == ^user_id
+    )
+    |> Repo.find_resource()
+  end
+
+  @spec get_by_id(FlakeId.Ecto.CompatType.t()) :: t() | nil
   def get_by_id(id) do
-    __MODULE__
-    |> Repo.get(id)
+    Repo.get(__MODULE__, id)
   end
 
+  @spec get(FlakeId.Ecto.CompatType.t(), String.t()) :: t() | nil
   def get(user_id, recipient) do
-    __MODULE__
-    |> Repo.get_by(user_id: user_id, recipient: recipient)
+    Repo.get_by(__MODULE__, user_id: user_id, recipient: recipient)
   end
 
+  @spec get_or_create(FlakeId.Ecto.CompatType.t(), String.t()) ::
+          {:ok, t()} | {:error, Ecto.Changeset.t()}
   def get_or_create(user_id, recipient) do
     %__MODULE__{}
     |> changeset(%{user_id: user_id, recipient: recipient})
@@ -62,6 +75,8 @@ defmodule Pleroma.Chat do
     )
   end
 
+  @spec bump_or_create(FlakeId.Ecto.CompatType.t(), String.t()) ::
+          {:ok, t()} | {:error, Ecto.Changeset.t()}
   def bump_or_create(user_id, recipient) do
     %__MODULE__{}
     |> changeset(%{user_id: user_id, recipient: recipient})
index 8b1bdef754d0a0b23c0a7727ef4fc9b15dc05d6e..5108c71c8a3b63e93ebee8825713ae0205af1952 100644 (file)
@@ -35,6 +35,11 @@ defmodule Pleroma.Emails.Mailer do
   def deliver(email, config \\ [])
 
   def deliver(email, config) do
+    # temporary hackney fix until hackney max_connections bug is fixed
+    # https://git.pleroma.social/pleroma/pleroma/-/issues/2101
+    email =
+      Swoosh.Email.put_private(email, :hackney_options, ssl_options: [versions: [:"tlsv1.2"]])
+
     case enabled?() do
       true -> Swoosh.Mailer.deliver(email, parse_config(config))
       false -> {:error, :deliveries_disabled}
index f6016d73fb5c02a0118cfe250a5980d844dd4c99..04936155b5e1419c63878f437f75c4224e687f14 100644 (file)
@@ -56,6 +56,9 @@ defmodule Pleroma.Emoji do
     end
   end
 
+  @spec exist?(String.t()) :: boolean()
+  def exist?(name), do: not is_nil(get(name))
+
   @doc "Returns all the emojos!!"
   @spec get_all() :: list({String.t(), String.t(), String.t()})
   def get_all do
index d076ae3125c5318815dba7d59042862c9f1399e8..0b3f8f00b6e8e4f99ff6d887a02cf6f7f8d04bef 100644 (file)
@@ -17,6 +17,7 @@ defmodule Pleroma.Emoji.Pack do
         }
 
   alias Pleroma.Emoji
+  alias Pleroma.Emoji.Pack
 
   @spec create(String.t()) :: {:ok, t()} | {:error, File.posix()} | {:error, :empty_values}
   def create(name) do
@@ -64,24 +65,93 @@ defmodule Pleroma.Emoji.Pack do
     end
   end
 
-  @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]),
+  @spec unpack_zip_emojies(list(tuple())) :: list(map())
+  defp unpack_zip_emojies(zip_files) do
+    Enum.reduce(zip_files, [], fn
+      {_, path, s, _, _, _}, acc when elem(s, 2) == :regular ->
+        with(
+          filename <- Path.basename(path),
+          shortcode <- Path.basename(filename, Path.extname(filename)),
+          false <- Emoji.exist?(shortcode)
+        ) do
+          [%{path: path, filename: path, shortcode: shortcode} | acc]
+        else
+          _ -> acc
+        end
+
+      _, acc ->
+        acc
+    end)
+  end
+
+  @spec add_file(t(), String.t(), Path.t(), Plug.Upload.t()) ::
+          {:ok, t()}
+          | {:error, File.posix() | atom()}
+  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
+      try do
+        {:ok, _emoji_files} =
+          :zip.unzip(
+            to_charlist(file.path),
+            [{:file_list, Enum.map(emojies, & &1[:path])}, {:cwd, tmp_dir}]
+          )
+
+        {_, updated_pack} =
+          Enum.map_reduce(emojies, pack, fn item, emoji_pack ->
+            emoji_file = %Plug.Upload{
+              filename: item[:filename],
+              path: Path.join(tmp_dir, item[:path])
+            }
+
+            {:ok, updated_pack} =
+              do_add_file(
+                emoji_pack,
+                item[:shortcode],
+                to_string(item[:filename]),
+                emoji_file
+              )
+
+            {item, updated_pack}
+          end)
+
+        Emoji.reload()
+
+        {:ok, updated_pack}
+      after
+        File.rm_rf(tmp_dir)
+      end
+    else
+      {:error, _} = error ->
+        error
+
+      _ ->
+        {:ok, pack}
+    end
+  end
+
+  def add_file(%Pack{} = pack, shortcode, filename, %Plug.Upload{} = file) do
+    with :ok <- validate_not_empty([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
+         {:ok, updated_pack} <- do_add_file(pack, shortcode, filename, file) do
       Emoji.reload()
       {:ok, updated_pack}
     end
   end
 
-  @spec delete_file(String.t(), String.t()) ::
+  defp do_add_file(pack, shortcode, filename, file) do
+    with :ok <- save_file(file, pack, filename) do
+      pack
+      |> put_emoji(shortcode, filename)
+      |> save_pack()
+    end
+  end
+
+  @spec delete_file(t(), String.t()) ::
           {:ok, t()} | {:error, File.posix() | atom()}
-  def delete_file(name, shortcode) do
-    with :ok <- validate_not_empty([name, shortcode]),
-         {:ok, pack} <- load_pack(name),
+  def delete_file(%Pack{} = pack, shortcode) do
+    with :ok <- validate_not_empty([shortcode]),
          :ok <- remove_file(pack, shortcode),
          {:ok, updated_pack} <- pack |> delete_emoji(shortcode) |> save_pack() do
       Emoji.reload()
@@ -89,11 +159,10 @@ defmodule Pleroma.Emoji.Pack do
     end
   end
 
-  @spec update_file(String.t(), String.t(), String.t(), String.t(), boolean()) ::
+  @spec update_file(t(), String.t(), String.t(), String.t(), boolean()) ::
           {: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),
+  def update_file(%Pack{} = pack, shortcode, new_shortcode, new_filename, force) do
+    with :ok <- validate_not_empty([shortcode, new_shortcode, new_filename]),
          {:ok, filename} <- get_filename(pack, shortcode),
          :ok <- validate_emoji_not_exists(new_shortcode, force),
          :ok <- rename_file(pack, filename, new_filename),
@@ -243,9 +312,10 @@ defmodule Pleroma.Emoji.Pack do
   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}
+    if Emoji.exist?(shortcode) do
+      {:error, :already_exists}
+    else
+      :ok
     end
   end
 
@@ -386,25 +456,18 @@ defmodule Pleroma.Emoji.Pack do
     end
   end
 
-  defp save_file(file, pack, filename) do
+  defp save_file(%Plug.Upload{path: upload_path}, pack, filename) 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
-        with {:ok, _} <- File.copy(upload_path, file_path), do: :ok
-
-      url when is_binary(url) ->
-        # Download and write the file
-        file_contents = Tesla.get!(url).body
-        File.write(file_path, file_contents)
+    with {:ok, _} <- File.copy(upload_path, file_path) do
+      :ok
     end
   end
 
   defp put_emoji(pack, shortcode, filename) do
     files = Map.put(pack.files, shortcode, filename)
-    %{pack | files: files}
+    %{pack | files: files, files_count: length(Map.keys(files))}
   end
 
   defp delete_emoji(pack, shortcode) do
index d618432fffcc70e8bb86ceb44baec07f26adb8dd..193b90d9d65e077d0b20d789afd843f62ff85758 100644 (file)
@@ -47,6 +47,7 @@ defmodule Pleroma.User.Query do
             is_moderator: boolean(),
             super_users: boolean(),
             invisible: boolean(),
+            internal: boolean(),
             followers: User.t(),
             friends: User.t(),
             recipients_from_activity: [String.t()],
@@ -80,7 +81,9 @@ defmodule Pleroma.User.Query do
   end
 
   defp prepare_query(query, criteria) do
-    Enum.reduce(criteria, query, &compose_query/2)
+    criteria
+    |> Map.put_new(:internal, false)
+    |> Enum.reduce(query, &compose_query/2)
   end
 
   defp compose_query({key, value}, query)
@@ -129,14 +132,12 @@ defmodule Pleroma.User.Query do
 
   defp compose_query({:active, _}, query) do
     User.restrict_deactivated(query)
-    |> where([u], not is_nil(u.nickname))
     |> where([u], u.approval_pending == false)
   end
 
   defp compose_query({:legacy_active, _}, query) do
     query
     |> where([u], fragment("not (?->'deactivated' @> 'true')", u.info))
-    |> where([u], not is_nil(u.nickname))
   end
 
   defp compose_query({:deactivated, false}, query) do
@@ -145,7 +146,6 @@ defmodule Pleroma.User.Query do
 
   defp compose_query({:deactivated, true}, query) do
     where(query, [u], u.deactivated == ^true)
-    |> where([u], not is_nil(u.nickname))
   end
 
   defp compose_query({:need_approval, _}, query) do
@@ -199,10 +199,15 @@ defmodule Pleroma.User.Query do
     limit(query, ^limit)
   end
 
+  defp compose_query({:internal, false}, query) do
+    query
+    |> where([u], not is_nil(u.nickname))
+    |> where([u], not like(u.nickname, "internal.%"))
+  end
+
   defp compose_query(_unsupported_param, query), do: query
 
   defp location_query(query, local) do
     where(query, [u], u.local == ^local)
-    |> where([u], not is_nil(u.nickname))
   end
 end
index 21d1159be84383426262ee49bb7d4758dccb3523..e95766223d86e9965fbcfdc9f5595e98a5505461 100644 (file)
@@ -24,4 +24,24 @@ defmodule Pleroma.Utils do
   def command_available?(command) do
     match?({_output, 0}, System.cmd("sh", ["-c", "command -v #{command}"]))
   end
+
+  @doc "creates the uniq temporary directory"
+  @spec tmp_dir(String.t()) :: {:ok, String.t()} | {:error, :file.posix()}
+  def tmp_dir(prefix \\ "") do
+    sub_dir =
+      [
+        prefix,
+        Timex.to_unix(Timex.now()),
+        :os.getpid(),
+        String.downcase(Integer.to_string(:rand.uniform(0x100000000), 36))
+      ]
+      |> Enum.join("-")
+
+    tmp_dir = Path.join(System.tmp_dir!(), sub_dir)
+
+    case File.mkdir(tmp_dir) do
+      :ok -> {:ok, tmp_dir}
+      error -> error
+    end
+  end
 end
index 56554d5b4a3d0913733ad8391390ef4f94b56689..0dcfdb35467ef2e04f5493ef04546bb124bffd9b 100644 (file)
@@ -158,7 +158,8 @@ defmodule Pleroma.Web.ApiSpec.ChatOperation do
             "The messages in the chat",
             "application/json",
             chat_messages_response()
-          )
+          ),
+        404 => Operation.response("Not Found", "application/json", ApiError)
       },
       security: [
         %{
diff --git a/lib/pleroma/web/api_spec/operations/pleroma_emoji_file_operation.ex b/lib/pleroma/web/api_spec/operations/pleroma_emoji_file_operation.ex
new file mode 100644 (file)
index 0000000..efbfce7
--- /dev/null
@@ -0,0 +1,139 @@
+# 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.PleromaEmojiFileOperation 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 create_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", create_request(), required: true),
+      parameters: [name_param()],
+      responses: %{
+        200 => Operation.response("Files Object", "application/json", files_object()),
+        422 => Operation.response("Unprocessable Entity", "application/json", ApiError),
+        404 => Operation.response("Not Found", "application/json", ApiError),
+        400 => Operation.response("Bad Request", "application/json", ApiError),
+        409 => Operation.response("Conflict", "application/json", ApiError)
+      }
+    }
+  end
+
+  defp create_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_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_request(), required: true),
+      parameters: [name_param()],
+      responses: %{
+        200 => Operation.response("Files Object", "application/json", files_object()),
+        404 => Operation.response("Not Found", "application/json", ApiError),
+        400 => Operation.response("Bad Request", "application/json", ApiError),
+        409 => Operation.response("Conflict", "application/json", ApiError),
+        422 => Operation.response("Unprocessable Entity", "application/json", ApiError)
+      }
+    }
+  end
+
+  defp update_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_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),
+        404 => Operation.response("Not Found", "application/json", ApiError),
+        422 => Operation.response("Unprocessable Entity", "application/json", ApiError)
+      }
+    }
+  end
+
+  defp name_param do
+    Operation.parameter(:name, :path, :string, "Pack Name", example: "cofe", required: true)
+  end
+
+  defp files_object do
+    %Schema{
+      type: :object,
+      additionalProperties: %Schema{type: :string},
+      description: "Object with emoji names as keys and filenames as values"
+    }
+  end
+end
index b2b4f87134d34458e85a1c88ab5f16fbc0cd598d..59548af1339e6d9150e05e0d545c8dda2c690f36 100644 (file)
@@ -175,111 +175,6 @@ defmodule Pleroma.Web.ApiSpec.PleromaEmojiPackOperation do
     }
   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"],
index 6445966e020c09b6e363599afb66baf2e2f51d53..69188a882049de1af680d78bc1aebecff6319e67 100644 (file)
@@ -48,13 +48,13 @@ defmodule Pleroma.Web.ControllerHelper do
 
   defp param_to_integer(_, default), do: default
 
-  def add_link_headers(conn, activities, extra_params \\ %{})
+  def add_link_headers(conn, entries, extra_params \\ %{})
 
-  def add_link_headers(%{assigns: %{skip_link_headers: true}} = conn, _activities, _extra_params),
+  def add_link_headers(%{assigns: %{skip_link_headers: true}} = conn, _entries, _extra_params),
     do: conn
 
-  def add_link_headers(conn, activities, extra_params) do
-    case get_pagination_fields(conn, activities, extra_params) do
+  def add_link_headers(conn, entries, extra_params) do
+    case get_pagination_fields(conn, entries, extra_params) do
       %{"next" => next_url, "prev" => prev_url} ->
         put_resp_header(conn, "link", "<#{next_url}>; rel=\"next\", <#{prev_url}>; rel=\"prev\"")
 
@@ -78,19 +78,15 @@ defmodule Pleroma.Web.ControllerHelper do
     }
   end
 
-  def get_pagination_fields(conn, activities, extra_params \\ %{}) do
-    case List.last(activities) do
+  def get_pagination_fields(conn, entries, extra_params \\ %{}) do
+    case List.last(entries) do
       %{pagination_id: max_id} when not is_nil(max_id) ->
-        %{pagination_id: min_id} =
-          activities
-          |> List.first()
+        %{pagination_id: min_id} = List.first(entries)
 
         build_pagination_fields(conn, min_id, max_id, extra_params)
 
       %{id: max_id} ->
-        %{id: min_id} =
-          activities
-          |> List.first()
+        %{id: min_id} = List.first(entries)
 
         build_pagination_fields(conn, min_id, max_id, extra_params)
 
index 9f09550e1c97e372f1e812a336c46243d68e7fac..57c0be5fea166463b652d9683e3ca4c8684271e2 100644 (file)
@@ -5,6 +5,8 @@
 defmodule Pleroma.Web.MastodonAPI.AuthController do
   use Pleroma.Web, :controller
 
+  import Pleroma.Web.ControllerHelper, only: [json_response: 3]
+
   alias Pleroma.User
   alias Pleroma.Web.OAuth.App
   alias Pleroma.Web.OAuth.Authorization
@@ -61,9 +63,7 @@ defmodule Pleroma.Web.MastodonAPI.AuthController do
 
     TwitterAPI.password_reset(nickname_or_email)
 
-    conn
-    |> put_status(:no_content)
-    |> json("")
+    json_response(conn, :no_content, "")
   end
 
   defp local_mastodon_root_path(conn) do
index 867cff8294af5b2835d1f687bf10e5de5c17cb9e..e667831c59c1b9d604208b4478c1ad15cbbd0a13 100644 (file)
@@ -4,6 +4,8 @@
 defmodule Pleroma.Web.PleromaAPI.ChatController do
   use Pleroma.Web, :controller
 
+  import Pleroma.Web.ControllerHelper, only: [add_link_headers: 2]
+
   alias Pleroma.Activity
   alias Pleroma.Chat
   alias Pleroma.Chat.MessageReference
@@ -47,7 +49,7 @@ defmodule Pleroma.Web.PleromaAPI.ChatController do
       }) do
     with %MessageReference{} = cm_ref <-
            MessageReference.get_by_id(message_id),
-         ^chat_id <- cm_ref.chat_id |> to_string(),
+         ^chat_id <- to_string(cm_ref.chat_id),
          %Chat{user_id: ^user_id} <- Chat.get_by_id(chat_id),
          {:ok, _} <- remove_or_delete(cm_ref, user) do
       conn
@@ -68,18 +70,13 @@ defmodule Pleroma.Web.PleromaAPI.ChatController do
     end
   end
 
-  defp remove_or_delete(cm_ref, _) do
-    cm_ref
-    |> MessageReference.delete()
-  end
+  defp remove_or_delete(cm_ref, _), do: MessageReference.delete(cm_ref)
 
   def post_chat_message(
-        %{body_params: params, assigns: %{user: %{id: user_id} = user}} = conn,
-        %{
-          id: id
-        }
+        %{body_params: params, assigns: %{user: user}} = conn,
+        %{id: id}
       ) do
-    with %Chat{} = chat <- Repo.get_by(Chat, id: id, user_id: user_id),
+    with {:ok, chat} <- Chat.get_by_user_and_id(user, id),
          %User{} = recipient <- User.get_cached_by_ap_id(chat.recipient),
          {:ok, activity} <-
            CommonAPI.post_chat_message(user, recipient, params[:content],
@@ -103,13 +100,12 @@ defmodule Pleroma.Web.PleromaAPI.ChatController do
     end
   end
 
-  def mark_message_as_read(%{assigns: %{user: %{id: user_id}}} = conn, %{
-        id: chat_id,
-        message_id: message_id
-      }) do
-    with %MessageReference{} = cm_ref <-
-           MessageReference.get_by_id(message_id),
-         ^chat_id <- cm_ref.chat_id |> to_string(),
+  def mark_message_as_read(
+        %{assigns: %{user: %{id: user_id}}} = conn,
+        %{id: chat_id, message_id: message_id}
+      ) do
+    with %MessageReference{} = cm_ref <- MessageReference.get_by_id(message_id),
+         ^chat_id <- to_string(cm_ref.chat_id),
          %Chat{user_id: ^user_id} <- Chat.get_by_id(chat_id),
          {:ok, cm_ref} <- MessageReference.mark_as_read(cm_ref) do
       conn
@@ -119,36 +115,28 @@ defmodule Pleroma.Web.PleromaAPI.ChatController do
   end
 
   def mark_as_read(
-        %{
-          body_params: %{last_read_id: last_read_id},
-          assigns: %{user: %{id: user_id}}
-        } = conn,
+        %{body_params: %{last_read_id: last_read_id}, assigns: %{user: user}} = conn,
         %{id: id}
       ) do
-    with %Chat{} = chat <- Repo.get_by(Chat, id: id, user_id: user_id),
-         {_n, _} <-
-           MessageReference.set_all_seen_for_chat(chat, last_read_id) do
+    with {:ok, chat} <- Chat.get_by_user_and_id(user, id),
+         {_n, _} <- MessageReference.set_all_seen_for_chat(chat, last_read_id) do
       conn
       |> put_view(ChatView)
       |> render("show.json", chat: chat)
     end
   end
 
-  def messages(%{assigns: %{user: %{id: user_id}}} = conn, %{id: id} = params) do
-    with %Chat{} = chat <- Repo.get_by(Chat, id: id, user_id: user_id) do
-      cm_refs =
+  def messages(%{assigns: %{user: user}} = conn, %{id: id} = params) do
+    with {:ok, chat} <- Chat.get_by_user_and_id(user, id) do
+      chat_message_refs =
         chat
         |> MessageReference.for_chat_query()
         |> Pagination.fetch_paginated(params)
 
       conn
+      |> add_link_headers(chat_message_refs)
       |> put_view(MessageReferenceView)
-      |> render("index.json", chat_message_references: cm_refs)
-    else
-      _ ->
-        conn
-        |> put_status(:not_found)
-        |> json(%{error: "not found"})
+      |> render("index.json", chat_message_references: chat_message_refs)
     end
   end
 
@@ -165,8 +153,8 @@ defmodule Pleroma.Web.PleromaAPI.ChatController do
     |> render("index.json", chats: chats)
   end
 
-  def create(%{assigns: %{user: user}} = conn, params) do
-    with %User{ap_id: recipient} <- User.get_by_id(params[:id]),
+  def create(%{assigns: %{user: user}} = conn, %{id: id}) do
+    with %User{ap_id: recipient} <- User.get_cached_by_id(id),
          {:ok, %Chat{} = chat} <- Chat.get_or_create(user.id, recipient) do
       conn
       |> put_view(ChatView)
@@ -174,8 +162,8 @@ defmodule Pleroma.Web.PleromaAPI.ChatController do
     end
   end
 
-  def show(%{assigns: %{user: user}} = conn, params) do
-    with %Chat{} = chat <- Repo.get_by(Chat, user_id: user.id, id: params[:id]) do
+  def show(%{assigns: %{user: user}} = conn, %{id: id}) do
+    with {:ok, chat} <- Chat.get_by_user_and_id(user, id) do
       conn
       |> put_view(ChatView)
       |> render("show.json", chat: chat)
diff --git a/lib/pleroma/web/pleroma_api/controllers/emoji_file_controller.ex b/lib/pleroma/web/pleroma_api/controllers/emoji_file_controller.ex
new file mode 100644 (file)
index 0000000..71c53df
--- /dev/null
@@ -0,0 +1,133 @@
+defmodule Pleroma.Web.PleromaAPI.EmojiFileController do
+  use Pleroma.Web, :controller
+
+  alias Pleroma.Emoji.Pack
+  alias Pleroma.Web.ApiSpec
+
+  plug(Pleroma.Web.ApiSpec.CastAndValidate)
+
+  plug(
+    Pleroma.Plugs.OAuthScopesPlug,
+    %{scopes: ["write"], admin: true}
+    when action in [
+           :create,
+           :update,
+           :delete
+         ]
+  )
+
+  defdelegate open_api_operation(action), to: ApiSpec.PleromaEmojiFileOperation
+
+  def create(%{body_params: params} = conn, %{name: pack_name}) 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})
+    end
+  end
+
+  def update(%{body_params: %{shortcode: shortcode} = params} = conn, %{name: pack_name}) 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})
+    end
+  end
+
+  def delete(conn, %{name: pack_name, shortcode: shortcode}) 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})
+    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, :not_found}, %{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."
+    )
+  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
index 657f4632451a192a0bf34dccb1bfe928d5e3c5d6..e3969fee103dd2bf9b2c73e48f814b8d8d4c72d4 100644 (file)
@@ -14,10 +14,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiPackController do
            :download,
            :create,
            :update,
-           :delete,
-           :add_file,
-           :update_file,
-           :delete_file
+           :delete
          ]
   )
 
@@ -184,105 +181,6 @@ defmodule Pleroma.Web.PleromaAPI.EmojiPackController do
     end
   end
 
-  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
-      json(conn, pack.files)
-    else
-      {:error, :already_exists} ->
-        conn
-        |> put_status(:conflict)
-        |> json(%{error: "An emoji with the \"#{shortcode}\" shortcode already exists"})
-
-      {:error, :not_found} ->
-        conn
-        |> put_status(:bad_request)
-        |> json(%{error: "pack \"#{name}\" is not found"})
-
-      {:error, :empty_values} ->
-        conn
-        |> put_status(:bad_request)
-        |> json(%{error: "pack name, shortcode or filename cannot be empty"})
-
-      {:error, _} ->
-        render_error(
-          conn,
-          :internal_server_error,
-          "Unexpected error occurred while adding file to pack."
-        )
-    end
-  end
-
-  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
-      json(conn, pack.files)
-    else
-      {:error, :doesnt_exist} ->
-        conn
-        |> put_status(:bad_request)
-        |> json(%{error: "Emoji \"#{shortcode}\" does not exist"})
-
-      {: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, :not_found} ->
-        conn
-        |> put_status(:bad_request)
-        |> json(%{error: "pack \"#{name}\" is not found"})
-
-      {:error, :empty_values} ->
-        conn
-        |> put_status(:bad_request)
-        |> json(%{error: "new_shortcode or new_filename cannot be empty"})
-
-      {:error, _} ->
-        render_error(
-          conn,
-          :internal_server_error,
-          "Unexpected error occurred while updating file in pack."
-        )
-    end
-  end
-
-  def delete_file(conn, %{name: name, shortcode: shortcode}) do
-    with {:ok, pack} <- Pack.delete_file(name, shortcode) do
-      json(conn, pack.files)
-    else
-      {:error, :doesnt_exist} ->
-        conn
-        |> put_status(:bad_request)
-        |> json(%{error: "Emoji \"#{shortcode}\" does not exist"})
-
-      {:error, :not_found} ->
-        conn
-        |> put_status(:bad_request)
-        |> json(%{error: "pack \"#{name}\" is not found"})
-
-      {:error, :empty_values} ->
-        conn
-        |> put_status(:bad_request)
-        |> json(%{error: "pack name or shortcode cannot be empty"})
-
-      {:error, _} ->
-        render_error(
-          conn,
-          :internal_server_error,
-          "Unexpected error occurred while removing file from pack."
-        )
-    end
-  end
-
   def import_from_filesystem(conn, _params) do
     with {:ok, names} <- Pack.import_from_filesystem() do
       json(conn, names)
@@ -298,7 +196,4 @@ defmodule Pleroma.Web.PleromaAPI.EmojiPackController do
         |> json(%{error: "Error accessing emoji pack directory"})
     end
   end
-
-  defp get_filename(%Plug.Upload{filename: filename}), do: filename
-  defp get_filename(url) when is_binary(url), do: Path.basename(url)
 end
index f924e1e916967e966d3bc900096f6827bbae8379..42a9db21da91cf9d902f686210c26cea15419779 100644 (file)
@@ -238,9 +238,9 @@ defmodule Pleroma.Web.Router do
       patch("/:name", EmojiPackController, :update)
       delete("/:name", EmojiPackController, :delete)
 
-      post("/:name/files", EmojiPackController, :add_file)
-      patch("/:name/files", EmojiPackController, :update_file)
-      delete("/:name/files", EmojiPackController, :delete_file)
+      post("/:name/files", EmojiFileController, :create)
+      patch("/:name/files", EmojiFileController, :update)
+      delete("/:name/files", EmojiFileController, :delete)
     end
 
     # Pack info / downloading
diff --git a/test/emoji/pack_test.exs b/test/emoji/pack_test.exs
new file mode 100644 (file)
index 0000000..70d1eaa
--- /dev/null
@@ -0,0 +1,93 @@
+# Pleroma: A lightweight social networking server
+# Copyright Â© 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Emoji.PackTest do
+  use ExUnit.Case, async: true
+  alias Pleroma.Emoji.Pack
+
+  @emoji_path Path.join(
+                Pleroma.Config.get!([:instance, :static_dir]),
+                "emoji"
+              )
+
+  setup do
+    pack_path = Path.join(@emoji_path, "dump_pack")
+    File.mkdir(pack_path)
+
+    File.write!(Path.join(pack_path, "pack.json"), """
+    {
+    "files": { },
+    "pack": {
+    "description": "Dump pack", "homepage": "https://pleroma.social",
+    "license": "Test license", "share-files": true
+    }}
+    """)
+
+    {:ok, pack} = Pleroma.Emoji.Pack.load_pack("dump_pack")
+
+    on_exit(fn ->
+      File.rm_rf!(pack_path)
+    end)
+
+    {:ok, pack: pack}
+  end
+
+  describe "add_file/4" do
+    test "add emojies from zip file", %{pack: pack} do
+      file = %Plug.Upload{
+        content_type: "application/zip",
+        filename: "emojis.zip",
+        path: Path.absname("test/fixtures/emojis.zip")
+      }
+
+      {:ok, updated_pack} = Pack.add_file(pack, nil, nil, file)
+
+      assert updated_pack.files == %{
+               "a_trusted_friend-128" => "128px/a_trusted_friend-128.png",
+               "auroraborealis" => "auroraborealis.png",
+               "baby_in_a_box" => "1000px/baby_in_a_box.png",
+               "bear" => "1000px/bear.png",
+               "bear-128" => "128px/bear-128.png"
+             }
+
+      assert updated_pack.files_count == 5
+    end
+  end
+
+  test "returns error when zip file is bad", %{pack: pack} do
+    file = %Plug.Upload{
+      content_type: "application/zip",
+      filename: "emojis.zip",
+      path: Path.absname("test/instance_static/emoji/test_pack/blank.png")
+    }
+
+    assert Pack.add_file(pack, nil, nil, file) == {:error, :einval}
+  end
+
+  test "returns pack when zip file is empty", %{pack: pack} do
+    file = %Plug.Upload{
+      content_type: "application/zip",
+      filename: "emojis.zip",
+      path: Path.absname("test/fixtures/empty.zip")
+    }
+
+    {:ok, updated_pack} = Pack.add_file(pack, nil, nil, file)
+    assert updated_pack == pack
+  end
+
+  test "add emoji file", %{pack: pack} do
+    file = %Plug.Upload{
+      filename: "blank.png",
+      path: "#{@emoji_path}/test_pack/blank.png"
+    }
+
+    {:ok, updated_pack} = Pack.add_file(pack, "test_blank", "test_blank.png", file)
+
+    assert updated_pack.files == %{
+             "test_blank" => "test_blank.png"
+           }
+
+    assert updated_pack.files_count == 1
+  end
+end
diff --git a/test/fixtures/emojis.zip b/test/fixtures/emojis.zip
new file mode 100644 (file)
index 0000000..d7fc473
Binary files /dev/null and b/test/fixtures/emojis.zip differ
diff --git a/test/fixtures/empty.zip b/test/fixtures/empty.zip
new file mode 100644 (file)
index 0000000..15cb0ec
Binary files /dev/null and b/test/fixtures/empty.zip differ
diff --git a/test/user/query_test.exs b/test/user/query_test.exs
new file mode 100644 (file)
index 0000000..e2f5c7d
--- /dev/null
@@ -0,0 +1,37 @@
+# Pleroma: A lightweight social networking server
+# Copyright Â© 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.User.QueryTest do
+  use Pleroma.DataCase, async: true
+
+  alias Pleroma.Repo
+  alias Pleroma.User
+  alias Pleroma.User.Query
+  alias Pleroma.Web.ActivityPub.InternalFetchActor
+
+  import Pleroma.Factory
+
+  describe "internal users" do
+    test "it filters out internal users by default" do
+      %User{nickname: "internal.fetch"} = InternalFetchActor.get_actor()
+
+      assert [_user] = User |> Repo.all()
+      assert [] == %{} |> Query.build() |> Repo.all()
+    end
+
+    test "it filters out users without nickname by default" do
+      insert(:user, %{nickname: nil})
+
+      assert [_user] = User |> Repo.all()
+      assert [] == %{} |> Query.build() |> Repo.all()
+    end
+
+    test "it returns internal users when enabled" do
+      %User{nickname: "internal.fetch"} = InternalFetchActor.get_actor()
+      insert(:user, %{nickname: nil})
+
+      assert %{internal: true} |> Query.build() |> Repo.aggregate(:count) == 2
+    end
+  end
+end
index cceb14eb9525cf94707b2f15999a5e4a068e6695..d506f704708a6c7f501bf51db735b8f5cd301b21 100644 (file)
@@ -509,7 +509,12 @@ defmodule Pleroma.UserTest do
       cng = User.register_changeset(%User{}, @full_user_data)
       {:ok, registered_user} = User.register(cng)
       ObanHelpers.perform_all()
-      assert_email_sent(Pleroma.Emails.UserEmail.account_confirmation_email(registered_user))
+
+      Pleroma.Emails.UserEmail.account_confirmation_email(registered_user)
+      # temporary hackney fix until hackney max_connections bug is fixed
+      # https://git.pleroma.social/pleroma/pleroma/-/issues/2101
+      |> Swoosh.Email.put_private(:hackney_options, ssl_options: [versions: [:"tlsv1.2"]])
+      |> assert_email_sent()
     end
 
     test "it requires an email, name, nickname and password, bio is optional when account_activation_required is enabled" do
diff --git a/test/utils_test.exs b/test/utils_test.exs
new file mode 100644 (file)
index 0000000..3a730d5
--- /dev/null
@@ -0,0 +1,15 @@
+# Pleroma: A lightweight social networking server
+# Copyright Â© 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.UtilsTest do
+  use ExUnit.Case, async: true
+
+  describe "tmp_dir/1" do
+    test "returns unique temporary directory" do
+      {:ok, path} = Pleroma.Utils.tmp_dir("emoji")
+      assert path =~ ~r/\/tmp\/emoji-(.*)-#{:os.getpid()}-(.*)/
+      File.rm_rf(path)
+    end
+  end
+end
index e4d3512deb0ad163acc007a1e2a222c9ebe70762..cba6b43d32a7d1a3e8519d5ebcc74d55e025256b 100644 (file)
@@ -1977,7 +1977,12 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
                }"
 
       ObanHelpers.perform_all()
-      assert_email_sent(Pleroma.Emails.UserEmail.account_confirmation_email(first_user))
+
+      Pleroma.Emails.UserEmail.account_confirmation_email(first_user)
+      # temporary hackney fix until hackney max_connections bug is fixed
+      # https://git.pleroma.social/pleroma/pleroma/-/issues/2101
+      |> Swoosh.Email.put_private(:hackney_options, ssl_options: [versions: [:"tlsv1.2"]])
+      |> assert_email_sent()
     end
   end
 
index 4fa95fce1ca464f35d26adfc07d455b1d6b84215..bf2438fe2da61f5c9c34a035b71fb6a3222f2892 100644 (file)
@@ -61,7 +61,7 @@ defmodule Pleroma.Web.MastodonAPI.AuthControllerTest do
     end
 
     test "it returns 204", %{conn: conn} do
-      assert json_response(conn, :no_content)
+      assert empty_json_response(conn)
     end
 
     test "it creates a PasswordResetToken record for user", %{user: user} do
@@ -91,7 +91,7 @@ defmodule Pleroma.Web.MastodonAPI.AuthControllerTest do
 
       assert conn
              |> post("/auth/password?nickname=#{user.nickname}")
-             |> json_response(:no_content)
+             |> empty_json_response()
 
       ObanHelpers.perform_all()
       token_record = Repo.get_by(Pleroma.PasswordResetToken, user_id: user.id)
@@ -112,7 +112,7 @@ defmodule Pleroma.Web.MastodonAPI.AuthControllerTest do
 
       assert conn
              |> post("/auth/password?nickname=#{user.nickname}")
-             |> json_response(:no_content)
+             |> empty_json_response()
     end
   end
 
@@ -125,24 +125,21 @@ defmodule Pleroma.Web.MastodonAPI.AuthControllerTest do
     test "it returns 204 when user is not found", %{conn: conn, user: user} do
       conn = post(conn, "/auth/password?email=nonexisting_#{user.email}")
 
-      assert conn
-             |> json_response(:no_content)
+      assert empty_json_response(conn)
     end
 
     test "it returns 204 when user is not local", %{conn: conn, user: user} do
       {:ok, user} = Repo.update(Ecto.Changeset.change(user, local: false))
       conn = post(conn, "/auth/password?email=#{user.email}")
 
-      assert conn
-             |> json_response(:no_content)
+      assert empty_json_response(conn)
     end
 
     test "it returns 204 when user is deactivated", %{conn: conn, user: user} do
       {:ok, user} = Repo.update(Ecto.Changeset.change(user, deactivated: true, local: true))
       conn = post(conn, "/auth/password?email=#{user.email}")
 
-      assert conn
-             |> json_response(:no_content)
+      assert empty_json_response(conn)
     end
   end
 
index 44a78a738f35527b3153db96dcce6c05a6fe9be5..11d5ba3739def5970ba9875dcd7658ac9b1ba3bf 100644 (file)
@@ -2,7 +2,7 @@
 # Copyright Â© 2017-2020 Pleroma Authors <https://pleroma.social/>
 # SPDX-License-Identifier: AGPL-3.0-only
 defmodule Pleroma.Web.PleromaAPI.ChatControllerTest do
-  use Pleroma.Web.ConnCase, async: true
+  use Pleroma.Web.ConnCase
 
   alias Pleroma.Chat
   alias Pleroma.Chat.MessageReference
@@ -201,17 +201,39 @@ defmodule Pleroma.Web.PleromaAPI.ChatControllerTest do
 
       chat = Chat.get(user.id, recipient.ap_id)
 
-      result =
-        conn
-        |> get("/api/v1/pleroma/chats/#{chat.id}/messages")
-        |> json_response_and_validate_schema(200)
+      response = get(conn, "/api/v1/pleroma/chats/#{chat.id}/messages")
+      result = json_response_and_validate_schema(response, 200)
+
+      [next, prev] = get_resp_header(response, "link") |> hd() |> String.split(", ")
+      api_endpoint = "/api/v1/pleroma/chats/"
+
+      assert String.match?(
+               next,
+               ~r(#{api_endpoint}.*/messages\?id=.*&limit=\d+&max_id=.*; rel=\"next\"$)
+             )
+
+      assert String.match?(
+               prev,
+               ~r(#{api_endpoint}.*/messages\?id=.*&limit=\d+&min_id=.*; rel=\"prev\"$)
+             )
 
       assert length(result) == 20
 
-      result =
-        conn
-        |> get("/api/v1/pleroma/chats/#{chat.id}/messages?max_id=#{List.last(result)["id"]}")
-        |> json_response_and_validate_schema(200)
+      response =
+        get(conn, "/api/v1/pleroma/chats/#{chat.id}/messages?max_id=#{List.last(result)["id"]}")
+
+      result = json_response_and_validate_schema(response, 200)
+      [next, prev] = get_resp_header(response, "link") |> hd() |> String.split(", ")
+
+      assert String.match?(
+               next,
+               ~r(#{api_endpoint}.*/messages\?id=.*&limit=\d+&max_id=.*; rel=\"next\"$)
+             )
+
+      assert String.match?(
+               prev,
+               ~r(#{api_endpoint}.*/messages\?id=.*&limit=\d+&max_id=.*&min_id=.*; rel=\"prev\"$)
+             )
 
       assert length(result) == 10
     end
@@ -240,12 +262,10 @@ defmodule Pleroma.Web.PleromaAPI.ChatControllerTest do
       assert length(result) == 3
 
       # Trying to get the chat of a different user
-      result =
-        conn
-        |> assign(:user, other_user)
-        |> get("/api/v1/pleroma/chats/#{chat.id}/messages")
-
-      assert result |> json_response(404)
+      conn
+      |> assign(:user, other_user)
+      |> get("/api/v1/pleroma/chats/#{chat.id}/messages")
+      |> json_response_and_validate_schema(404)
     end
   end
 
diff --git a/test/web/pleroma_api/controllers/emoji_file_controller_test.exs b/test/web/pleroma_api/controllers/emoji_file_controller_test.exs
new file mode 100644 (file)
index 0000000..39b4e1d
--- /dev/null
@@ -0,0 +1,357 @@
+# Pleroma: A lightweight social networking server
+# Copyright Â© 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.PleromaAPI.EmojiFileControllerTest do
+  use Pleroma.Web.ConnCase
+
+  import Tesla.Mock
+  import Pleroma.Factory
+
+  @emoji_path Path.join(
+                Pleroma.Config.get!([:instance, :static_dir]),
+                "emoji"
+              )
+  setup do: clear_config([:auth, :enforce_oauth_admin_scope_usage], false)
+
+  setup do: clear_config([:instance, :public], true)
+
+  setup do
+    admin = insert(:user, is_admin: true)
+    token = insert(:oauth_admin_token, user: admin)
+
+    admin_conn =
+      build_conn()
+      |> assign(:user, admin)
+      |> assign(:token, token)
+
+    Pleroma.Emoji.reload()
+    {:ok, %{admin_conn: admin_conn}}
+  end
+
+  describe "POST/PATCH/DELETE /api/pleroma/emoji/packs/:name/files" do
+    setup do
+      pack_file = "#{@emoji_path}/test_pack/pack.json"
+      original_content = File.read!(pack_file)
+
+      on_exit(fn ->
+        File.write!(pack_file, original_content)
+      end)
+
+      :ok
+    end
+
+    test "upload zip file with emojies", %{admin_conn: admin_conn} do
+      on_exit(fn ->
+        [
+          "128px/a_trusted_friend-128.png",
+          "auroraborealis.png",
+          "1000px/baby_in_a_box.png",
+          "1000px/bear.png",
+          "128px/bear-128.png"
+        ]
+        |> Enum.each(fn path -> File.rm_rf!("#{@emoji_path}/test_pack/#{path}") end)
+      end)
+
+      resp =
+        admin_conn
+        |> put_req_header("content-type", "multipart/form-data")
+        |> post("/api/pleroma/emoji/packs/test_pack/files", %{
+          file: %Plug.Upload{
+            content_type: "application/zip",
+            filename: "emojis.zip",
+            path: Path.absname("test/fixtures/emojis.zip")
+          }
+        })
+        |> json_response_and_validate_schema(200)
+
+      assert resp == %{
+               "a_trusted_friend-128" => "128px/a_trusted_friend-128.png",
+               "auroraborealis" => "auroraborealis.png",
+               "baby_in_a_box" => "1000px/baby_in_a_box.png",
+               "bear" => "1000px/bear.png",
+               "bear-128" => "128px/bear-128.png",
+               "blank" => "blank.png",
+               "blank2" => "blank2.png"
+             }
+
+      Enum.each(Map.values(resp), fn path ->
+        assert File.exists?("#{@emoji_path}/test_pack/#{path}")
+      end)
+    end
+
+    test "create shortcode exists", %{admin_conn: admin_conn} do
+      assert admin_conn
+             |> put_req_header("content-type", "multipart/form-data")
+             |> post("/api/pleroma/emoji/packs/test_pack/files", %{
+               shortcode: "blank",
+               filename: "dir/blank.png",
+               file: %Plug.Upload{
+                 filename: "blank.png",
+                 path: "#{@emoji_path}/test_pack/blank.png"
+               }
+             })
+             |> json_response_and_validate_schema(:conflict) == %{
+               "error" => "An emoji with the \"blank\" shortcode already exists"
+             }
+    end
+
+    test "don't rewrite old emoji", %{admin_conn: admin_conn} do
+      on_exit(fn -> File.rm_rf!("#{@emoji_path}/test_pack/dir/") end)
+
+      assert admin_conn
+             |> put_req_header("content-type", "multipart/form-data")
+             |> post("/api/pleroma/emoji/packs/test_pack/files", %{
+               shortcode: "blank3",
+               filename: "dir/blank.png",
+               file: %Plug.Upload{
+                 filename: "blank.png",
+                 path: "#{@emoji_path}/test_pack/blank.png"
+               }
+             })
+             |> json_response_and_validate_schema(200) == %{
+               "blank" => "blank.png",
+               "blank2" => "blank2.png",
+               "blank3" => "dir/blank.png"
+             }
+
+      assert File.exists?("#{@emoji_path}/test_pack/dir/blank.png")
+
+      assert admin_conn
+             |> put_req_header("content-type", "multipart/form-data")
+             |> patch("/api/pleroma/emoji/packs/test_pack/files", %{
+               shortcode: "blank",
+               new_shortcode: "blank2",
+               new_filename: "dir_2/blank_3.png"
+             })
+             |> json_response_and_validate_schema(:conflict) == %{
+               "error" =>
+                 "New shortcode \"blank2\" is already used. If you want to override emoji use 'force' option"
+             }
+    end
+
+    test "rewrite old emoji with force option", %{admin_conn: admin_conn} do
+      on_exit(fn -> File.rm_rf!("#{@emoji_path}/test_pack/dir_2/") end)
+
+      assert admin_conn
+             |> put_req_header("content-type", "multipart/form-data")
+             |> post("/api/pleroma/emoji/packs/test_pack/files", %{
+               shortcode: "blank3",
+               filename: "dir/blank.png",
+               file: %Plug.Upload{
+                 filename: "blank.png",
+                 path: "#{@emoji_path}/test_pack/blank.png"
+               }
+             })
+             |> json_response_and_validate_schema(200) == %{
+               "blank" => "blank.png",
+               "blank2" => "blank2.png",
+               "blank3" => "dir/blank.png"
+             }
+
+      assert File.exists?("#{@emoji_path}/test_pack/dir/blank.png")
+
+      assert admin_conn
+             |> put_req_header("content-type", "multipart/form-data")
+             |> patch("/api/pleroma/emoji/packs/test_pack/files", %{
+               shortcode: "blank3",
+               new_shortcode: "blank4",
+               new_filename: "dir_2/blank_3.png",
+               force: true
+             })
+             |> json_response_and_validate_schema(200) == %{
+               "blank" => "blank.png",
+               "blank2" => "blank2.png",
+               "blank4" => "dir_2/blank_3.png"
+             }
+
+      assert File.exists?("#{@emoji_path}/test_pack/dir_2/blank_3.png")
+    end
+
+    test "with empty filename", %{admin_conn: admin_conn} do
+      assert admin_conn
+             |> put_req_header("content-type", "multipart/form-data")
+             |> post("/api/pleroma/emoji/packs/test_pack/files", %{
+               shortcode: "blank2",
+               filename: "",
+               file: %Plug.Upload{
+                 filename: "blank.png",
+                 path: "#{@emoji_path}/test_pack/blank.png"
+               }
+             })
+             |> json_response_and_validate_schema(422) == %{
+               "error" => "pack name, shortcode or filename cannot be empty"
+             }
+    end
+
+    test "add file with not loaded pack", %{admin_conn: admin_conn} do
+      assert admin_conn
+             |> put_req_header("content-type", "multipart/form-data")
+             |> post("/api/pleroma/emoji/packs/not_loaded/files", %{
+               shortcode: "blank3",
+               filename: "dir/blank.png",
+               file: %Plug.Upload{
+                 filename: "blank.png",
+                 path: "#{@emoji_path}/test_pack/blank.png"
+               }
+             })
+             |> json_response_and_validate_schema(:not_found) == %{
+               "error" => "pack \"not_loaded\" is not found"
+             }
+    end
+
+    test "remove file with not loaded pack", %{admin_conn: admin_conn} do
+      assert admin_conn
+             |> delete("/api/pleroma/emoji/packs/not_loaded/files?shortcode=blank3")
+             |> json_response_and_validate_schema(:not_found) == %{
+               "error" => "pack \"not_loaded\" is not found"
+             }
+    end
+
+    test "remove file with empty shortcode", %{admin_conn: admin_conn} do
+      assert admin_conn
+             |> delete("/api/pleroma/emoji/packs/not_loaded/files?shortcode=")
+             |> json_response_and_validate_schema(:not_found) == %{
+               "error" => "pack \"not_loaded\" is not found"
+             }
+    end
+
+    test "update file with not loaded pack", %{admin_conn: admin_conn} do
+      assert admin_conn
+             |> put_req_header("content-type", "multipart/form-data")
+             |> patch("/api/pleroma/emoji/packs/not_loaded/files", %{
+               shortcode: "blank4",
+               new_shortcode: "blank3",
+               new_filename: "dir_2/blank_3.png"
+             })
+             |> json_response_and_validate_schema(:not_found) == %{
+               "error" => "pack \"not_loaded\" is not found"
+             }
+    end
+
+    test "new with shortcode as file with update", %{admin_conn: admin_conn} do
+      assert admin_conn
+             |> put_req_header("content-type", "multipart/form-data")
+             |> post("/api/pleroma/emoji/packs/test_pack/files", %{
+               shortcode: "blank4",
+               filename: "dir/blank.png",
+               file: %Plug.Upload{
+                 filename: "blank.png",
+                 path: "#{@emoji_path}/test_pack/blank.png"
+               }
+             })
+             |> json_response_and_validate_schema(200) == %{
+               "blank" => "blank.png",
+               "blank4" => "dir/blank.png",
+               "blank2" => "blank2.png"
+             }
+
+      assert File.exists?("#{@emoji_path}/test_pack/dir/blank.png")
+
+      assert admin_conn
+             |> put_req_header("content-type", "multipart/form-data")
+             |> patch("/api/pleroma/emoji/packs/test_pack/files", %{
+               shortcode: "blank4",
+               new_shortcode: "blank3",
+               new_filename: "dir_2/blank_3.png"
+             })
+             |> json_response_and_validate_schema(200) == %{
+               "blank3" => "dir_2/blank_3.png",
+               "blank" => "blank.png",
+               "blank2" => "blank2.png"
+             }
+
+      refute File.exists?("#{@emoji_path}/test_pack/dir/")
+      assert File.exists?("#{@emoji_path}/test_pack/dir_2/blank_3.png")
+
+      assert admin_conn
+             |> delete("/api/pleroma/emoji/packs/test_pack/files?shortcode=blank3")
+             |> json_response_and_validate_schema(200) == %{
+               "blank" => "blank.png",
+               "blank2" => "blank2.png"
+             }
+
+      refute File.exists?("#{@emoji_path}/test_pack/dir_2/")
+
+      on_exit(fn -> File.rm_rf!("#{@emoji_path}/test_pack/dir") end)
+    end
+
+    test "new with shortcode from url", %{admin_conn: admin_conn} do
+      mock(fn
+        %{
+          method: :get,
+          url: "https://test-blank/blank_url.png"
+        } ->
+          text(File.read!("#{@emoji_path}/test_pack/blank.png"))
+      end)
+
+      assert admin_conn
+             |> put_req_header("content-type", "multipart/form-data")
+             |> post("/api/pleroma/emoji/packs/test_pack/files", %{
+               shortcode: "blank_url",
+               file: "https://test-blank/blank_url.png"
+             })
+             |> json_response_and_validate_schema(200) == %{
+               "blank_url" => "blank_url.png",
+               "blank" => "blank.png",
+               "blank2" => "blank2.png"
+             }
+
+      assert File.exists?("#{@emoji_path}/test_pack/blank_url.png")
+
+      on_exit(fn -> File.rm_rf!("#{@emoji_path}/test_pack/blank_url.png") end)
+    end
+
+    test "new without shortcode", %{admin_conn: admin_conn} do
+      on_exit(fn -> File.rm_rf!("#{@emoji_path}/test_pack/shortcode.png") end)
+
+      assert admin_conn
+             |> put_req_header("content-type", "multipart/form-data")
+             |> post("/api/pleroma/emoji/packs/test_pack/files", %{
+               file: %Plug.Upload{
+                 filename: "shortcode.png",
+                 path: "#{Pleroma.Config.get([:instance, :static_dir])}/add/shortcode.png"
+               }
+             })
+             |> json_response_and_validate_schema(200) == %{
+               "shortcode" => "shortcode.png",
+               "blank" => "blank.png",
+               "blank2" => "blank2.png"
+             }
+    end
+
+    test "remove non existing shortcode in pack.json", %{admin_conn: admin_conn} do
+      assert admin_conn
+             |> delete("/api/pleroma/emoji/packs/test_pack/files?shortcode=blank3")
+             |> json_response_and_validate_schema(:bad_request) == %{
+               "error" => "Emoji \"blank3\" does not exist"
+             }
+    end
+
+    test "update non existing emoji", %{admin_conn: admin_conn} do
+      assert admin_conn
+             |> put_req_header("content-type", "multipart/form-data")
+             |> patch("/api/pleroma/emoji/packs/test_pack/files", %{
+               shortcode: "blank3",
+               new_shortcode: "blank4",
+               new_filename: "dir_2/blank_3.png"
+             })
+             |> json_response_and_validate_schema(:bad_request) == %{
+               "error" => "Emoji \"blank3\" does not exist"
+             }
+    end
+
+    test "update with empty shortcode", %{admin_conn: admin_conn} do
+      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
index e113bb15fb679697f89093d45a01866e84f39532..a34df2c18b8311c47eac41c5e0cf85424ef71860 100644 (file)
@@ -411,293 +411,6 @@ defmodule Pleroma.Web.PleromaAPI.EmojiPackControllerTest do
     end
   end
 
-  describe "POST/PATCH/DELETE /api/pleroma/emoji/packs/:name/files" do
-    setup do
-      pack_file = "#{@emoji_path}/test_pack/pack.json"
-      original_content = File.read!(pack_file)
-
-      on_exit(fn ->
-        File.write!(pack_file, original_content)
-      end)
-
-      :ok
-    end
-
-    test "create shortcode exists", %{admin_conn: admin_conn} do
-      assert admin_conn
-             |> put_req_header("content-type", "multipart/form-data")
-             |> post("/api/pleroma/emoji/packs/test_pack/files", %{
-               shortcode: "blank",
-               filename: "dir/blank.png",
-               file: %Plug.Upload{
-                 filename: "blank.png",
-                 path: "#{@emoji_path}/test_pack/blank.png"
-               }
-             })
-             |> json_response_and_validate_schema(:conflict) == %{
-               "error" => "An emoji with the \"blank\" shortcode already exists"
-             }
-    end
-
-    test "don't rewrite old emoji", %{admin_conn: admin_conn} do
-      on_exit(fn -> File.rm_rf!("#{@emoji_path}/test_pack/dir/") end)
-
-      assert admin_conn
-             |> put_req_header("content-type", "multipart/form-data")
-             |> post("/api/pleroma/emoji/packs/test_pack/files", %{
-               shortcode: "blank3",
-               filename: "dir/blank.png",
-               file: %Plug.Upload{
-                 filename: "blank.png",
-                 path: "#{@emoji_path}/test_pack/blank.png"
-               }
-             })
-             |> json_response_and_validate_schema(200) == %{
-               "blank" => "blank.png",
-               "blank2" => "blank2.png",
-               "blank3" => "dir/blank.png"
-             }
-
-      assert File.exists?("#{@emoji_path}/test_pack/dir/blank.png")
-
-      assert admin_conn
-             |> put_req_header("content-type", "multipart/form-data")
-             |> patch("/api/pleroma/emoji/packs/test_pack/files", %{
-               shortcode: "blank",
-               new_shortcode: "blank2",
-               new_filename: "dir_2/blank_3.png"
-             })
-             |> json_response_and_validate_schema(:conflict) == %{
-               "error" =>
-                 "New shortcode \"blank2\" is already used. If you want to override emoji use 'force' option"
-             }
-    end
-
-    test "rewrite old emoji with force option", %{admin_conn: admin_conn} do
-      on_exit(fn -> File.rm_rf!("#{@emoji_path}/test_pack/dir_2/") end)
-
-      assert admin_conn
-             |> put_req_header("content-type", "multipart/form-data")
-             |> post("/api/pleroma/emoji/packs/test_pack/files", %{
-               shortcode: "blank3",
-               filename: "dir/blank.png",
-               file: %Plug.Upload{
-                 filename: "blank.png",
-                 path: "#{@emoji_path}/test_pack/blank.png"
-               }
-             })
-             |> json_response_and_validate_schema(200) == %{
-               "blank" => "blank.png",
-               "blank2" => "blank2.png",
-               "blank3" => "dir/blank.png"
-             }
-
-      assert File.exists?("#{@emoji_path}/test_pack/dir/blank.png")
-
-      assert admin_conn
-             |> put_req_header("content-type", "multipart/form-data")
-             |> patch("/api/pleroma/emoji/packs/test_pack/files", %{
-               shortcode: "blank3",
-               new_shortcode: "blank4",
-               new_filename: "dir_2/blank_3.png",
-               force: true
-             })
-             |> json_response_and_validate_schema(200) == %{
-               "blank" => "blank.png",
-               "blank2" => "blank2.png",
-               "blank4" => "dir_2/blank_3.png"
-             }
-
-      assert File.exists?("#{@emoji_path}/test_pack/dir_2/blank_3.png")
-    end
-
-    test "with empty filename", %{admin_conn: admin_conn} do
-      assert admin_conn
-             |> put_req_header("content-type", "multipart/form-data")
-             |> post("/api/pleroma/emoji/packs/test_pack/files", %{
-               shortcode: "blank2",
-               filename: "",
-               file: %Plug.Upload{
-                 filename: "blank.png",
-                 path: "#{@emoji_path}/test_pack/blank.png"
-               }
-             })
-             |> json_response_and_validate_schema(:bad_request) == %{
-               "error" => "pack name, shortcode or filename cannot be empty"
-             }
-    end
-
-    test "add file with not loaded pack", %{admin_conn: admin_conn} do
-      assert admin_conn
-             |> put_req_header("content-type", "multipart/form-data")
-             |> post("/api/pleroma/emoji/packs/not_loaded/files", %{
-               shortcode: "blank3",
-               filename: "dir/blank.png",
-               file: %Plug.Upload{
-                 filename: "blank.png",
-                 path: "#{@emoji_path}/test_pack/blank.png"
-               }
-             })
-             |> json_response_and_validate_schema(:bad_request) == %{
-               "error" => "pack \"not_loaded\" is not found"
-             }
-    end
-
-    test "remove file with not loaded pack", %{admin_conn: admin_conn} do
-      assert admin_conn
-             |> 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
-
-    test "remove file with empty shortcode", %{admin_conn: admin_conn} do
-      assert admin_conn
-             |> delete("/api/pleroma/emoji/packs/not_loaded/files?shortcode=")
-             |> json_response_and_validate_schema(:bad_request) == %{
-               "error" => "pack name or shortcode cannot be empty"
-             }
-    end
-
-    test "update file with not loaded pack", %{admin_conn: admin_conn} do
-      assert admin_conn
-             |> put_req_header("content-type", "multipart/form-data")
-             |> patch("/api/pleroma/emoji/packs/not_loaded/files", %{
-               shortcode: "blank4",
-               new_shortcode: "blank3",
-               new_filename: "dir_2/blank_3.png"
-             })
-             |> json_response_and_validate_schema(:bad_request) == %{
-               "error" => "pack \"not_loaded\" is not found"
-             }
-    end
-
-    test "new with shortcode as file with update", %{admin_conn: admin_conn} do
-      assert admin_conn
-             |> put_req_header("content-type", "multipart/form-data")
-             |> post("/api/pleroma/emoji/packs/test_pack/files", %{
-               shortcode: "blank4",
-               filename: "dir/blank.png",
-               file: %Plug.Upload{
-                 filename: "blank.png",
-                 path: "#{@emoji_path}/test_pack/blank.png"
-               }
-             })
-             |> json_response_and_validate_schema(200) == %{
-               "blank" => "blank.png",
-               "blank4" => "dir/blank.png",
-               "blank2" => "blank2.png"
-             }
-
-      assert File.exists?("#{@emoji_path}/test_pack/dir/blank.png")
-
-      assert admin_conn
-             |> put_req_header("content-type", "multipart/form-data")
-             |> patch("/api/pleroma/emoji/packs/test_pack/files", %{
-               shortcode: "blank4",
-               new_shortcode: "blank3",
-               new_filename: "dir_2/blank_3.png"
-             })
-             |> json_response_and_validate_schema(200) == %{
-               "blank3" => "dir_2/blank_3.png",
-               "blank" => "blank.png",
-               "blank2" => "blank2.png"
-             }
-
-      refute File.exists?("#{@emoji_path}/test_pack/dir/")
-      assert File.exists?("#{@emoji_path}/test_pack/dir_2/blank_3.png")
-
-      assert admin_conn
-             |> delete("/api/pleroma/emoji/packs/test_pack/files?shortcode=blank3")
-             |> json_response_and_validate_schema(200) == %{
-               "blank" => "blank.png",
-               "blank2" => "blank2.png"
-             }
-
-      refute File.exists?("#{@emoji_path}/test_pack/dir_2/")
-
-      on_exit(fn -> File.rm_rf!("#{@emoji_path}/test_pack/dir") end)
-    end
-
-    test "new with shortcode from url", %{admin_conn: admin_conn} do
-      mock(fn
-        %{
-          method: :get,
-          url: "https://test-blank/blank_url.png"
-        } ->
-          text(File.read!("#{@emoji_path}/test_pack/blank.png"))
-      end)
-
-      assert admin_conn
-             |> put_req_header("content-type", "multipart/form-data")
-             |> post("/api/pleroma/emoji/packs/test_pack/files", %{
-               shortcode: "blank_url",
-               file: "https://test-blank/blank_url.png"
-             })
-             |> json_response_and_validate_schema(200) == %{
-               "blank_url" => "blank_url.png",
-               "blank" => "blank.png",
-               "blank2" => "blank2.png"
-             }
-
-      assert File.exists?("#{@emoji_path}/test_pack/blank_url.png")
-
-      on_exit(fn -> File.rm_rf!("#{@emoji_path}/test_pack/blank_url.png") end)
-    end
-
-    test "new without shortcode", %{admin_conn: admin_conn} do
-      on_exit(fn -> File.rm_rf!("#{@emoji_path}/test_pack/shortcode.png") end)
-
-      assert admin_conn
-             |> put_req_header("content-type", "multipart/form-data")
-             |> post("/api/pleroma/emoji/packs/test_pack/files", %{
-               file: %Plug.Upload{
-                 filename: "shortcode.png",
-                 path: "#{Pleroma.Config.get([:instance, :static_dir])}/add/shortcode.png"
-               }
-             })
-             |> json_response_and_validate_schema(200) == %{
-               "shortcode" => "shortcode.png",
-               "blank" => "blank.png",
-               "blank2" => "blank2.png"
-             }
-    end
-
-    test "remove non existing shortcode in pack.json", %{admin_conn: admin_conn} do
-      assert admin_conn
-             |> delete("/api/pleroma/emoji/packs/test_pack/files?shortcode=blank3")
-             |> json_response_and_validate_schema(:bad_request) == %{
-               "error" => "Emoji \"blank3\" does not exist"
-             }
-    end
-
-    test "update non existing emoji", %{admin_conn: admin_conn} do
-      assert admin_conn
-             |> put_req_header("content-type", "multipart/form-data")
-             |> patch("/api/pleroma/emoji/packs/test_pack/files", %{
-               shortcode: "blank3",
-               new_shortcode: "blank4",
-               new_filename: "dir_2/blank_3.png"
-             })
-             |> json_response_and_validate_schema(:bad_request) == %{
-               "error" => "Emoji \"blank3\" does not exist"
-             }
-    end
-
-    test "update with empty shortcode", %{admin_conn: admin_conn} do
-      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
-
   describe "POST/DELETE /api/pleroma/emoji/packs/:name" do
     test "creating and deleting a pack", %{admin_conn: admin_conn} do
       assert admin_conn