Merge branch 'update/docs-jp' into 'develop'
[akkoma] / test / web / pleroma_api / emoji_api_controller_test.exs
1 defmodule Pleroma.Web.PleromaAPI.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 "listing remote packs" do
37 admin = insert(:user, info: %{is_admin: true})
38 conn = build_conn() |> assign(:user, admin)
39
40 resp = conn |> get(emoji_api_path(conn, :list_packs)) |> json_response(200)
41
42 mock(fn
43 %{method: :get, url: "https://example.com/.well-known/nodeinfo"} ->
44 json(%{links: [%{href: "https://example.com/nodeinfo/2.1.json"}]})
45
46 %{method: :get, url: "https://example.com/nodeinfo/2.1.json"} ->
47 json(%{metadata: %{features: ["shareable_emoji_packs"]}})
48
49 %{method: :get, url: "https://example.com/api/pleroma/emoji/packs"} ->
50 json(resp)
51 end)
52
53 assert conn
54 |> post(emoji_api_path(conn, :list_from), %{instance_address: "https://example.com"})
55 |> json_response(200) == resp
56 end
57
58 test "downloading a shared pack from download_shared" do
59 conn = build_conn()
60
61 resp =
62 conn
63 |> get(emoji_api_path(conn, :download_shared, "test_pack"))
64 |> response(200)
65
66 {:ok, arch} = :zip.unzip(resp, [:memory])
67
68 assert Enum.find(arch, fn {n, _} -> n == 'pack.json' end)
69 assert Enum.find(arch, fn {n, _} -> n == 'blank.png' end)
70 end
71
72 test "downloading shared & unshared packs from another instance via download_from, deleting them" do
73 on_exit(fn ->
74 File.rm_rf!("#{@emoji_dir_path}/test_pack2")
75 File.rm_rf!("#{@emoji_dir_path}/test_pack_nonshared2")
76 end)
77
78 mock(fn
79 %{method: :get, url: "https://old-instance/.well-known/nodeinfo"} ->
80 json(%{links: [%{href: "https://old-instance/nodeinfo/2.1.json"}]})
81
82 %{method: :get, url: "https://old-instance/nodeinfo/2.1.json"} ->
83 json(%{metadata: %{features: []}})
84
85 %{method: :get, url: "https://example.com/.well-known/nodeinfo"} ->
86 json(%{links: [%{href: "https://example.com/nodeinfo/2.1.json"}]})
87
88 %{method: :get, url: "https://example.com/nodeinfo/2.1.json"} ->
89 json(%{metadata: %{features: ["shareable_emoji_packs"]}})
90
91 %{
92 method: :get,
93 url: "https://example.com/api/pleroma/emoji/packs/list"
94 } ->
95 conn = build_conn()
96
97 conn
98 |> get(emoji_api_path(conn, :list_packs))
99 |> json_response(200)
100 |> json()
101
102 %{
103 method: :get,
104 url: "https://example.com/api/pleroma/emoji/packs/download_shared/test_pack"
105 } ->
106 conn = build_conn()
107
108 conn
109 |> get(emoji_api_path(conn, :download_shared, "test_pack"))
110 |> response(200)
111 |> text()
112
113 %{
114 method: :get,
115 url: "https://nonshared-pack"
116 } ->
117 text(File.read!("#{@emoji_dir_path}/test_pack_nonshared/nonshared.zip"))
118 end)
119
120 admin = insert(:user, info: %{is_admin: true})
121
122 conn = build_conn() |> assign(:user, admin)
123
124 assert (conn
125 |> put_req_header("content-type", "application/json")
126 |> post(
127 emoji_api_path(
128 conn,
129 :download_from
130 ),
131 %{
132 instance_address: "https://old-instance",
133 pack_name: "test_pack",
134 as: "test_pack2"
135 }
136 |> Jason.encode!()
137 )
138 |> json_response(500))["error"] =~ "does not support"
139
140 assert conn
141 |> put_req_header("content-type", "application/json")
142 |> post(
143 emoji_api_path(
144 conn,
145 :download_from
146 ),
147 %{
148 instance_address: "https://example.com",
149 pack_name: "test_pack",
150 as: "test_pack2"
151 }
152 |> Jason.encode!()
153 )
154 |> json_response(200) == "ok"
155
156 assert File.exists?("#{@emoji_dir_path}/test_pack2/pack.json")
157 assert File.exists?("#{@emoji_dir_path}/test_pack2/blank.png")
158
159 assert conn
160 |> delete(emoji_api_path(conn, :delete, "test_pack2"))
161 |> json_response(200) == "ok"
162
163 refute File.exists?("#{@emoji_dir_path}/test_pack2")
164
165 # non-shared, downloaded from the fallback URL
166
167 conn = build_conn() |> assign(:user, admin)
168
169 assert conn
170 |> put_req_header("content-type", "application/json")
171 |> post(
172 emoji_api_path(
173 conn,
174 :download_from
175 ),
176 %{
177 instance_address: "https://example.com",
178 pack_name: "test_pack_nonshared",
179 as: "test_pack_nonshared2"
180 }
181 |> Jason.encode!()
182 )
183 |> json_response(200) == "ok"
184
185 assert File.exists?("#{@emoji_dir_path}/test_pack_nonshared2/pack.json")
186 assert File.exists?("#{@emoji_dir_path}/test_pack_nonshared2/blank.png")
187
188 assert conn
189 |> delete(emoji_api_path(conn, :delete, "test_pack_nonshared2"))
190 |> json_response(200) == "ok"
191
192 refute File.exists?("#{@emoji_dir_path}/test_pack_nonshared2")
193 end
194
195 describe "updating pack metadata" do
196 setup do
197 pack_file = "#{@emoji_dir_path}/test_pack/pack.json"
198 original_content = File.read!(pack_file)
199
200 on_exit(fn ->
201 File.write!(pack_file, original_content)
202 end)
203
204 {:ok,
205 admin: insert(:user, info: %{is_admin: true}),
206 pack_file: pack_file,
207 new_data: %{
208 "license" => "Test license changed",
209 "homepage" => "https://pleroma.social",
210 "description" => "Test description",
211 "share-files" => false
212 }}
213 end
214
215 test "for a pack without a fallback source", ctx do
216 conn = build_conn()
217
218 assert conn
219 |> assign(:user, ctx[:admin])
220 |> post(
221 emoji_api_path(conn, :update_metadata, "test_pack"),
222 %{
223 "new_data" => ctx[:new_data]
224 }
225 )
226 |> json_response(200) == ctx[:new_data]
227
228 assert Jason.decode!(File.read!(ctx[:pack_file]))["pack"] == ctx[:new_data]
229 end
230
231 test "for a pack with a fallback source", ctx do
232 mock(fn
233 %{
234 method: :get,
235 url: "https://nonshared-pack"
236 } ->
237 text(File.read!("#{@emoji_dir_path}/test_pack_nonshared/nonshared.zip"))
238 end)
239
240 new_data = Map.put(ctx[:new_data], "fallback-src", "https://nonshared-pack")
241
242 new_data_with_sha =
243 Map.put(
244 new_data,
245 "fallback-src-sha256",
246 "74409E2674DAA06C072729C6C8426C4CB3B7E0B85ED77792DB7A436E11D76DAF"
247 )
248
249 conn = build_conn()
250
251 assert conn
252 |> assign(:user, ctx[:admin])
253 |> post(
254 emoji_api_path(conn, :update_metadata, "test_pack"),
255 %{
256 "new_data" => new_data
257 }
258 )
259 |> json_response(200) == new_data_with_sha
260
261 assert Jason.decode!(File.read!(ctx[:pack_file]))["pack"] == new_data_with_sha
262 end
263
264 test "when the fallback source doesn't have all the files", ctx do
265 mock(fn
266 %{
267 method: :get,
268 url: "https://nonshared-pack"
269 } ->
270 {:ok, {'empty.zip', empty_arch}} = :zip.zip('empty.zip', [], [:memory])
271 text(empty_arch)
272 end)
273
274 new_data = Map.put(ctx[:new_data], "fallback-src", "https://nonshared-pack")
275
276 conn = build_conn()
277
278 assert (conn
279 |> assign(:user, ctx[:admin])
280 |> post(
281 emoji_api_path(conn, :update_metadata, "test_pack"),
282 %{
283 "new_data" => new_data
284 }
285 )
286 |> json_response(:bad_request))["error"] =~ "does not have all"
287 end
288 end
289
290 test "updating pack files" do
291 pack_file = "#{@emoji_dir_path}/test_pack/pack.json"
292 original_content = File.read!(pack_file)
293
294 on_exit(fn ->
295 File.write!(pack_file, original_content)
296
297 File.rm_rf!("#{@emoji_dir_path}/test_pack/blank_url.png")
298 File.rm_rf!("#{@emoji_dir_path}/test_pack/dir")
299 File.rm_rf!("#{@emoji_dir_path}/test_pack/dir_2")
300 end)
301
302 admin = insert(:user, info: %{is_admin: true})
303
304 conn = build_conn()
305
306 same_name = %{
307 "action" => "add",
308 "shortcode" => "blank",
309 "filename" => "dir/blank.png",
310 "file" => %Plug.Upload{
311 filename: "blank.png",
312 path: "#{@emoji_dir_path}/test_pack/blank.png"
313 }
314 }
315
316 different_name = %{same_name | "shortcode" => "blank_2"}
317
318 conn = conn |> assign(:user, admin)
319
320 assert (conn
321 |> post(emoji_api_path(conn, :update_file, "test_pack"), same_name)
322 |> json_response(:conflict))["error"] =~ "already exists"
323
324 assert conn
325 |> post(emoji_api_path(conn, :update_file, "test_pack"), different_name)
326 |> json_response(200) == %{"blank" => "blank.png", "blank_2" => "dir/blank.png"}
327
328 assert File.exists?("#{@emoji_dir_path}/test_pack/dir/blank.png")
329
330 assert conn
331 |> post(emoji_api_path(conn, :update_file, "test_pack"), %{
332 "action" => "update",
333 "shortcode" => "blank_2",
334 "new_shortcode" => "blank_3",
335 "new_filename" => "dir_2/blank_3.png"
336 })
337 |> json_response(200) == %{"blank" => "blank.png", "blank_3" => "dir_2/blank_3.png"}
338
339 refute File.exists?("#{@emoji_dir_path}/test_pack/dir/")
340 assert File.exists?("#{@emoji_dir_path}/test_pack/dir_2/blank_3.png")
341
342 assert conn
343 |> post(emoji_api_path(conn, :update_file, "test_pack"), %{
344 "action" => "remove",
345 "shortcode" => "blank_3"
346 })
347 |> json_response(200) == %{"blank" => "blank.png"}
348
349 refute File.exists?("#{@emoji_dir_path}/test_pack/dir_2/")
350
351 mock(fn
352 %{
353 method: :get,
354 url: "https://test-blank/blank_url.png"
355 } ->
356 text(File.read!("#{@emoji_dir_path}/test_pack/blank.png"))
357 end)
358
359 # The name should be inferred from the URL ending
360 from_url = %{
361 "action" => "add",
362 "shortcode" => "blank_url",
363 "file" => "https://test-blank/blank_url.png"
364 }
365
366 assert conn
367 |> post(emoji_api_path(conn, :update_file, "test_pack"), from_url)
368 |> json_response(200) == %{
369 "blank" => "blank.png",
370 "blank_url" => "blank_url.png"
371 }
372
373 assert File.exists?("#{@emoji_dir_path}/test_pack/blank_url.png")
374
375 assert conn
376 |> post(emoji_api_path(conn, :update_file, "test_pack"), %{
377 "action" => "remove",
378 "shortcode" => "blank_url"
379 })
380 |> json_response(200) == %{"blank" => "blank.png"}
381
382 refute File.exists?("#{@emoji_dir_path}/test_pack/blank_url.png")
383 end
384
385 test "creating and deleting a pack" do
386 on_exit(fn ->
387 File.rm_rf!("#{@emoji_dir_path}/test_created")
388 end)
389
390 admin = insert(:user, info: %{is_admin: true})
391
392 conn = build_conn() |> assign(:user, admin)
393
394 assert conn
395 |> put_req_header("content-type", "application/json")
396 |> put(
397 emoji_api_path(
398 conn,
399 :create,
400 "test_created"
401 )
402 )
403 |> json_response(200) == "ok"
404
405 assert File.exists?("#{@emoji_dir_path}/test_created/pack.json")
406
407 assert Jason.decode!(File.read!("#{@emoji_dir_path}/test_created/pack.json")) == %{
408 "pack" => %{},
409 "files" => %{}
410 }
411
412 assert conn
413 |> delete(emoji_api_path(conn, :delete, "test_created"))
414 |> json_response(200) == "ok"
415
416 refute File.exists?("#{@emoji_dir_path}/test_created/pack.json")
417 end
418
419 test "filesystem import" do
420 on_exit(fn ->
421 File.rm!("#{@emoji_dir_path}/test_pack_for_import/emoji.txt")
422 File.rm!("#{@emoji_dir_path}/test_pack_for_import/pack.json")
423 end)
424
425 conn = build_conn()
426 resp = conn |> get(emoji_api_path(conn, :list_packs)) |> json_response(200)
427
428 refute Map.has_key?(resp, "test_pack_for_import")
429
430 admin = insert(:user, info: %{is_admin: true})
431
432 assert conn
433 |> assign(:user, admin)
434 |> post(emoji_api_path(conn, :import_from_fs))
435 |> json_response(200) == ["test_pack_for_import"]
436
437 resp = conn |> get(emoji_api_path(conn, :list_packs)) |> json_response(200)
438 assert resp["test_pack_for_import"]["files"] == %{"blank" => "blank.png"}
439
440 File.rm!("#{@emoji_dir_path}/test_pack_for_import/pack.json")
441 refute File.exists?("#{@emoji_dir_path}/test_pack_for_import/pack.json")
442
443 emoji_txt_content = "blank, blank.png, Fun\n\nblank2, blank.png"
444
445 File.write!("#{@emoji_dir_path}/test_pack_for_import/emoji.txt", emoji_txt_content)
446
447 assert conn
448 |> assign(:user, admin)
449 |> post(emoji_api_path(conn, :import_from_fs))
450 |> json_response(200) == ["test_pack_for_import"]
451
452 resp = conn |> get(emoji_api_path(conn, :list_packs)) |> json_response(200)
453
454 assert resp["test_pack_for_import"]["files"] == %{
455 "blank" => "blank.png",
456 "blank2" => "blank.png"
457 }
458 end
459 end