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