total rebase
[anni] / lib / pleroma / web / pleroma_api / controllers / emoji_file_controller.ex
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
5 defmodule Pleroma.Web.PleromaAPI.EmojiFileController do
6   use Pleroma.Web, :controller
7
8   alias Pleroma.Emoji.Pack
9   alias Pleroma.Web.ApiSpec
10
11   plug(Pleroma.Web.ApiSpec.CastAndValidate, replace_params: false)
12
13   plug(
14     Pleroma.Web.Plugs.OAuthScopesPlug,
15     %{scopes: ["admin:write"]}
16     when action in [
17            :create,
18            :update,
19            :delete
20          ]
21   )
22
23   defdelegate open_api_operation(action), to: ApiSpec.PleromaEmojiFileOperation
24
25   def create(
26         %{private: %{open_api_spex: %{body_params: params, params: %{name: pack_name}}}} = conn,
27         _
28       ) do
29     filename = params[:filename] || get_filename(params[:file])
30     shortcode = params[:shortcode] || Path.basename(filename, Path.extname(filename))
31
32     with {:ok, pack} <- Pack.load_pack(pack_name),
33          {:ok, file} <- get_file(params[:file]),
34          {:ok, pack} <- Pack.add_file(pack, shortcode, filename, file) do
35       json(conn, pack.files)
36     else
37       {:error, :already_exists} ->
38         conn
39         |> put_status(:conflict)
40         |> json(%{error: "An emoji with the \"#{shortcode}\" shortcode already exists"})
41
42       {:error, :empty_values} ->
43         conn
44         |> put_status(:unprocessable_entity)
45         |> json(%{error: "pack name, shortcode or filename cannot be empty"})
46
47       {:error, _} = error ->
48         handle_error(conn, error, %{
49           pack_name: pack_name,
50           message: "Unexpected error occurred while adding file to pack."
51         })
52     end
53   end
54
55   def update(
56         %{
57           private: %{
58             open_api_spex: %{
59               body_params: %{shortcode: shortcode} = params,
60               params: %{name: pack_name}
61             }
62           }
63         } = conn,
64         _
65       ) do
66     new_shortcode = params[:new_shortcode]
67     new_filename = params[:new_filename]
68     force = params[:force]
69
70     with {:ok, pack} <- Pack.load_pack(pack_name),
71          {:ok, pack} <- Pack.update_file(pack, shortcode, new_shortcode, new_filename, force) do
72       json(conn, pack.files)
73     else
74       {:error, :already_exists} ->
75         conn
76         |> put_status(:conflict)
77         |> json(%{
78           error:
79             "New shortcode \"#{new_shortcode}\" is already used. If you want to override emoji use 'force' option"
80         })
81
82       {:error, :empty_values} ->
83         conn
84         |> put_status(:unprocessable_entity)
85         |> json(%{error: "new_shortcode or new_filename cannot be empty"})
86
87       {:error, _} = error ->
88         handle_error(conn, error, %{
89           pack_name: pack_name,
90           code: shortcode,
91           message: "Unexpected error occurred while updating."
92         })
93     end
94   end
95
96   def delete(
97         %{private: %{open_api_spex: %{params: %{name: pack_name, shortcode: shortcode}}}} = conn,
98         _
99       ) do
100     with {:ok, pack} <- Pack.load_pack(pack_name),
101          {:ok, pack} <- Pack.delete_file(pack, shortcode) do
102       json(conn, pack.files)
103     else
104       {:error, :empty_values} ->
105         conn
106         |> put_status(:unprocessable_entity)
107         |> json(%{error: "pack name or shortcode cannot be empty"})
108
109       {:error, _} = error ->
110         handle_error(conn, error, %{
111           pack_name: pack_name,
112           code: shortcode,
113           message: "Unexpected error occurred while deleting emoji file."
114         })
115     end
116   end
117
118   defp handle_error(conn, {:error, :doesnt_exist}, %{code: emoji_code}) do
119     conn
120     |> put_status(:bad_request)
121     |> json(%{error: "Emoji \"#{emoji_code}\" does not exist"})
122   end
123
124   defp handle_error(conn, {:error, :enoent}, %{pack_name: pack_name}) do
125     conn
126     |> put_status(:not_found)
127     |> json(%{error: "pack \"#{pack_name}\" is not found"})
128   end
129
130   defp handle_error(conn, {:error, error}, opts) do
131     message =
132       [
133         Map.get(opts, :message, "Unexpected error occurred."),
134         Pleroma.Utils.posix_error_message(error)
135       ]
136       |> Enum.join(" ")
137       |> String.trim()
138
139     conn
140     |> put_status(:internal_server_error)
141     |> json(%{error: message})
142   end
143
144   defp get_filename(%Plug.Upload{filename: filename}), do: filename
145   defp get_filename(url) when is_binary(url), do: Path.basename(url)
146
147   def get_file(%Plug.Upload{} = file), do: {:ok, file}
148
149   def get_file(url) when is_binary(url) do
150     with {:ok, %Tesla.Env{body: body, status: code, headers: headers}}
151          when code in 200..299 <- Pleroma.HTTP.get(url) do
152       path = Plug.Upload.random_file!("emoji")
153
154       content_type =
155         case List.keyfind(headers, "content-type", 0) do
156           {"content-type", value} -> value
157           nil -> nil
158         end
159
160       File.write(path, body)
161
162       {:ok,
163        %Plug.Upload{
164          filename: Path.basename(url),
165          path: path,
166          content_type: content_type
167        }}
168     end
169   end
170 end