total rebase
[anni] / lib / pleroma / web / pleroma_api / controllers / emoji_pack_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.EmojiPackController do
6   use Pleroma.Web, :controller
7
8   alias Pleroma.Emoji.Pack
9
10   plug(Pleroma.Web.ApiSpec.CastAndValidate, replace_params: false)
11
12   plug(
13     Pleroma.Web.Plugs.OAuthScopesPlug,
14     %{scopes: ["admin:write"]}
15     when action in [
16            :import_from_filesystem,
17            :remote,
18            :download,
19            :create,
20            :update,
21            :delete
22          ]
23   )
24
25   plug(:skip_auth when action in [:index, :archive, :show])
26
27   defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.PleromaEmojiPackOperation
28
29   def remote(%{private: %{open_api_spex: %{params: params}}} = conn, _) do
30     with {:ok, packs} <-
31            Pack.list_remote(url: params.url, page_size: params.page_size, page: params.page) do
32       json(conn, packs)
33     else
34       {:error, :not_shareable} ->
35         conn
36         |> put_status(:internal_server_error)
37         |> json(%{error: "The requested instance does not support sharing emoji packs"})
38     end
39   end
40
41   def index(%{private: %{open_api_spex: %{params: params}}} = conn, _) do
42     emoji_path =
43       [:instance, :static_dir]
44       |> Pleroma.Config.get!()
45       |> Path.join("emoji")
46
47     with {:ok, packs, count} <- Pack.list_local(page: params.page, page_size: params.page_size) do
48       json(conn, %{packs: packs, count: count})
49     else
50       {:error, :create_dir, e} ->
51         conn
52         |> put_status(:internal_server_error)
53         |> json(%{error: "Failed to create the emoji pack directory at #{emoji_path}: #{e}"})
54
55       {:error, :ls, e} ->
56         conn
57         |> put_status(:internal_server_error)
58         |> json(%{
59           error: "Failed to get the contents of the emoji pack directory at #{emoji_path}: #{e}"
60         })
61     end
62   end
63
64   def show(
65         %{private: %{open_api_spex: %{params: %{name: name, page: page, page_size: page_size}}}} =
66           conn,
67         _
68       ) do
69     name = String.trim(name)
70
71     with {:ok, pack} <- Pack.show(name: name, page: page, page_size: page_size) do
72       json(conn, pack)
73     else
74       {:error, :enoent} ->
75         conn
76         |> put_status(:not_found)
77         |> json(%{error: "Pack #{name} does not exist"})
78
79       {:error, :empty_values} ->
80         conn
81         |> put_status(:bad_request)
82         |> json(%{error: "pack name cannot be empty"})
83
84       {:error, error} ->
85         error_message =
86           add_posix_error(
87             "Failed to get the contents of the `#{name}` pack.",
88             error
89           )
90
91         conn
92         |> put_status(:internal_server_error)
93         |> json(%{error: error_message})
94     end
95   end
96
97   def archive(%{private: %{open_api_spex: %{params: %{name: name}}}} = conn, _) do
98     with {:ok, archive} <- Pack.get_archive(name) do
99       send_download(conn, {:binary, archive}, filename: "#{name}.zip")
100     else
101       {:error, :cant_download} ->
102         conn
103         |> put_status(:forbidden)
104         |> json(%{
105           error:
106             "Pack #{name} cannot be downloaded from this instance, either pack sharing was disabled for this pack or some files are missing"
107         })
108
109       {:error, :enoent} ->
110         conn
111         |> put_status(:not_found)
112         |> json(%{error: "Pack #{name} does not exist"})
113     end
114   end
115
116   def download(
117         %{private: %{open_api_spex: %{body_params: %{url: url, name: name} = params}}} = conn,
118         _
119       ) do
120     with {:ok, _pack} <- Pack.download(name, url, params[:as]) do
121       json(conn, "ok")
122     else
123       {:error, :not_shareable} ->
124         conn
125         |> put_status(:internal_server_error)
126         |> json(%{error: "The requested instance does not support sharing emoji packs"})
127
128       {:error, :invalid_checksum} ->
129         conn
130         |> put_status(:internal_server_error)
131         |> json(%{error: "SHA256 for the pack doesn't match the one sent by the server"})
132
133       {:error, error} ->
134         conn
135         |> put_status(:internal_server_error)
136         |> json(%{error: error})
137     end
138   end
139
140   def create(%{private: %{open_api_spex: %{params: %{name: name}}}} = conn, _) do
141     name = String.trim(name)
142
143     with {:ok, _pack} <- Pack.create(name) do
144       json(conn, "ok")
145     else
146       {:error, :eexist} ->
147         conn
148         |> put_status(:conflict)
149         |> json(%{error: "A pack named \"#{name}\" already exists"})
150
151       {:error, :empty_values} ->
152         conn
153         |> put_status(:bad_request)
154         |> json(%{error: "pack name cannot be empty"})
155
156       {:error, error} ->
157         error_message =
158           add_posix_error(
159             "Unexpected error occurred while creating pack.",
160             error
161           )
162
163         conn
164         |> put_status(:internal_server_error)
165         |> json(%{error: error_message})
166     end
167   end
168
169   def delete(%{private: %{open_api_spex: %{params: %{name: name}}}} = conn, _) do
170     name = String.trim(name)
171
172     with {:ok, deleted} when deleted != [] <- Pack.delete(name) do
173       json(conn, "ok")
174     else
175       {:ok, []} ->
176         conn
177         |> put_status(:not_found)
178         |> json(%{error: "Pack #{name} does not exist"})
179
180       {:error, :empty_values} ->
181         conn
182         |> put_status(:bad_request)
183         |> json(%{error: "pack name cannot be empty"})
184
185       {:error, error, _} ->
186         error_message = add_posix_error("Couldn't delete the `#{name}` pack", error)
187
188         conn
189         |> put_status(:internal_server_error)
190         |> json(%{error: error_message})
191     end
192   end
193
194   def update(
195         %{private: %{open_api_spex: %{body_params: %{metadata: metadata}, params: %{name: name}}}} =
196           conn,
197         _
198       ) do
199     with {:ok, pack} <- Pack.update_metadata(name, metadata) do
200       json(conn, pack.pack)
201     else
202       {:error, :incomplete} ->
203         conn
204         |> put_status(:bad_request)
205         |> json(%{error: "The fallback archive does not have all files specified in pack.json"})
206
207       {:error, error} ->
208         error_message =
209           add_posix_error(
210             "Unexpected error occurred while updating pack metadata.",
211             error
212           )
213
214         conn
215         |> put_status(:internal_server_error)
216         |> json(%{error: error_message})
217     end
218   end
219
220   def import_from_filesystem(conn, _params) do
221     with {:ok, names} <- Pack.import_from_filesystem() do
222       json(conn, names)
223     else
224       {:error, :no_read_write} ->
225         conn
226         |> put_status(:internal_server_error)
227         |> json(%{error: "Error: emoji pack directory must be writable"})
228
229       {:error, _} ->
230         conn
231         |> put_status(:internal_server_error)
232         |> json(%{error: "Error accessing emoji pack directory"})
233     end
234   end
235
236   defp add_posix_error(msg, error) do
237     [msg, Pleroma.Utils.posix_error_message(error)]
238     |> Enum.join(" ")
239     |> String.trim()
240   end
241 end