Implememt emoji pack file updating + write tests
authorEkaterina Vaartis <vaartis@cock.li>
Sun, 18 Aug 2019 19:05:38 +0000 (22:05 +0300)
committerEkaterina Vaartis <vaartis@cock.li>
Wed, 18 Sep 2019 21:16:33 +0000 (00:16 +0300)
lib/pleroma/web/emoji_api/emoji_api_controller.ex
lib/pleroma/web/router.ex
test/web/emoji_api_controller_test.exs

index 4873129c4d844ba4802ea409e043656d97c27063..dc3dcf1ea189a724e1d051492777dd7c0550f53b 100644 (file)
@@ -223,7 +223,7 @@ keeping it in cache for #{div(cache_ms, 1000)}s")
     end
   end
 
-  def update_metadata(conn, %{"name" => name, "new_data" => new_data}) do
+  def update_metadata(conn, %{"pack_name" => name, "new_data" => new_data}) do
     pack_dir = Path.join(@emoji_dir_path, name)
     pack_file_p = Path.join(pack_dir, "pack.json")
 
@@ -274,4 +274,134 @@ keeping it in cache for #{div(cache_ms, 1000)}s")
         e
     end
   end
+
+  def update_file(
+        conn,
+        %{"pack_name" => pack_name, "action" => action, "shortcode" => shortcode} = params
+      ) do
+    pack_dir = Path.join(@emoji_dir_path, pack_name)
+    pack_file_p = Path.join(pack_dir, "pack.json")
+
+    full_pack = Jason.decode!(File.read!(pack_file_p))
+
+    res =
+      case action do
+        "add" ->
+          unless Map.has_key?(full_pack["files"], shortcode) do
+            with %{"file" => %Plug.Upload{filename: filename, path: upload_path}} <- params do
+              # If there was a file name provided with the request, use it, otherwise just use the
+              # uploaded file name
+              filename =
+                if Map.has_key?(params, "filename") do
+                  params["filename"]
+                else
+                  filename
+                end
+
+              file_path = Path.join(pack_dir, filename)
+
+              # If the name contains directories, create them
+              if String.contains?(file_path, "/") do
+                File.mkdir_p!(Path.dirname(file_path))
+              end
+
+              # Copy the uploaded file from the temporary directory
+              File.copy!(upload_path, file_path)
+
+              updated_full_pack = put_in(full_pack, ["files", shortcode], filename)
+
+              {:ok, updated_full_pack}
+            else
+              _ -> {:error, conn |> put_status(:bad_request) |> text("\"file\" not provided")}
+            end
+          else
+            {:error,
+             conn
+             |> put_status(:conflict)
+             |> text("An emoji with the \"#{shortcode}\" shortcode already exists")}
+          end
+
+        "remove" ->
+          if Map.has_key?(full_pack["files"], shortcode) do
+            {emoji_file_path, updated_full_pack} = pop_in(full_pack, ["files", shortcode])
+
+            emoji_file_path = Path.join(pack_dir, emoji_file_path)
+
+            # Delete the emoji file
+            File.rm!(emoji_file_path)
+
+            # If the old directory has no more files, remove it
+            if String.contains?(emoji_file_path, "/") do
+              dir = Path.dirname(emoji_file_path)
+
+              if Enum.empty?(File.ls!(dir)) do
+                File.rmdir!(dir)
+              end
+            end
+
+            {:ok, updated_full_pack}
+          else
+            {:error,
+             conn |> put_status(:bad_request) |> text("Emoji \"#{shortcode}\" does not exist")}
+          end
+
+        "update" ->
+          if Map.has_key?(full_pack["files"], shortcode) do
+            with %{"new_shortcode" => new_shortcode, "new_filename" => new_filename} <- params do
+              # First, remove the old shortcode, saving the old path
+              {old_emoji_file_path, updated_full_pack} = pop_in(full_pack, ["files", shortcode])
+              old_emoji_file_path = Path.join(pack_dir, old_emoji_file_path)
+              new_emoji_file_path = Path.join(pack_dir, new_filename)
+
+              # If the name contains directories, create them
+              if String.contains?(new_emoji_file_path, "/") do
+                File.mkdir_p!(Path.dirname(new_emoji_file_path))
+              end
+
+              # Move/Rename the old filename to a new filename
+              # These are probably on the same filesystem, so just rename should work
+              :ok = File.rename(old_emoji_file_path, new_emoji_file_path)
+
+              # If the old directory has no more files, remove it
+              if String.contains?(old_emoji_file_path, "/") do
+                dir = Path.dirname(old_emoji_file_path)
+
+                if Enum.empty?(File.ls!(dir)) do
+                  File.rmdir!(dir)
+                end
+              end
+
+              # Then, put in the new shortcode with the new path
+              updated_full_pack =
+                put_in(updated_full_pack, ["files", new_shortcode], new_filename)
+
+              {:ok, updated_full_pack}
+            else
+              _ ->
+                {:error,
+                 conn
+                 |> put_status(:bad_request)
+                 |> text("new_shortcode or new_file were not specified")}
+            end
+          else
+            {:error,
+             conn |> put_status(:bad_request) |> text("Emoji \"#{shortcode}\" does not exist")}
+          end
+
+        _ ->
+          {:error, conn |> put_status(:bad_request) |> text("Unknown action: #{action}")}
+      end
+
+    case res do
+      {:ok, updated_full_pack} ->
+        # Write the emoji pack file
+        File.write!(pack_file_p, Jason.encode!(updated_full_pack, pretty: true))
+
+        # Return the modified file list
+        conn |> json(updated_full_pack["files"])
+
+      {:error, e} ->
+        e
+    end
+  end
 end
index 471d09c437375b93d173209e7603adf762dbc65c..acd6f740ba8823fe92a0b035eb2363edc586f196 100644 (file)
@@ -218,7 +218,8 @@ defmodule Pleroma.Web.Router do
       # Modifying packs
       pipe_through([:admin_api, :oauth_write])
 
-      post("/update_metadata/:name", EmojiAPIController, :update_metadata)
+      post("/update_file/:pack_name", EmojiAPIController, :update_file)
+      post("/update_metadata/:pack_name", EmojiAPIController, :update_metadata)
       delete("/delete/:name", EmojiAPIController, :delete)
       post("/download_from", EmojiAPIController, :download_from)
     end
index 759a4dc04b9447480eb59f2ecfb1f96bc3c12b20..6d3603da569fb1a63464ecf1b1dbcc8ef1f7e6f7 100644 (file)
@@ -85,11 +85,10 @@ defmodule Pleroma.Web.EmojiAPI.EmojiAPIControllerTest do
 
     admin = insert(:user, info: %{is_admin: true})
 
-    conn = build_conn()
+    conn = build_conn() |> assign(:user, admin)
 
     assert conn
            |> put_req_header("content-type", "application/json")
-           |> assign(:user, admin)
            |> post(
              emoji_api_path(
                conn,
@@ -108,7 +107,6 @@ defmodule Pleroma.Web.EmojiAPI.EmojiAPIControllerTest do
     assert File.exists?("#{@emoji_dir_path}/test_pack2/blank.png")
 
     assert conn
-           |> assign(:user, admin)
            |> delete(emoji_api_path(conn, :delete, "test_pack2"))
            |> response(200) == "ok"
 
@@ -116,11 +114,10 @@ defmodule Pleroma.Web.EmojiAPI.EmojiAPIControllerTest do
 
     # non-shared, downloaded from the fallback URL
 
-    conn = build_conn()
+    conn = build_conn() |> assign(:user, admin)
 
     assert conn
            |> put_req_header("content-type", "application/json")
-           |> assign(:user, admin)
            |> post(
              emoji_api_path(
                conn,
@@ -139,7 +136,6 @@ defmodule Pleroma.Web.EmojiAPI.EmojiAPIControllerTest do
     assert File.exists?("#{@emoji_dir_path}/test_pack_nonshared2/blank.png")
 
     assert conn
-           |> assign(:user, admin)
            |> delete(emoji_api_path(conn, :delete, "test_pack_nonshared2"))
            |> response(200) == "ok"
 
@@ -240,4 +236,65 @@ defmodule Pleroma.Web.EmojiAPI.EmojiAPIControllerTest do
              |> text_response(:bad_request) =~ "does not have all"
     end
   end
+
+  test "updating pack files" do
+    pack_file = "#{@emoji_dir_path}/test_pack/pack.json"
+    original_content = File.read!(pack_file)
+
+    on_exit(fn ->
+      File.write!(pack_file, original_content)
+
+      File.rm_rf!("#{@emoji_dir_path}/test_pack/dir")
+      File.rm_rf!("#{@emoji_dir_path}/test_pack/dir_2")
+    end)
+
+    admin = insert(:user, info: %{is_admin: true})
+
+    conn = build_conn()
+
+    same_name = %{
+      "action" => "add",
+      "shortcode" => "blank",
+      "filename" => "dir/blank.png",
+      "file" => %Plug.Upload{
+        filename: "blank.png",
+        path: "#{@emoji_dir_path}/test_pack/blank.png"
+      }
+    }
+
+    different_name = %{same_name | "shortcode" => "blank_2"}
+
+    conn = conn |> assign(:user, admin)
+
+    assert conn
+           |> post(emoji_api_path(conn, :update_file, "test_pack"), same_name)
+           |> text_response(:conflict) =~ "already exists"
+
+    assert conn
+           |> post(emoji_api_path(conn, :update_file, "test_pack"), different_name)
+           |> json_response(200) == %{"blank" => "blank.png", "blank_2" => "dir/blank.png"}
+
+    assert File.exists?("#{@emoji_dir_path}/test_pack/dir/blank.png")
+
+    assert conn
+           |> post(emoji_api_path(conn, :update_file, "test_pack"), %{
+             "action" => "update",
+             "shortcode" => "blank_2",
+             "new_shortcode" => "blank_3",
+             "new_filename" => "dir_2/blank_3.png"
+           })
+           |> json_response(200) == %{"blank" => "blank.png", "blank_3" => "dir_2/blank_3.png"}
+
+    refute File.exists?("#{@emoji_dir_path}/test_pack/dir/")
+    assert File.exists?("#{@emoji_dir_path}/test_pack/dir_2/blank_3.png")
+
+    assert conn
+           |> post(emoji_api_path(conn, :update_file, "test_pack"), %{
+             "action" => "remove",
+             "shortcode" => "blank_3"
+           })
+           |> json_response(200) == %{"blank" => "blank.png"}
+
+    refute File.exists?("#{@emoji_dir_path}/test_pack/dir_2/")
+  end
 end