From 6e4de715b3ae2523fc90c2f5660a47fdda03bd6b Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Thu, 14 May 2020 19:21:51 +0400 Subject: [PATCH] Add OpenAPI spec for PleromaAPI.EmojiAPIController --- lib/pleroma/emoji/pack.ex | 4 +- .../operations/pleroma_emoji_operation.ex | 390 ++++++++++++++++++ .../controllers/emoji_api_controller.ex | 54 +-- lib/pleroma/web/router.ex | 3 +- test/web/api_spec/schema_examples_test.exs | 2 +- .../controllers/emoji_api_controller_test.exs | 184 ++++++--- 6 files changed, 541 insertions(+), 96 deletions(-) create mode 100644 lib/pleroma/web/api_spec/operations/pleroma_emoji_operation.ex diff --git a/lib/pleroma/emoji/pack.ex b/lib/pleroma/emoji/pack.ex index 242344374..c7b423fbd 100644 --- a/lib/pleroma/emoji/pack.ex +++ b/lib/pleroma/emoji/pack.ex @@ -443,10 +443,10 @@ def update_metadata(name, data) do pack = load_pack(name) fb_sha_changed? = - not is_nil(data["fallback-src"]) and data["fallback-src"] != pack.pack["fallback-src"] + not is_nil(data[:"fallback-src"]) and data[:"fallback-src"] != pack.pack[:"fallback-src"] with {_, true} <- {:update?, fb_sha_changed?}, - {:ok, %{body: zip}} <- Tesla.get(data["fallback-src"]), + {:ok, %{body: zip}} <- Tesla.get(data[:"fallback-src"]), {:ok, f_list} <- :zip.unzip(zip, [:memory]), {_, true} <- {:has_all_files?, has_all_files?(pack.files, f_list)} do fallback_sha = :crypto.hash(:sha256, zip) |> Base.encode16() diff --git a/lib/pleroma/web/api_spec/operations/pleroma_emoji_operation.ex b/lib/pleroma/web/api_spec/operations/pleroma_emoji_operation.ex new file mode 100644 index 000000000..fc881e657 --- /dev/null +++ b/lib/pleroma/web/api_spec/operations/pleroma_emoji_operation.ex @@ -0,0 +1,390 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2020 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.ApiSpec.PleromaEmojiOperation do + alias OpenApiSpex.Operation + alias OpenApiSpex.Schema + alias Pleroma.Web.ApiSpec.Schemas.ApiError + + import Pleroma.Web.ApiSpec.Helpers + + def open_api_operation(action) do + operation = String.to_existing_atom("#{action}_operation") + apply(__MODULE__, operation, []) + end + + def remote_operation do + %Operation{ + tags: ["Emoji Packs"], + summary: "Make request to another instance for emoji packs list", + security: [%{"oAuth" => ["write"]}], + parameters: [url_param()], + operationId: "PleromaAPI.EmojiAPIController.remote", + responses: %{ + 200 => emoji_packs_response(), + 500 => Operation.response("Error", "application/json", ApiError) + } + } + end + + def index_operation do + %Operation{ + tags: ["Emoji Packs"], + summary: "Lists local custom emoji packs", + operationId: "PleromaAPI.EmojiAPIController.index", + responses: %{ + 200 => emoji_packs_response() + } + } + end + + def show_operation do + %Operation{ + tags: ["Emoji Packs"], + summary: "Show emoji pack", + operationId: "PleromaAPI.EmojiAPIController.show", + parameters: [name_param()], + responses: %{ + 200 => Operation.response("Emoji Pack", "application/json", emoji_pack()), + 400 => Operation.response("Bad Request", "application/json", ApiError), + 404 => Operation.response("Not Found", "application/json", ApiError) + } + } + end + + def archive_operation do + %Operation{ + tags: ["Emoji Packs"], + summary: "Requests a local pack archive from the instance", + operationId: "PleromaAPI.EmojiAPIController.archive", + parameters: [name_param()], + responses: %{ + 200 => + Operation.response("Archive file", "application/octet-stream", %Schema{ + type: :string, + format: :binary + }), + 403 => Operation.response("Forbidden", "application/json", ApiError), + 404 => Operation.response("Not Found", "application/json", ApiError) + } + } + end + + def download_operation do + %Operation{ + tags: ["Emoji Packs"], + summary: "Download pack from another instance", + operationId: "PleromaAPI.EmojiAPIController.download", + security: [%{"oAuth" => ["write"]}], + requestBody: request_body("Parameters", download_request(), required: true), + responses: %{ + 200 => ok_response(), + 500 => Operation.response("Error", "application/json", ApiError) + } + } + end + + defp download_request do + %Schema{ + type: :object, + required: [:url, :name], + properties: %{ + url: %Schema{ + type: :string, + format: :uri, + description: "URL of the instance to download from" + }, + name: %Schema{type: :string, format: :uri, description: "Pack Name"}, + as: %Schema{type: :string, format: :uri, description: "Save as"} + } + } + end + + def create_operation do + %Operation{ + tags: ["Emoji Packs"], + summary: "Create an empty pack", + operationId: "PleromaAPI.EmojiAPIController.create", + security: [%{"oAuth" => ["write"]}], + parameters: [name_param()], + responses: %{ + 200 => ok_response(), + 400 => Operation.response("Not Found", "application/json", ApiError), + 409 => Operation.response("Conflict", "application/json", ApiError), + 500 => Operation.response("Error", "application/json", ApiError) + } + } + end + + def delete_operation do + %Operation{ + tags: ["Emoji Packs"], + summary: "Delete a custom emoji pack", + operationId: "PleromaAPI.EmojiAPIController.delete", + security: [%{"oAuth" => ["write"]}], + parameters: [name_param()], + responses: %{ + 200 => ok_response(), + 400 => Operation.response("Bad Request", "application/json", ApiError), + 404 => Operation.response("Not Found", "application/json", ApiError) + } + } + end + + def update_operation do + %Operation{ + tags: ["Emoji Packs"], + summary: "Updates (replaces) pack metadata", + operationId: "PleromaAPI.EmojiAPIController.update", + security: [%{"oAuth" => ["write"]}], + requestBody: request_body("Parameters", update_request(), required: true), + parameters: [name_param()], + responses: %{ + 200 => Operation.response("Metadata", "application/json", metadata()), + 400 => Operation.response("Bad Request", "application/json", ApiError) + } + } + end + + def add_file_operation do + %Operation{ + tags: ["Emoji Packs"], + summary: "Add new file to the pack", + operationId: "PleromaAPI.EmojiAPIController.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 uniq 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.EmojiAPIController.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.EmojiAPIController.delete_file", + security: [%{"oAuth" => ["write"]}], + parameters: [ + name_param(), + Operation.parameter(:shortcode, :query, :string, "File shortcode", + example: "cofe", + required: true + ) + ], + responses: %{ + 200 => Operation.response("Files Object", "application/json", files_object()), + 400 => Operation.response("Bad Request", "application/json", ApiError) + } + } + end + + def import_from_filesystem_operation do + %Operation{ + tags: ["Emoji Packs"], + summary: "Imports packs from filesystem", + operationId: "PleromaAPI.EmojiAPIController.import", + security: [%{"oAuth" => ["write"]}], + responses: %{ + 200 => + Operation.response("Array of imported pack names", "application/json", %Schema{ + type: :array, + items: %Schema{type: :string} + }) + } + } + end + + defp name_param do + Operation.parameter(:name, :path, :string, "Pack Name", example: "cofe", required: true) + end + + defp url_param do + Operation.parameter( + :url, + :query, + %Schema{type: :string, format: :uri}, + "URL of the instance", + required: true + ) + end + + defp ok_response do + Operation.response("Ok", "application/json", %Schema{type: :string, example: "ok"}) + end + + defp emoji_packs_response do + Operation.response( + "Object with pack names as keys and pack contents as values", + "application/json", + %Schema{ + type: :object, + additionalProperties: emoji_pack(), + example: %{ + "emojos" => emoji_pack().example + } + } + ) + end + + defp emoji_pack do + %Schema{ + title: "EmojiPack", + type: :object, + properties: %{ + files: files_object(), + pack: %Schema{ + type: :object, + properties: %{ + license: %Schema{type: :string}, + homepage: %Schema{type: :string, format: :uri}, + description: %Schema{type: :string}, + "can-download": %Schema{type: :boolean}, + "share-files": %Schema{type: :boolean}, + "download-sha256": %Schema{type: :string} + } + } + }, + example: %{ + "files" => %{"emacs" => "emacs.png", "guix" => "guix.png"}, + "pack" => %{ + "license" => "Test license", + "homepage" => "https://pleroma.social", + "description" => "Test description", + "can-download" => true, + "share-files" => true, + "download-sha256" => "57482F30674FD3DE821FF48C81C00DA4D4AF1F300209253684ABA7075E5FC238" + } + } + } + end + + defp files_object do + %Schema{ + type: :object, + additionalProperties: %Schema{type: :string}, + description: "Object with emoji names as keys and filenames as values" + } + end + + defp update_request do + %Schema{ + type: :object, + properties: %{ + metadata: %Schema{ + type: :object, + description: "Metadata to replace the old one", + properties: %{ + license: %Schema{type: :string}, + homepage: %Schema{type: :string, format: :uri}, + description: %Schema{type: :string}, + "fallback-src": %Schema{ + type: :string, + format: :uri, + description: "Fallback url to download pack from" + }, + "fallback-src-sha256": %Schema{ + type: :string, + description: "SHA256 encoded for fallback pack archive" + }, + "share-files": %Schema{type: :boolean, description: "Is pack allowed for sharing?"} + } + } + } + } + end + + defp metadata do + %Schema{ + type: :object, + properties: %{ + license: %Schema{type: :string}, + homepage: %Schema{type: :string, format: :uri}, + description: %Schema{type: :string}, + "fallback-src": %Schema{ + type: :string, + format: :uri, + description: "Fallback url to download pack from" + }, + "fallback-src-sha256": %Schema{ + type: :string, + description: "SHA256 encoded for fallback pack archive" + }, + "share-files": %Schema{type: :boolean, description: "Is pack allowed for sharing?"} + } + } + end +end diff --git a/lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex b/lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex index d276b96a4..e20c11860 100644 --- a/lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex +++ b/lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex @@ -3,6 +3,8 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIController do alias Pleroma.Emoji.Pack + plug(Pleroma.Web.ApiSpec.CastAndValidate) + plug( Pleroma.Plugs.OAuthScopesPlug, %{scopes: ["write"], admin: true} @@ -19,13 +21,12 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIController do ] ) - plug( - :skip_plug, - [Pleroma.Plugs.OAuthScopesPlug, Pleroma.Plugs.ExpectPublicOrAuthenticatedCheckPlug] - when action in [:archive, :show, :list] - ) + @skip_plugs [Pleroma.Plugs.OAuthScopesPlug, Pleroma.Plugs.ExpectPublicOrAuthenticatedCheckPlug] + plug(:skip_plug, @skip_plugs when action in [:archive, :show, :list]) - def remote(conn, %{"url" => url}) do + defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.PleromaEmojiOperation + + def remote(conn, %{url: url}) do with {:ok, packs} <- Pack.list_remote(url) do json(conn, packs) else @@ -36,12 +37,11 @@ def remote(conn, %{"url" => url}) do end end - def list(conn, _params) do + def index(conn, _params) do emoji_path = - Path.join( - Pleroma.Config.get!([:instance, :static_dir]), - "emoji" - ) + [:instance, :static_dir] + |> Pleroma.Config.get!() + |> Path.join("emoji") with {:ok, packs} <- Pack.list_local() do json(conn, packs) @@ -60,7 +60,7 @@ def list(conn, _params) do end end - def show(conn, %{"name" => name}) do + def show(conn, %{name: name}) do name = String.trim(name) with {:ok, pack} <- Pack.show(name) do @@ -78,7 +78,7 @@ def show(conn, %{"name" => name}) do end end - def archive(conn, %{"name" => name}) do + def archive(conn, %{name: name}) do with {:ok, archive} <- Pack.get_archive(name) do send_download(conn, {:binary, archive}, filename: "#{name}.zip") else @@ -97,8 +97,8 @@ def archive(conn, %{"name" => name}) do end end - def download(conn, %{"url" => url, "name" => name} = params) do - with :ok <- Pack.download(name, url, params["as"]) do + def download(%{body_params: %{url: url, name: name} = params} = conn, _) do + with :ok <- Pack.download(name, url, params[:as]) do json(conn, "ok") else {:shareable, _} -> @@ -118,7 +118,7 @@ def download(conn, %{"url" => url, "name" => name} = params) do end end - def create(conn, %{"name" => name}) do + def create(conn, %{name: name}) do name = String.trim(name) with :ok <- Pack.create(name) do @@ -143,7 +143,7 @@ def create(conn, %{"name" => name}) do end end - def delete(conn, %{"name" => name}) do + def delete(conn, %{name: name}) do name = String.trim(name) with {:ok, deleted} when deleted != [] <- Pack.delete(name) do @@ -166,7 +166,7 @@ def delete(conn, %{"name" => name}) do end end - def update(conn, %{"name" => name, "metadata" => metadata}) do + def update(%{body_params: %{metadata: metadata}} = conn, %{name: name}) do with {:ok, pack} <- Pack.update_metadata(name, metadata) do json(conn, pack.pack) else @@ -184,11 +184,11 @@ def update(conn, %{"name" => name, "metadata" => metadata}) do end end - def add_file(conn, %{"name" => name} = params) do - filename = params["filename"] || get_filename(params["file"]) - shortcode = params["shortcode"] || Path.basename(filename, Path.extname(filename)) + def add_file(%{body_params: params} = conn, %{name: name}) do + filename = params[:filename] || get_filename(params[:file]) + shortcode = params[:shortcode] || Path.basename(filename, Path.extname(filename)) - with {:ok, pack} <- Pack.add_file(name, shortcode, filename, params["file"]) do + with {:ok, pack} <- Pack.add_file(name, shortcode, filename, params[:file]) do json(conn, pack.files) else {:exists, _} -> @@ -215,10 +215,10 @@ def add_file(conn, %{"name" => name} = params) do end end - def update_file(conn, %{"name" => name, "shortcode" => shortcode} = params) do - new_shortcode = params["new_shortcode"] - new_filename = params["new_filename"] - force = params["force"] == true + def update_file(%{body_params: %{shortcode: shortcode} = params} = conn, %{name: name}) do + new_shortcode = params[:new_shortcode] + new_filename = params[:new_filename] + force = params[:force] with {:ok, pack} <- Pack.update_file(name, shortcode, new_shortcode, new_filename, force) do json(conn, pack.files) @@ -255,7 +255,7 @@ def update_file(conn, %{"name" => name, "shortcode" => shortcode} = params) do end end - def delete_file(conn, %{"name" => name, "shortcode" => shortcode}) do + def delete_file(conn, %{name: name, shortcode: shortcode}) do with {:ok, pack} <- Pack.delete_file(name, shortcode) do json(conn, pack.files) else diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index d77a61361..0d4ebf4ce 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -231,7 +231,8 @@ defmodule Pleroma.Web.Router do # Pack info / downloading scope "/packs" do - get("/", EmojiAPIController, :list) + pipe_through(:api) + get("/", EmojiAPIController, :index) get("/:name", EmojiAPIController, :show) get("/:name/archive", EmojiAPIController, :archive) end diff --git a/test/web/api_spec/schema_examples_test.exs b/test/web/api_spec/schema_examples_test.exs index 88b6f07cb..f00e834fc 100644 --- a/test/web/api_spec/schema_examples_test.exs +++ b/test/web/api_spec/schema_examples_test.exs @@ -28,7 +28,7 @@ test "request body schema example matches schema" do end end - for {status, response} <- operation.responses do + for {status, response} <- operation.responses, is_map(response.content[@content_type]) do describe "#{operation.operationId} - #{status} Response" do @schema resolve_schema(response.content[@content_type].schema) diff --git a/test/web/pleroma_api/controllers/emoji_api_controller_test.exs b/test/web/pleroma_api/controllers/emoji_api_controller_test.exs index d343256fe..c625a5c43 100644 --- a/test/web/pleroma_api/controllers/emoji_api_controller_test.exs +++ b/test/web/pleroma_api/controllers/emoji_api_controller_test.exs @@ -28,7 +28,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIControllerTest do end test "GET /api/pleroma/emoji/packs", %{conn: conn} do - resp = conn |> get("/api/pleroma/emoji/packs") |> json_response(200) + resp = conn |> get("/api/pleroma/emoji/packs") |> json_response_and_validate_schema(200) shared = resp["test_pack"] assert shared["files"] == %{"blank" => "blank.png"} @@ -46,7 +46,7 @@ test "shareable instance", %{admin_conn: admin_conn, conn: conn} do resp = conn |> get("/api/pleroma/emoji/packs") - |> json_response(200) + |> json_response_and_validate_schema(200) mock(fn %{method: :get, url: "https://example.com/.well-known/nodeinfo"} -> @@ -60,10 +60,8 @@ test "shareable instance", %{admin_conn: admin_conn, conn: conn} do end) assert admin_conn - |> get("/api/pleroma/emoji/packs/remote", %{ - url: "https://example.com" - }) - |> json_response(200) == resp + |> get("/api/pleroma/emoji/packs/remote?url=https://example.com") + |> json_response_and_validate_schema(200) == resp end test "non shareable instance", %{admin_conn: admin_conn} do @@ -76,8 +74,8 @@ test "non shareable instance", %{admin_conn: admin_conn} do end) assert admin_conn - |> get("/api/pleroma/emoji/packs/remote", %{url: "https://example.com"}) - |> json_response(500) == %{ + |> get("/api/pleroma/emoji/packs/remote?url=https://example.com") + |> json_response_and_validate_schema(500) == %{ "error" => "The requested instance does not support sharing emoji packs" } end @@ -99,7 +97,7 @@ test "download shared pack", %{conn: conn} do test "non existing pack", %{conn: conn} do assert conn |> get("/api/pleroma/emoji/packs/test_pack_for_import/archive") - |> json_response(:not_found) == %{ + |> json_response_and_validate_schema(:not_found) == %{ "error" => "Pack test_pack_for_import does not exist" } end @@ -107,7 +105,7 @@ test "non existing pack", %{conn: conn} do test "non downloadable pack", %{conn: conn} do assert conn |> get("/api/pleroma/emoji/packs/test_pack_nonshared/archive") - |> json_response(:forbidden) == %{ + |> json_response_and_validate_schema(:forbidden) == %{ "error" => "Pack test_pack_nonshared cannot be downloaded from this instance, either pack sharing was disabled for this pack or some files are missing" } @@ -132,7 +130,7 @@ test "shared pack from remote and non shared from fallback-src", %{ } -> conn |> get("/api/pleroma/emoji/packs/test_pack") - |> json_response(200) + |> json_response_and_validate_schema(200) |> json() %{ @@ -150,7 +148,7 @@ test "shared pack from remote and non shared from fallback-src", %{ } -> conn |> get("/api/pleroma/emoji/packs/test_pack_nonshared") - |> json_response(200) + |> json_response_and_validate_schema(200) |> json() %{ @@ -161,23 +159,25 @@ test "shared pack from remote and non shared from fallback-src", %{ end) assert admin_conn + |> put_req_header("content-type", "multipart/form-data") |> post("/api/pleroma/emoji/packs/download", %{ url: "https://example.com", name: "test_pack", as: "test_pack2" }) - |> json_response(200) == "ok" + |> json_response_and_validate_schema(200) == "ok" assert File.exists?("#{@emoji_path}/test_pack2/pack.json") assert File.exists?("#{@emoji_path}/test_pack2/blank.png") assert admin_conn |> delete("/api/pleroma/emoji/packs/test_pack2") - |> json_response(200) == "ok" + |> json_response_and_validate_schema(200) == "ok" refute File.exists?("#{@emoji_path}/test_pack2") assert admin_conn + |> put_req_header("content-type", "multipart/form-data") |> post( "/api/pleroma/emoji/packs/download", %{ @@ -186,14 +186,14 @@ test "shared pack from remote and non shared from fallback-src", %{ as: "test_pack_nonshared2" } ) - |> json_response(200) == "ok" + |> json_response_and_validate_schema(200) == "ok" assert File.exists?("#{@emoji_path}/test_pack_nonshared2/pack.json") assert File.exists?("#{@emoji_path}/test_pack_nonshared2/blank.png") assert admin_conn |> delete("/api/pleroma/emoji/packs/test_pack_nonshared2") - |> json_response(200) == "ok" + |> json_response_and_validate_schema(200) == "ok" refute File.exists?("#{@emoji_path}/test_pack_nonshared2") end @@ -208,6 +208,7 @@ test "nonshareable instance", %{admin_conn: admin_conn} do end) assert admin_conn + |> put_req_header("content-type", "multipart/form-data") |> post( "/api/pleroma/emoji/packs/download", %{ @@ -216,7 +217,7 @@ test "nonshareable instance", %{admin_conn: admin_conn} do as: "test_pack2" } ) - |> json_response(500) == %{ + |> json_response_and_validate_schema(500) == %{ "error" => "The requested instance does not support sharing emoji packs" } end @@ -249,12 +250,13 @@ test "checksum fail", %{admin_conn: admin_conn} do end) assert admin_conn + |> put_req_header("content-type", "multipart/form-data") |> post("/api/pleroma/emoji/packs/download", %{ url: "https://example.com", name: "pack_bad_sha", as: "pack_bad_sha2" }) - |> json_response(:internal_server_error) == %{ + |> json_response_and_validate_schema(:internal_server_error) == %{ "error" => "SHA256 for the pack doesn't match the one sent by the server" } end @@ -278,12 +280,13 @@ test "other error", %{admin_conn: admin_conn} do end) assert admin_conn + |> put_req_header("content-type", "multipart/form-data") |> post("/api/pleroma/emoji/packs/download", %{ url: "https://example.com", name: "test_pack", as: "test_pack2" }) - |> json_response(:internal_server_error) == %{ + |> json_response_and_validate_schema(:internal_server_error) == %{ "error" => "The pack was not set as shared and there is no fallback src to download from" } @@ -311,8 +314,9 @@ test "other error", %{admin_conn: admin_conn} do test "for a pack without a fallback source", ctx do assert ctx[:admin_conn] + |> put_req_header("content-type", "multipart/form-data") |> patch("/api/pleroma/emoji/packs/test_pack", %{"metadata" => ctx[:new_data]}) - |> json_response(200) == ctx[:new_data] + |> json_response_and_validate_schema(200) == ctx[:new_data] assert Jason.decode!(File.read!(ctx[:pack_file]))["pack"] == ctx[:new_data] end @@ -336,8 +340,9 @@ test "for a pack with a fallback source", ctx do ) assert ctx[:admin_conn] + |> put_req_header("content-type", "multipart/form-data") |> patch("/api/pleroma/emoji/packs/test_pack", %{metadata: new_data}) - |> json_response(200) == new_data_with_sha + |> json_response_and_validate_schema(200) == new_data_with_sha assert Jason.decode!(File.read!(ctx[:pack_file]))["pack"] == new_data_with_sha end @@ -355,8 +360,9 @@ test "when the fallback source doesn't have all the files", ctx do new_data = Map.put(ctx[:new_data], "fallback-src", "https://nonshared-pack") assert ctx[:admin_conn] + |> put_req_header("content-type", "multipart/form-data") |> patch("/api/pleroma/emoji/packs/test_pack", %{metadata: new_data}) - |> json_response(:bad_request) == %{ + |> json_response_and_validate_schema(:bad_request) == %{ "error" => "The fallback archive does not have all files specified in pack.json" } end @@ -376,6 +382,7 @@ test "when the fallback source doesn't have all the files", ctx do 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", @@ -384,7 +391,7 @@ test "create shortcode exists", %{admin_conn: admin_conn} do path: "#{@emoji_path}/test_pack/blank.png" } }) - |> json_response(:conflict) == %{ + |> json_response_and_validate_schema(:conflict) == %{ "error" => "An emoji with the \"blank\" shortcode already exists" } end @@ -393,6 +400,7 @@ 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: "blank2", filename: "dir/blank.png", @@ -401,17 +409,21 @@ test "don't rewrite old emoji", %{admin_conn: admin_conn} do path: "#{@emoji_path}/test_pack/blank.png" } }) - |> json_response(200) == %{"blank" => "blank.png", "blank2" => "dir/blank.png"} + |> json_response_and_validate_schema(200) == %{ + "blank" => "blank.png", + "blank2" => "dir/blank.png" + } assert File.exists?("#{@emoji_path}/test_pack/dir/blank.png") assert 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(:conflict) == %{ + |> json_response_and_validate_schema(:conflict) == %{ "error" => "New shortcode \"blank2\" is already used. If you want to override emoji use 'force' option" } @@ -421,6 +433,7 @@ 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: "blank2", filename: "dir/blank.png", @@ -429,18 +442,22 @@ test "rewrite old emoji with force option", %{admin_conn: admin_conn} do path: "#{@emoji_path}/test_pack/blank.png" } }) - |> json_response(200) == %{"blank" => "blank.png", "blank2" => "dir/blank.png"} + |> json_response_and_validate_schema(200) == %{ + "blank" => "blank.png", + "blank2" => "dir/blank.png" + } assert File.exists?("#{@emoji_path}/test_pack/dir/blank.png") assert admin_conn + |> put_req_header("content-type", "multipart/form-data") |> patch("/api/pleroma/emoji/packs/test_pack/files", %{ shortcode: "blank2", new_shortcode: "blank3", new_filename: "dir_2/blank_3.png", force: true }) - |> json_response(200) == %{ + |> json_response_and_validate_schema(200) == %{ "blank" => "blank.png", "blank3" => "dir_2/blank_3.png" } @@ -450,6 +467,7 @@ test "rewrite old emoji with force option", %{admin_conn: admin_conn} do 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: "", @@ -458,13 +476,14 @@ test "with empty filename", %{admin_conn: admin_conn} do path: "#{@emoji_path}/test_pack/blank.png" } }) - |> json_response(:bad_request) == %{ + |> json_response_and_validate_schema(:bad_request) == %{ "error" => "pack name, shortcode or filename cannot be empty" } 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: "blank2", filename: "dir/blank.png", @@ -473,37 +492,43 @@ test "add file with not loaded pack", %{admin_conn: admin_conn} do path: "#{@emoji_path}/test_pack/blank.png" } }) - |> json_response(:bad_request) == %{ + |> json_response_and_validate_schema(:bad_request) == %{ "error" => "pack \"not_loaded\" is not found" } 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(:bad_request) == %{"error" => "pack \"not_loaded\" is not found"} + |> delete("/api/pleroma/emoji/packs/not_loaded/files?shortcode=blank3") + |> json_response_and_validate_schema(:bad_request) == %{ + "error" => "pack \"not_loaded\" is not found" + } end 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(:bad_request) == %{ + |> delete("/api/pleroma/emoji/packs/not_loaded/files?shortcode=") + |> json_response_and_validate_schema(:bad_request) == %{ "error" => "pack name or shortcode cannot be empty" } 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(:bad_request) == %{"error" => "pack \"not_loaded\" is not found"} + |> 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", @@ -512,24 +537,31 @@ test "new with shortcode as file with update", %{admin_conn: admin_conn} do path: "#{@emoji_path}/test_pack/blank.png" } }) - |> json_response(200) == %{"blank" => "blank.png", "blank4" => "dir/blank.png"} + |> json_response_and_validate_schema(200) == %{ + "blank" => "blank.png", + "blank4" => "dir/blank.png" + } assert File.exists?("#{@emoji_path}/test_pack/dir/blank.png") assert 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(200) == %{"blank3" => "dir_2/blank_3.png", "blank" => "blank.png"} + |> json_response_and_validate_schema(200) == %{ + "blank3" => "dir_2/blank_3.png", + "blank" => "blank.png" + } refute File.exists?("#{@emoji_path}/test_pack/dir/") 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(200) == %{"blank" => "blank.png"} + |> delete("/api/pleroma/emoji/packs/test_pack/files?shortcode=blank3") + |> json_response_and_validate_schema(200) == %{"blank" => "blank.png"} refute File.exists?("#{@emoji_path}/test_pack/dir_2/") @@ -546,11 +578,12 @@ test "new with shortcode from url", %{admin_conn: admin_conn} do 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(200) == %{ + |> json_response_and_validate_schema(200) == %{ "blank_url" => "blank_url.png", "blank" => "blank.png" } @@ -564,40 +597,51 @@ 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(200) == %{"shortcode" => "shortcode.png", "blank" => "blank.png"} + |> json_response_and_validate_schema(200) == %{ + "shortcode" => "shortcode.png", + "blank" => "blank.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: "blank2"}) - |> json_response(:bad_request) == %{"error" => "Emoji \"blank2\" does not exist"} + |> delete("/api/pleroma/emoji/packs/test_pack/files?shortcode=blank2") + |> json_response_and_validate_schema(:bad_request) == %{ + "error" => "Emoji \"blank2\" does not exist" + } end 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: "blank2", new_shortcode: "blank3", new_filename: "dir_2/blank_3.png" }) - |> json_response(:bad_request) == %{"error" => "Emoji \"blank2\" does not exist"} + |> json_response_and_validate_schema(:bad_request) == %{ + "error" => "Emoji \"blank2\" does not exist" + } end test "update with empty shortcode", %{admin_conn: admin_conn} do - assert admin_conn - |> patch("/api/pleroma/emoji/packs/test_pack/files", %{ - shortcode: "blank", - new_filename: "dir_2/blank_3.png" - }) - |> json_response(:bad_request) == %{ - "error" => "new_shortcode or new_filename cannot be empty" - } + assert %{ + "error" => "Missing field: new_shortcode." + } = + admin_conn + |> put_req_header("content-type", "multipart/form-data") + |> patch("/api/pleroma/emoji/packs/test_pack/files", %{ + shortcode: "blank", + new_filename: "dir_2/blank_3.png" + }) + |> json_response_and_validate_schema(:bad_request) end end @@ -605,7 +649,7 @@ test "update with empty shortcode", %{admin_conn: admin_conn} do test "creating and deleting a pack", %{admin_conn: admin_conn} do assert admin_conn |> post("/api/pleroma/emoji/packs/test_created") - |> json_response(200) == "ok" + |> json_response_and_validate_schema(200) == "ok" assert File.exists?("#{@emoji_path}/test_created/pack.json") @@ -616,7 +660,7 @@ test "creating and deleting a pack", %{admin_conn: admin_conn} do assert admin_conn |> delete("/api/pleroma/emoji/packs/test_created") - |> json_response(200) == "ok" + |> json_response_and_validate_schema(200) == "ok" refute File.exists?("#{@emoji_path}/test_created/pack.json") end @@ -629,7 +673,7 @@ test "if pack exists", %{admin_conn: admin_conn} do assert admin_conn |> post("/api/pleroma/emoji/packs/test_created") - |> json_response(:conflict) == %{ + |> json_response_and_validate_schema(:conflict) == %{ "error" => "A pack named \"test_created\" already exists" } @@ -639,20 +683,26 @@ test "if pack exists", %{admin_conn: admin_conn} do test "with empty name", %{admin_conn: admin_conn} do assert admin_conn |> post("/api/pleroma/emoji/packs/ ") - |> json_response(:bad_request) == %{"error" => "pack name cannot be empty"} + |> json_response_and_validate_schema(:bad_request) == %{ + "error" => "pack name cannot be empty" + } end end test "deleting nonexisting pack", %{admin_conn: admin_conn} do assert admin_conn |> delete("/api/pleroma/emoji/packs/non_existing") - |> json_response(:not_found) == %{"error" => "Pack non_existing does not exist"} + |> json_response_and_validate_schema(:not_found) == %{ + "error" => "Pack non_existing does not exist" + } end test "deleting with empty name", %{admin_conn: admin_conn} do assert admin_conn |> delete("/api/pleroma/emoji/packs/ ") - |> json_response(:bad_request) == %{"error" => "pack name cannot be empty"} + |> json_response_and_validate_schema(:bad_request) == %{ + "error" => "pack name cannot be empty" + } end test "filesystem import", %{admin_conn: admin_conn, conn: conn} do @@ -661,15 +711,15 @@ test "filesystem import", %{admin_conn: admin_conn, conn: conn} do File.rm!("#{@emoji_path}/test_pack_for_import/pack.json") end) - resp = conn |> get("/api/pleroma/emoji/packs") |> json_response(200) + resp = conn |> get("/api/pleroma/emoji/packs") |> json_response_and_validate_schema(200) refute Map.has_key?(resp, "test_pack_for_import") assert admin_conn |> get("/api/pleroma/emoji/packs/import") - |> json_response(200) == ["test_pack_for_import"] + |> json_response_and_validate_schema(200) == ["test_pack_for_import"] - resp = conn |> get("/api/pleroma/emoji/packs") |> json_response(200) + resp = conn |> get("/api/pleroma/emoji/packs") |> json_response_and_validate_schema(200) assert resp["test_pack_for_import"]["files"] == %{"blank" => "blank.png"} File.rm!("#{@emoji_path}/test_pack_for_import/pack.json") @@ -686,9 +736,9 @@ test "filesystem import", %{admin_conn: admin_conn, conn: conn} do assert admin_conn |> get("/api/pleroma/emoji/packs/import") - |> json_response(200) == ["test_pack_for_import"] + |> json_response_and_validate_schema(200) == ["test_pack_for_import"] - resp = conn |> get("/api/pleroma/emoji/packs") |> json_response(200) + resp = conn |> get("/api/pleroma/emoji/packs") |> json_response_and_validate_schema(200) assert resp["test_pack_for_import"]["files"] == %{ "blank" => "blank.png", @@ -712,19 +762,23 @@ test "shows pack.json", %{conn: conn} do } = conn |> get("/api/pleroma/emoji/packs/test_pack") - |> json_response(200) + |> json_response_and_validate_schema(200) end test "non existing pack", %{conn: conn} do assert conn |> get("/api/pleroma/emoji/packs/non_existing") - |> json_response(:not_found) == %{"error" => "Pack non_existing does not exist"} + |> json_response_and_validate_schema(:not_found) == %{ + "error" => "Pack non_existing does not exist" + } end test "error name", %{conn: conn} do assert conn |> get("/api/pleroma/emoji/packs/ ") - |> json_response(:bad_request) == %{"error" => "pack name cannot be empty"} + |> json_response_and_validate_schema(:bad_request) == %{ + "error" => "pack name cannot be empty" + } end end end