Allow uploading new emojis to packs from URLs
[akkoma] / test / web / emoji_api_controller_test.exs
1 defmodule Pleroma.Web.EmojiAPI.EmojiAPIControllerTest do
2 use Pleroma.Web.ConnCase
3
4 import Tesla.Mock
5
6 import Pleroma.Factory
7
8 @emoji_dir_path Path.join(
9 Pleroma.Config.get!([:instance, :static_dir]),
10 "emoji"
11 )
12
13 test "shared & non-shared pack information in list_packs is ok" do
14 conn = build_conn()
15 resp = conn |> get(emoji_api_path(conn, :list_packs)) |> json_response(200)
16
17 assert Map.has_key?(resp, "test_pack")
18
19 pack = resp["test_pack"]
20
21 assert Map.has_key?(pack["pack"], "download-sha256")
22 assert pack["pack"]["can-download"]
23
24 assert pack["files"] == %{"blank" => "blank.png"}
25
26 # Non-shared pack
27
28 assert Map.has_key?(resp, "test_pack_nonshared")
29
30 pack = resp["test_pack_nonshared"]
31
32 refute pack["pack"]["shared"]
33 refute pack["pack"]["can-download"]
34 end
35
36 test "downloading a shared pack from download_shared" do
37 conn = build_conn()
38
39 resp =
40 conn
41 |> get(emoji_api_path(conn, :download_shared, "test_pack"))
42 |> response(200)
43
44 {:ok, arch} = :zip.unzip(resp, [:memory])
45
46 assert Enum.find(arch, fn {n, _} -> n == 'pack.json' end)
47 assert Enum.find(arch, fn {n, _} -> n == 'blank.png' end)
48 end
49
50 test "downloading shared & unshared packs from another instance via download_from, deleting them" do
51 on_exit(fn ->
52 File.rm_rf!("#{@emoji_dir_path}/test_pack2")
53 File.rm_rf!("#{@emoji_dir_path}/test_pack_nonshared2")
54 end)
55
56 mock(fn
57 %{
58 method: :get,
59 url: "https://example.com/api/pleroma/emoji/packs/list"
60 } ->
61 conn = build_conn()
62
63 conn
64 |> get(emoji_api_path(conn, :list_packs))
65 |> json_response(200)
66 |> json()
67
68 %{
69 method: :get,
70 url: "https://example.com/api/pleroma/emoji/packs/download_shared/test_pack"
71 } ->
72 conn = build_conn()
73
74 conn
75 |> get(emoji_api_path(conn, :download_shared, "test_pack"))
76 |> response(200)
77 |> text()
78
79 %{
80 method: :get,
81 url: "https://nonshared-pack"
82 } ->
83 text(File.read!("#{@emoji_dir_path}/test_pack_nonshared/nonshared.zip"))
84 end)
85
86 admin = insert(:user, info: %{is_admin: true})
87
88 conn = build_conn() |> assign(:user, admin)
89
90 assert conn
91 |> put_req_header("content-type", "application/json")
92 |> post(
93 emoji_api_path(
94 conn,
95 :download_from
96 ),
97 %{
98 instance_address: "https://example.com",
99 pack_name: "test_pack",
100 as: "test_pack2"
101 }
102 |> Jason.encode!()
103 )
104 |> text_response(200) == "ok"
105
106 assert File.exists?("#{@emoji_dir_path}/test_pack2/pack.json")
107 assert File.exists?("#{@emoji_dir_path}/test_pack2/blank.png")
108
109 assert conn
110 |> delete(emoji_api_path(conn, :delete, "test_pack2"))
111 |> response(200) == "ok"
112
113 refute File.exists?("#{@emoji_dir_path}/test_pack2")
114
115 # non-shared, downloaded from the fallback URL
116
117 conn = build_conn() |> assign(:user, admin)
118
119 assert conn
120 |> put_req_header("content-type", "application/json")
121 |> post(
122 emoji_api_path(
123 conn,
124 :download_from
125 ),
126 %{
127 instance_address: "https://example.com",
128 pack_name: "test_pack_nonshared",
129 as: "test_pack_nonshared2"
130 }
131 |> Jason.encode!()
132 )
133 |> text_response(200) == "ok"
134
135 assert File.exists?("#{@emoji_dir_path}/test_pack_nonshared2/pack.json")
136 assert File.exists?("#{@emoji_dir_path}/test_pack_nonshared2/blank.png")
137
138 assert conn
139 |> delete(emoji_api_path(conn, :delete, "test_pack_nonshared2"))
140 |> response(200) == "ok"
141
142 refute File.exists?("#{@emoji_dir_path}/test_pack_nonshared2")
143 end
144
145 describe "updating pack metadata" do
146 setup do
147 pack_file = "#{@emoji_dir_path}/test_pack/pack.json"
148 original_content = File.read!(pack_file)
149
150 on_exit(fn ->
151 File.write!(pack_file, original_content)
152 end)
153
154 {:ok,
155 admin: insert(:user, info: %{is_admin: true}),
156 pack_file: pack_file,
157 new_data: %{
158 "license" => "Test license changed",
159 "homepage" => "https://pleroma.social",
160 "description" => "Test description",
161 "share-files" => false
162 }}
163 end
164
165 test "for a pack without a fallback source", ctx do
166 conn = build_conn()
167
168 assert conn
169 |> assign(:user, ctx[:admin])
170 |> post(
171 emoji_api_path(conn, :update_metadata, "test_pack"),
172 %{
173 "new_data" => ctx[:new_data]
174 }
175 )
176 |> json_response(200) == ctx[:new_data]
177
178 assert Jason.decode!(File.read!(ctx[:pack_file]))["pack"] == ctx[:new_data]
179 end
180
181 test "for a pack with a fallback source", ctx do
182 mock(fn
183 %{
184 method: :get,
185 url: "https://nonshared-pack"
186 } ->
187 text(File.read!("#{@emoji_dir_path}/test_pack_nonshared/nonshared.zip"))
188 end)
189
190 new_data = Map.put(ctx[:new_data], "fallback-src", "https://nonshared-pack")
191
192 new_data_with_sha =
193 Map.put(
194 new_data,
195 "fallback-src-sha256",
196 "74409E2674DAA06C072729C6C8426C4CB3B7E0B85ED77792DB7A436E11D76DAF"
197 )
198
199 conn = build_conn()
200
201 assert conn
202 |> assign(:user, ctx[:admin])
203 |> post(
204 emoji_api_path(conn, :update_metadata, "test_pack"),
205 %{
206 "new_data" => new_data
207 }
208 )
209 |> json_response(200) == new_data_with_sha
210
211 assert Jason.decode!(File.read!(ctx[:pack_file]))["pack"] == new_data_with_sha
212 end
213
214 test "when the fallback source doesn't have all the files", ctx do
215 mock(fn
216 %{
217 method: :get,
218 url: "https://nonshared-pack"
219 } ->
220 {:ok, {'empty.zip', empty_arch}} = :zip.zip('empty.zip', [], [:memory])
221 text(empty_arch)
222 end)
223
224 new_data = Map.put(ctx[:new_data], "fallback-src", "https://nonshared-pack")
225
226 conn = build_conn()
227
228 assert conn
229 |> assign(:user, ctx[:admin])
230 |> post(
231 emoji_api_path(conn, :update_metadata, "test_pack"),
232 %{
233 "new_data" => new_data
234 }
235 )
236 |> text_response(:bad_request) =~ "does not have all"
237 end
238 end
239
240 test "updating pack files" do
241 pack_file = "#{@emoji_dir_path}/test_pack/pack.json"
242 original_content = File.read!(pack_file)
243
244 on_exit(fn ->
245 File.write!(pack_file, original_content)
246
247 File.rm_rf!("#{@emoji_dir_path}/test_pack/blank_url.png")
248 File.rm_rf!("#{@emoji_dir_path}/test_pack/dir")
249 File.rm_rf!("#{@emoji_dir_path}/test_pack/dir_2")
250 end)
251
252 admin = insert(:user, info: %{is_admin: true})
253
254 conn = build_conn()
255
256 same_name = %{
257 "action" => "add",
258 "shortcode" => "blank",
259 "filename" => "dir/blank.png",
260 "file" => %Plug.Upload{
261 filename: "blank.png",
262 path: "#{@emoji_dir_path}/test_pack/blank.png"
263 }
264 }
265
266 different_name = %{same_name | "shortcode" => "blank_2"}
267
268 conn = conn |> assign(:user, admin)
269
270 assert conn
271 |> post(emoji_api_path(conn, :update_file, "test_pack"), same_name)
272 |> text_response(:conflict) =~ "already exists"
273
274 assert conn
275 |> post(emoji_api_path(conn, :update_file, "test_pack"), different_name)
276 |> json_response(200) == %{"blank" => "blank.png", "blank_2" => "dir/blank.png"}
277
278 assert File.exists?("#{@emoji_dir_path}/test_pack/dir/blank.png")
279
280 assert conn
281 |> post(emoji_api_path(conn, :update_file, "test_pack"), %{
282 "action" => "update",
283 "shortcode" => "blank_2",
284 "new_shortcode" => "blank_3",
285 "new_filename" => "dir_2/blank_3.png"
286 })
287 |> json_response(200) == %{"blank" => "blank.png", "blank_3" => "dir_2/blank_3.png"}
288
289 refute File.exists?("#{@emoji_dir_path}/test_pack/dir/")
290 assert File.exists?("#{@emoji_dir_path}/test_pack/dir_2/blank_3.png")
291
292 assert conn
293 |> post(emoji_api_path(conn, :update_file, "test_pack"), %{
294 "action" => "remove",
295 "shortcode" => "blank_3"
296 })
297 |> json_response(200) == %{"blank" => "blank.png"}
298
299 refute File.exists?("#{@emoji_dir_path}/test_pack/dir_2/")
300
301 mock(fn
302 %{
303 method: :get,
304 url: "https://test-blank/blank_url.png"
305 } ->
306 text(File.read!("#{@emoji_dir_path}/test_pack/blank.png"))
307 end)
308
309 # The name should be inferred from the URL ending
310 from_url = %{
311 "action" => "add",
312 "shortcode" => "blank_url",
313 "file" => "https://test-blank/blank_url.png"
314 }
315
316 assert conn
317 |> post(emoji_api_path(conn, :update_file, "test_pack"), from_url)
318 |> json_response(200) == %{
319 "blank" => "blank.png",
320 "blank_url" => "blank_url.png"
321 }
322
323 assert File.exists?("#{@emoji_dir_path}/test_pack/blank_url.png")
324
325 assert conn
326 |> post(emoji_api_path(conn, :update_file, "test_pack"), %{
327 "action" => "remove",
328 "shortcode" => "blank_url"
329 })
330 |> json_response(200) == %{"blank" => "blank.png"}
331
332 refute File.exists?("#{@emoji_dir_path}/test_pack/blank_url.png")
333 end
334 end