diff options
Diffstat (limited to 'lib/pleroma/web')
-rw-r--r-- | lib/pleroma/web/api_spec/operations/pleroma_emoji_pack_operation.ex | 390 | ||||
-rw-r--r-- | lib/pleroma/web/pleroma_api/controllers/emoji_pack_controller.ex (renamed from lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex) | 90 | ||||
-rw-r--r-- | lib/pleroma/web/router.ex | 25 |
3 files changed, 448 insertions, 57 deletions
diff --git a/lib/pleroma/web/api_spec/operations/pleroma_emoji_pack_operation.ex b/lib/pleroma/web/api_spec/operations/pleroma_emoji_pack_operation.ex new file mode 100644 index 000000000..567688ff5 --- /dev/null +++ b/lib/pleroma/web/api_spec/operations/pleroma_emoji_pack_operation.ex @@ -0,0 +1,390 @@ +# 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.PleromaEmojiPackOperation 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.EmojiPackController.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.EmojiPackController.index", + responses: %{ + 200 => emoji_packs_response() + } + } + end + + def show_operation do + %Operation{ + tags: ["Emoji Packs"], + summary: "Show emoji pack", + operationId: "PleromaAPI.EmojiPackController.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.EmojiPackController.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.EmojiPackController.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.EmojiPackController.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.EmojiPackController.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.EmojiPackController.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.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"], + summary: "Imports packs from filesystem", + operationId: "PleromaAPI.EmojiPackController.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_pack_controller.ex index d276b96a4..2c53dcde1 100644 --- a/lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex +++ b/lib/pleroma/web/pleroma_api/controllers/emoji_pack_controller.ex @@ -1,8 +1,10 @@ -defmodule Pleroma.Web.PleromaAPI.EmojiAPIController do +defmodule Pleroma.Web.PleromaAPI.EmojiPackController do use Pleroma.Web, :controller alias Pleroma.Emoji.Pack + plug(Pleroma.Web.ApiSpec.CastAndValidate) + plug( Pleroma.Plugs.OAuthScopesPlug, %{scopes: ["write"], admin: true} @@ -19,39 +21,37 @@ 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]) + + defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.PleromaEmojiPackOperation - def remote(conn, %{"url" => url}) do + def remote(conn, %{url: url}) do with {:ok, packs} <- Pack.list_remote(url) do json(conn, packs) else - {:shareable, _} -> + {:error, :not_shareable} -> conn |> put_status(:internal_server_error) |> json(%{error: "The requested instance does not support sharing emoji packs"}) 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) else - {:create_dir, {:error, e}} -> + {:error, :create_dir, e} -> conn |> put_status(:internal_server_error) |> json(%{error: "Failed to create the emoji pack directory at #{emoji_path}: #{e}"}) - {:ls, {:error, e}} -> + {:error, :ls, e} -> conn |> put_status(:internal_server_error) |> json(%{ @@ -60,13 +60,13 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIController 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 json(conn, pack) else - {:loaded, _} -> + {:error, :not_found} -> conn |> put_status(:not_found) |> json(%{error: "Pack #{name} does not exist"}) @@ -78,11 +78,11 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIController 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 - {:can_download?, _} -> + {:error, :cant_download} -> conn |> put_status(:forbidden) |> json(%{ @@ -90,23 +90,23 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIController do "Pack #{name} cannot be downloaded from this instance, either pack sharing was disabled for this pack or some files are missing" }) - {:exists?, _} -> + {:error, :not_found} -> conn |> put_status(:not_found) |> json(%{error: "Pack #{name} does not exist"}) 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} <- Pack.download(name, url, params[:as]) do json(conn, "ok") else - {:shareable, _} -> + {:error, :not_shareable} -> conn |> put_status(:internal_server_error) |> json(%{error: "The requested instance does not support sharing emoji packs"}) - {:checksum, _} -> + {:error, :imvalid_checksum} -> conn |> put_status(:internal_server_error) |> json(%{error: "SHA256 for the pack doesn't match the one sent by the server"}) @@ -118,10 +118,10 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIController 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 + with {:ok, _pack} <- Pack.create(name) do json(conn, "ok") else {:error, :eexist} -> @@ -143,7 +143,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIController 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,11 +166,11 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIController 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 - {:has_all_files?, _} -> + {:error, :incomplete} -> conn |> put_status(:bad_request) |> json(%{error: "The fallback archive does not have all files specified in pack.json"}) @@ -184,19 +184,19 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIController 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, _} -> + {:error, :already_exists} -> conn |> put_status(:conflict) |> json(%{error: "An emoji with the \"#{shortcode}\" shortcode already exists"}) - {:loaded, _} -> + {:error, :not_found} -> conn |> put_status(:bad_request) |> json(%{error: "pack \"#{name}\" is not found"}) @@ -215,20 +215,20 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIController 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) else - {:exists, _} -> + {:error, :doesnt_exist} -> conn |> put_status(:bad_request) |> json(%{error: "Emoji \"#{shortcode}\" does not exist"}) - {:not_used, _} -> + {:error, :already_exists} -> conn |> put_status(:conflict) |> json(%{ @@ -236,7 +236,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIController do "New shortcode \"#{new_shortcode}\" is already used. If you want to override emoji use 'force' option" }) - {:loaded, _} -> + {:error, :not_found} -> conn |> put_status(:bad_request) |> json(%{error: "pack \"#{name}\" is not found"}) @@ -255,16 +255,16 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIController 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 - {:exists, _} -> + {:error, :doesnt_exist} -> conn |> put_status(:bad_request) |> json(%{error: "Emoji \"#{shortcode}\" does not exist"}) - {:loaded, _} -> + {:error, :not_found} -> conn |> put_status(:bad_request) |> json(%{error: "pack \"#{name}\" is not found"}) diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 369c54cf4..4cacf6255 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -216,24 +216,25 @@ defmodule Pleroma.Web.Router do scope "/packs" do pipe_through(:admin_api) - get("/import", EmojiAPIController, :import_from_filesystem) - get("/remote", EmojiAPIController, :remote) - post("/download", EmojiAPIController, :download) + get("/import", EmojiPackController, :import_from_filesystem) + get("/remote", EmojiPackController, :remote) + post("/download", EmojiPackController, :download) - post("/:name", EmojiAPIController, :create) - patch("/:name", EmojiAPIController, :update) - delete("/:name", EmojiAPIController, :delete) + post("/:name", EmojiPackController, :create) + patch("/:name", EmojiPackController, :update) + delete("/:name", EmojiPackController, :delete) - post("/:name/files", EmojiAPIController, :add_file) - patch("/:name/files", EmojiAPIController, :update_file) - delete("/:name/files", EmojiAPIController, :delete_file) + post("/:name/files", EmojiPackController, :add_file) + patch("/:name/files", EmojiPackController, :update_file) + delete("/:name/files", EmojiPackController, :delete_file) end # Pack info / downloading scope "/packs" do - get("/", EmojiAPIController, :list) - get("/:name", EmojiAPIController, :show) - get("/:name/archive", EmojiAPIController, :archive) + pipe_through(:api) + get("/", EmojiPackController, :index) + get("/:name", EmojiPackController, :show) + get("/:name/archive", EmojiPackController, :archive) end end |