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