9c6cdbd7adff331302c2d5b56f78b8a89d9c30ec
[akkoma] / test / web / mastodon_api / mastodon_api_controller_test.exs
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
5 defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
6 use Pleroma.Web.ConnCase
7
8 alias Ecto.Changeset
9 alias Pleroma.Activity
10 alias Pleroma.Config
11 alias Pleroma.Notification
12 alias Pleroma.Object
13 alias Pleroma.Repo
14 alias Pleroma.ScheduledActivity
15 alias Pleroma.Tests.ObanHelpers
16 alias Pleroma.User
17 alias Pleroma.Web.ActivityPub.ActivityPub
18 alias Pleroma.Web.CommonAPI
19 alias Pleroma.Web.OAuth.App
20 alias Pleroma.Web.OAuth.Token
21 alias Pleroma.Web.Push
22
23 import ExUnit.CaptureLog
24 import Pleroma.Factory
25 import Swoosh.TestAssertions
26 import Tesla.Mock
27
28 @image "data:image/gif;base64,R0lGODlhEAAQAMQAAORHHOVSKudfOulrSOp3WOyDZu6QdvCchPGolfO0o/XBs/fNwfjZ0frl3/zy7////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkAABAALAAAAAAQABAAAAVVICSOZGlCQAosJ6mu7fiyZeKqNKToQGDsM8hBADgUXoGAiqhSvp5QAnQKGIgUhwFUYLCVDFCrKUE1lBavAViFIDlTImbKC5Gm2hB0SlBCBMQiB0UjIQA7"
29
30 setup do
31 mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
32 :ok
33 end
34
35 clear_config([:instance, :public])
36 clear_config([:rich_media, :enabled])
37
38 test "Conversations", %{conn: conn} do
39 user_one = insert(:user)
40 user_two = insert(:user)
41 user_three = insert(:user)
42
43 {:ok, user_two} = User.follow(user_two, user_one)
44
45 {:ok, direct} =
46 CommonAPI.post(user_one, %{
47 "status" => "Hi @#{user_two.nickname}, @#{user_three.nickname}!",
48 "visibility" => "direct"
49 })
50
51 {:ok, _follower_only} =
52 CommonAPI.post(user_one, %{
53 "status" => "Hi @#{user_two.nickname}!",
54 "visibility" => "private"
55 })
56
57 res_conn =
58 conn
59 |> assign(:user, user_one)
60 |> get("/api/v1/conversations")
61
62 assert response = json_response(res_conn, 200)
63
64 assert [
65 %{
66 "id" => res_id,
67 "accounts" => res_accounts,
68 "last_status" => res_last_status,
69 "unread" => unread
70 }
71 ] = response
72
73 account_ids = Enum.map(res_accounts, & &1["id"])
74 assert length(res_accounts) == 2
75 assert user_two.id in account_ids
76 assert user_three.id in account_ids
77 assert is_binary(res_id)
78 assert unread == true
79 assert res_last_status["id"] == direct.id
80
81 # Apparently undocumented API endpoint
82 res_conn =
83 conn
84 |> assign(:user, user_one)
85 |> post("/api/v1/conversations/#{res_id}/read")
86
87 assert response = json_response(res_conn, 200)
88 assert length(response["accounts"]) == 2
89 assert response["last_status"]["id"] == direct.id
90 assert response["unread"] == false
91
92 # (vanilla) Mastodon frontend behaviour
93 res_conn =
94 conn
95 |> assign(:user, user_one)
96 |> get("/api/v1/statuses/#{res_last_status["id"]}/context")
97
98 assert %{"ancestors" => [], "descendants" => []} == json_response(res_conn, 200)
99 end
100
101 test "verify_credentials", %{conn: conn} do
102 user = insert(:user)
103
104 conn =
105 conn
106 |> assign(:user, user)
107 |> get("/api/v1/accounts/verify_credentials")
108
109 response = json_response(conn, 200)
110
111 assert %{"id" => id, "source" => %{"privacy" => "public"}} = response
112 assert response["pleroma"]["chat_token"]
113 assert id == to_string(user.id)
114 end
115
116 test "verify_credentials default scope unlisted", %{conn: conn} do
117 user = insert(:user, %{info: %User.Info{default_scope: "unlisted"}})
118
119 conn =
120 conn
121 |> assign(:user, user)
122 |> get("/api/v1/accounts/verify_credentials")
123
124 assert %{"id" => id, "source" => %{"privacy" => "unlisted"}} = json_response(conn, 200)
125 assert id == to_string(user.id)
126 end
127
128 test "apps/verify_credentials", %{conn: conn} do
129 token = insert(:oauth_token)
130
131 conn =
132 conn
133 |> assign(:user, token.user)
134 |> assign(:token, token)
135 |> get("/api/v1/apps/verify_credentials")
136
137 app = Repo.preload(token, :app).app
138
139 expected = %{
140 "name" => app.client_name,
141 "website" => app.website,
142 "vapid_key" => Push.vapid_config() |> Keyword.get(:public_key)
143 }
144
145 assert expected == json_response(conn, 200)
146 end
147
148 test "user avatar can be set", %{conn: conn} do
149 user = insert(:user)
150 avatar_image = File.read!("test/fixtures/avatar_data_uri")
151
152 conn =
153 conn
154 |> assign(:user, user)
155 |> patch("/api/v1/pleroma/accounts/update_avatar", %{img: avatar_image})
156
157 user = refresh_record(user)
158
159 assert %{
160 "name" => _,
161 "type" => _,
162 "url" => [
163 %{
164 "href" => _,
165 "mediaType" => _,
166 "type" => _
167 }
168 ]
169 } = user.avatar
170
171 assert %{"url" => _} = json_response(conn, 200)
172 end
173
174 test "user avatar can be reset", %{conn: conn} do
175 user = insert(:user)
176
177 conn =
178 conn
179 |> assign(:user, user)
180 |> patch("/api/v1/pleroma/accounts/update_avatar", %{img: ""})
181
182 user = User.get_cached_by_id(user.id)
183
184 assert user.avatar == nil
185
186 assert %{"url" => nil} = json_response(conn, 200)
187 end
188
189 test "can set profile banner", %{conn: conn} do
190 user = insert(:user)
191
192 conn =
193 conn
194 |> assign(:user, user)
195 |> patch("/api/v1/pleroma/accounts/update_banner", %{"banner" => @image})
196
197 user = refresh_record(user)
198 assert user.info.banner["type"] == "Image"
199
200 assert %{"url" => _} = json_response(conn, 200)
201 end
202
203 test "can reset profile banner", %{conn: conn} do
204 user = insert(:user)
205
206 conn =
207 conn
208 |> assign(:user, user)
209 |> patch("/api/v1/pleroma/accounts/update_banner", %{"banner" => ""})
210
211 user = refresh_record(user)
212 assert user.info.banner == %{}
213
214 assert %{"url" => nil} = json_response(conn, 200)
215 end
216
217 test "background image can be set", %{conn: conn} do
218 user = insert(:user)
219
220 conn =
221 conn
222 |> assign(:user, user)
223 |> patch("/api/v1/pleroma/accounts/update_background", %{"img" => @image})
224
225 user = refresh_record(user)
226 assert user.info.background["type"] == "Image"
227 assert %{"url" => _} = json_response(conn, 200)
228 end
229
230 test "background image can be reset", %{conn: conn} do
231 user = insert(:user)
232
233 conn =
234 conn
235 |> assign(:user, user)
236 |> patch("/api/v1/pleroma/accounts/update_background", %{"img" => ""})
237
238 user = refresh_record(user)
239 assert user.info.background == %{}
240 assert %{"url" => nil} = json_response(conn, 200)
241 end
242
243 test "creates an oauth app", %{conn: conn} do
244 user = insert(:user)
245 app_attrs = build(:oauth_app)
246
247 conn =
248 conn
249 |> assign(:user, user)
250 |> post("/api/v1/apps", %{
251 client_name: app_attrs.client_name,
252 redirect_uris: app_attrs.redirect_uris
253 })
254
255 [app] = Repo.all(App)
256
257 expected = %{
258 "name" => app.client_name,
259 "website" => app.website,
260 "client_id" => app.client_id,
261 "client_secret" => app.client_secret,
262 "id" => app.id |> to_string(),
263 "redirect_uri" => app.redirect_uris,
264 "vapid_key" => Push.vapid_config() |> Keyword.get(:public_key)
265 }
266
267 assert expected == json_response(conn, 200)
268 end
269
270 describe "user timelines" do
271 test "gets a users statuses", %{conn: conn} do
272 user_one = insert(:user)
273 user_two = insert(:user)
274 user_three = insert(:user)
275
276 {:ok, user_three} = User.follow(user_three, user_one)
277
278 {:ok, activity} = CommonAPI.post(user_one, %{"status" => "HI!!!"})
279
280 {:ok, direct_activity} =
281 CommonAPI.post(user_one, %{
282 "status" => "Hi, @#{user_two.nickname}.",
283 "visibility" => "direct"
284 })
285
286 {:ok, private_activity} =
287 CommonAPI.post(user_one, %{"status" => "private", "visibility" => "private"})
288
289 resp =
290 conn
291 |> get("/api/v1/accounts/#{user_one.id}/statuses")
292
293 assert [%{"id" => id}] = json_response(resp, 200)
294 assert id == to_string(activity.id)
295
296 resp =
297 conn
298 |> assign(:user, user_two)
299 |> get("/api/v1/accounts/#{user_one.id}/statuses")
300
301 assert [%{"id" => id_one}, %{"id" => id_two}] = json_response(resp, 200)
302 assert id_one == to_string(direct_activity.id)
303 assert id_two == to_string(activity.id)
304
305 resp =
306 conn
307 |> assign(:user, user_three)
308 |> get("/api/v1/accounts/#{user_one.id}/statuses")
309
310 assert [%{"id" => id_one}, %{"id" => id_two}] = json_response(resp, 200)
311 assert id_one == to_string(private_activity.id)
312 assert id_two == to_string(activity.id)
313 end
314
315 test "unimplemented pinned statuses feature", %{conn: conn} do
316 note = insert(:note_activity)
317 user = User.get_cached_by_ap_id(note.data["actor"])
318
319 conn =
320 conn
321 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
322
323 assert json_response(conn, 200) == []
324 end
325
326 test "gets an users media", %{conn: conn} do
327 note = insert(:note_activity)
328 user = User.get_cached_by_ap_id(note.data["actor"])
329
330 file = %Plug.Upload{
331 content_type: "image/jpg",
332 path: Path.absname("test/fixtures/image.jpg"),
333 filename: "an_image.jpg"
334 }
335
336 {:ok, %{id: media_id}} = ActivityPub.upload(file, actor: user.ap_id)
337
338 {:ok, image_post} = CommonAPI.post(user, %{"status" => "cofe", "media_ids" => [media_id]})
339
340 conn =
341 conn
342 |> get("/api/v1/accounts/#{user.id}/statuses", %{"only_media" => "true"})
343
344 assert [%{"id" => id}] = json_response(conn, 200)
345 assert id == to_string(image_post.id)
346
347 conn =
348 build_conn()
349 |> get("/api/v1/accounts/#{user.id}/statuses", %{"only_media" => "1"})
350
351 assert [%{"id" => id}] = json_response(conn, 200)
352 assert id == to_string(image_post.id)
353 end
354
355 test "gets a user's statuses without reblogs", %{conn: conn} do
356 user = insert(:user)
357 {:ok, post} = CommonAPI.post(user, %{"status" => "HI!!!"})
358 {:ok, _, _} = CommonAPI.repeat(post.id, user)
359
360 conn =
361 conn
362 |> get("/api/v1/accounts/#{user.id}/statuses", %{"exclude_reblogs" => "true"})
363
364 assert [%{"id" => id}] = json_response(conn, 200)
365 assert id == to_string(post.id)
366
367 conn =
368 conn
369 |> get("/api/v1/accounts/#{user.id}/statuses", %{"exclude_reblogs" => "1"})
370
371 assert [%{"id" => id}] = json_response(conn, 200)
372 assert id == to_string(post.id)
373 end
374
375 test "filters user's statuses by a hashtag", %{conn: conn} do
376 user = insert(:user)
377 {:ok, post} = CommonAPI.post(user, %{"status" => "#hashtag"})
378 {:ok, _post} = CommonAPI.post(user, %{"status" => "hashtag"})
379
380 conn =
381 conn
382 |> get("/api/v1/accounts/#{user.id}/statuses", %{"tagged" => "hashtag"})
383
384 assert [%{"id" => id}] = json_response(conn, 200)
385 assert id == to_string(post.id)
386 end
387 end
388
389 describe "user relationships" do
390 test "returns the relationships for the current user", %{conn: conn} do
391 user = insert(:user)
392 other_user = insert(:user)
393 {:ok, user} = User.follow(user, other_user)
394
395 conn =
396 conn
397 |> assign(:user, user)
398 |> get("/api/v1/accounts/relationships", %{"id" => [other_user.id]})
399
400 assert [relationship] = json_response(conn, 200)
401
402 assert to_string(other_user.id) == relationship["id"]
403 end
404 end
405
406 describe "media upload" do
407 setup do
408 user = insert(:user)
409
410 conn =
411 build_conn()
412 |> assign(:user, user)
413
414 image = %Plug.Upload{
415 content_type: "image/jpg",
416 path: Path.absname("test/fixtures/image.jpg"),
417 filename: "an_image.jpg"
418 }
419
420 [conn: conn, image: image]
421 end
422
423 clear_config([:media_proxy])
424 clear_config([Pleroma.Upload])
425
426 test "returns uploaded image", %{conn: conn, image: image} do
427 desc = "Description of the image"
428
429 media =
430 conn
431 |> post("/api/v1/media", %{"file" => image, "description" => desc})
432 |> json_response(:ok)
433
434 assert media["type"] == "image"
435 assert media["description"] == desc
436 assert media["id"]
437
438 object = Repo.get(Object, media["id"])
439 assert object.data["actor"] == User.ap_id(conn.assigns[:user])
440 end
441 end
442
443 describe "locked accounts" do
444 test "/api/v1/follow_requests works" do
445 user = insert(:user, %{info: %User.Info{locked: true}})
446 other_user = insert(:user)
447
448 {:ok, _activity} = ActivityPub.follow(other_user, user)
449
450 user = User.get_cached_by_id(user.id)
451 other_user = User.get_cached_by_id(other_user.id)
452
453 assert User.following?(other_user, user) == false
454
455 conn =
456 build_conn()
457 |> assign(:user, user)
458 |> get("/api/v1/follow_requests")
459
460 assert [relationship] = json_response(conn, 200)
461 assert to_string(other_user.id) == relationship["id"]
462 end
463
464 test "/api/v1/follow_requests/:id/authorize works" do
465 user = insert(:user, %{info: %User.Info{locked: true}})
466 other_user = insert(:user)
467
468 {:ok, _activity} = ActivityPub.follow(other_user, user)
469
470 user = User.get_cached_by_id(user.id)
471 other_user = User.get_cached_by_id(other_user.id)
472
473 assert User.following?(other_user, user) == false
474
475 conn =
476 build_conn()
477 |> assign(:user, user)
478 |> post("/api/v1/follow_requests/#{other_user.id}/authorize")
479
480 assert relationship = json_response(conn, 200)
481 assert to_string(other_user.id) == relationship["id"]
482
483 user = User.get_cached_by_id(user.id)
484 other_user = User.get_cached_by_id(other_user.id)
485
486 assert User.following?(other_user, user) == true
487 end
488
489 test "verify_credentials", %{conn: conn} do
490 user = insert(:user, %{info: %User.Info{default_scope: "private"}})
491
492 conn =
493 conn
494 |> assign(:user, user)
495 |> get("/api/v1/accounts/verify_credentials")
496
497 assert %{"id" => id, "source" => %{"privacy" => "private"}} = json_response(conn, 200)
498 assert id == to_string(user.id)
499 end
500
501 test "/api/v1/follow_requests/:id/reject works" do
502 user = insert(:user, %{info: %User.Info{locked: true}})
503 other_user = insert(:user)
504
505 {:ok, _activity} = ActivityPub.follow(other_user, user)
506
507 user = User.get_cached_by_id(user.id)
508
509 conn =
510 build_conn()
511 |> assign(:user, user)
512 |> post("/api/v1/follow_requests/#{other_user.id}/reject")
513
514 assert relationship = json_response(conn, 200)
515 assert to_string(other_user.id) == relationship["id"]
516
517 user = User.get_cached_by_id(user.id)
518 other_user = User.get_cached_by_id(other_user.id)
519
520 assert User.following?(other_user, user) == false
521 end
522 end
523
524 describe "account fetching" do
525 test "works by id" do
526 user = insert(:user)
527
528 conn =
529 build_conn()
530 |> get("/api/v1/accounts/#{user.id}")
531
532 assert %{"id" => id} = json_response(conn, 200)
533 assert id == to_string(user.id)
534
535 conn =
536 build_conn()
537 |> get("/api/v1/accounts/-1")
538
539 assert %{"error" => "Can't find user"} = json_response(conn, 404)
540 end
541
542 test "works by nickname" do
543 user = insert(:user)
544
545 conn =
546 build_conn()
547 |> get("/api/v1/accounts/#{user.nickname}")
548
549 assert %{"id" => id} = json_response(conn, 200)
550 assert id == user.id
551 end
552
553 test "works by nickname for remote users" do
554 limit_to_local = Pleroma.Config.get([:instance, :limit_to_local_content])
555 Pleroma.Config.put([:instance, :limit_to_local_content], false)
556 user = insert(:user, nickname: "user@example.com", local: false)
557
558 conn =
559 build_conn()
560 |> get("/api/v1/accounts/#{user.nickname}")
561
562 Pleroma.Config.put([:instance, :limit_to_local_content], limit_to_local)
563 assert %{"id" => id} = json_response(conn, 200)
564 assert id == user.id
565 end
566
567 test "respects limit_to_local_content == :all for remote user nicknames" do
568 limit_to_local = Pleroma.Config.get([:instance, :limit_to_local_content])
569 Pleroma.Config.put([:instance, :limit_to_local_content], :all)
570
571 user = insert(:user, nickname: "user@example.com", local: false)
572
573 conn =
574 build_conn()
575 |> get("/api/v1/accounts/#{user.nickname}")
576
577 Pleroma.Config.put([:instance, :limit_to_local_content], limit_to_local)
578 assert json_response(conn, 404)
579 end
580
581 test "respects limit_to_local_content == :unauthenticated for remote user nicknames" do
582 limit_to_local = Pleroma.Config.get([:instance, :limit_to_local_content])
583 Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
584
585 user = insert(:user, nickname: "user@example.com", local: false)
586 reading_user = insert(:user)
587
588 conn =
589 build_conn()
590 |> get("/api/v1/accounts/#{user.nickname}")
591
592 assert json_response(conn, 404)
593
594 conn =
595 build_conn()
596 |> assign(:user, reading_user)
597 |> get("/api/v1/accounts/#{user.nickname}")
598
599 Pleroma.Config.put([:instance, :limit_to_local_content], limit_to_local)
600 assert %{"id" => id} = json_response(conn, 200)
601 assert id == user.id
602 end
603 end
604
605 test "mascot upload", %{conn: conn} do
606 user = insert(:user)
607
608 non_image_file = %Plug.Upload{
609 content_type: "audio/mpeg",
610 path: Path.absname("test/fixtures/sound.mp3"),
611 filename: "sound.mp3"
612 }
613
614 conn =
615 conn
616 |> assign(:user, user)
617 |> put("/api/v1/pleroma/mascot", %{"file" => non_image_file})
618
619 assert json_response(conn, 415)
620
621 file = %Plug.Upload{
622 content_type: "image/jpg",
623 path: Path.absname("test/fixtures/image.jpg"),
624 filename: "an_image.jpg"
625 }
626
627 conn =
628 build_conn()
629 |> assign(:user, user)
630 |> put("/api/v1/pleroma/mascot", %{"file" => file})
631
632 assert %{"id" => _, "type" => image} = json_response(conn, 200)
633 end
634
635 test "mascot retrieving", %{conn: conn} do
636 user = insert(:user)
637 # When user hasn't set a mascot, we should just get pleroma tan back
638 conn =
639 conn
640 |> assign(:user, user)
641 |> get("/api/v1/pleroma/mascot")
642
643 assert %{"url" => url} = json_response(conn, 200)
644 assert url =~ "pleroma-fox-tan-smol"
645
646 # When a user sets their mascot, we should get that back
647 file = %Plug.Upload{
648 content_type: "image/jpg",
649 path: Path.absname("test/fixtures/image.jpg"),
650 filename: "an_image.jpg"
651 }
652
653 conn =
654 build_conn()
655 |> assign(:user, user)
656 |> put("/api/v1/pleroma/mascot", %{"file" => file})
657
658 assert json_response(conn, 200)
659
660 user = User.get_cached_by_id(user.id)
661
662 conn =
663 build_conn()
664 |> assign(:user, user)
665 |> get("/api/v1/pleroma/mascot")
666
667 assert %{"url" => url, "type" => "image"} = json_response(conn, 200)
668 assert url =~ "an_image"
669 end
670
671 test "getting followers", %{conn: conn} do
672 user = insert(:user)
673 other_user = insert(:user)
674 {:ok, user} = User.follow(user, other_user)
675
676 conn =
677 conn
678 |> get("/api/v1/accounts/#{other_user.id}/followers")
679
680 assert [%{"id" => id}] = json_response(conn, 200)
681 assert id == to_string(user.id)
682 end
683
684 test "getting followers, hide_followers", %{conn: conn} do
685 user = insert(:user)
686 other_user = insert(:user, %{info: %{hide_followers: true}})
687 {:ok, _user} = User.follow(user, other_user)
688
689 conn =
690 conn
691 |> get("/api/v1/accounts/#{other_user.id}/followers")
692
693 assert [] == json_response(conn, 200)
694 end
695
696 test "getting followers, hide_followers, same user requesting", %{conn: conn} do
697 user = insert(:user)
698 other_user = insert(:user, %{info: %{hide_followers: true}})
699 {:ok, _user} = User.follow(user, other_user)
700
701 conn =
702 conn
703 |> assign(:user, other_user)
704 |> get("/api/v1/accounts/#{other_user.id}/followers")
705
706 refute [] == json_response(conn, 200)
707 end
708
709 test "getting followers, pagination", %{conn: conn} do
710 user = insert(:user)
711 follower1 = insert(:user)
712 follower2 = insert(:user)
713 follower3 = insert(:user)
714 {:ok, _} = User.follow(follower1, user)
715 {:ok, _} = User.follow(follower2, user)
716 {:ok, _} = User.follow(follower3, user)
717
718 conn =
719 conn
720 |> assign(:user, user)
721
722 res_conn =
723 conn
724 |> get("/api/v1/accounts/#{user.id}/followers?since_id=#{follower1.id}")
725
726 assert [%{"id" => id3}, %{"id" => id2}] = json_response(res_conn, 200)
727 assert id3 == follower3.id
728 assert id2 == follower2.id
729
730 res_conn =
731 conn
732 |> get("/api/v1/accounts/#{user.id}/followers?max_id=#{follower3.id}")
733
734 assert [%{"id" => id2}, %{"id" => id1}] = json_response(res_conn, 200)
735 assert id2 == follower2.id
736 assert id1 == follower1.id
737
738 res_conn =
739 conn
740 |> get("/api/v1/accounts/#{user.id}/followers?limit=1&max_id=#{follower3.id}")
741
742 assert [%{"id" => id2}] = json_response(res_conn, 200)
743 assert id2 == follower2.id
744
745 assert [link_header] = get_resp_header(res_conn, "link")
746 assert link_header =~ ~r/min_id=#{follower2.id}/
747 assert link_header =~ ~r/max_id=#{follower2.id}/
748 end
749
750 test "getting following", %{conn: conn} do
751 user = insert(:user)
752 other_user = insert(:user)
753 {:ok, user} = User.follow(user, other_user)
754
755 conn =
756 conn
757 |> get("/api/v1/accounts/#{user.id}/following")
758
759 assert [%{"id" => id}] = json_response(conn, 200)
760 assert id == to_string(other_user.id)
761 end
762
763 test "getting following, hide_follows", %{conn: conn} do
764 user = insert(:user, %{info: %{hide_follows: true}})
765 other_user = insert(:user)
766 {:ok, user} = User.follow(user, other_user)
767
768 conn =
769 conn
770 |> get("/api/v1/accounts/#{user.id}/following")
771
772 assert [] == json_response(conn, 200)
773 end
774
775 test "getting following, hide_follows, same user requesting", %{conn: conn} do
776 user = insert(:user, %{info: %{hide_follows: true}})
777 other_user = insert(:user)
778 {:ok, user} = User.follow(user, other_user)
779
780 conn =
781 conn
782 |> assign(:user, user)
783 |> get("/api/v1/accounts/#{user.id}/following")
784
785 refute [] == json_response(conn, 200)
786 end
787
788 test "getting following, pagination", %{conn: conn} do
789 user = insert(:user)
790 following1 = insert(:user)
791 following2 = insert(:user)
792 following3 = insert(:user)
793 {:ok, _} = User.follow(user, following1)
794 {:ok, _} = User.follow(user, following2)
795 {:ok, _} = User.follow(user, following3)
796
797 conn =
798 conn
799 |> assign(:user, user)
800
801 res_conn =
802 conn
803 |> get("/api/v1/accounts/#{user.id}/following?since_id=#{following1.id}")
804
805 assert [%{"id" => id3}, %{"id" => id2}] = json_response(res_conn, 200)
806 assert id3 == following3.id
807 assert id2 == following2.id
808
809 res_conn =
810 conn
811 |> get("/api/v1/accounts/#{user.id}/following?max_id=#{following3.id}")
812
813 assert [%{"id" => id2}, %{"id" => id1}] = json_response(res_conn, 200)
814 assert id2 == following2.id
815 assert id1 == following1.id
816
817 res_conn =
818 conn
819 |> get("/api/v1/accounts/#{user.id}/following?limit=1&max_id=#{following3.id}")
820
821 assert [%{"id" => id2}] = json_response(res_conn, 200)
822 assert id2 == following2.id
823
824 assert [link_header] = get_resp_header(res_conn, "link")
825 assert link_header =~ ~r/min_id=#{following2.id}/
826 assert link_header =~ ~r/max_id=#{following2.id}/
827 end
828
829 test "following / unfollowing a user", %{conn: conn} do
830 user = insert(:user)
831 other_user = insert(:user)
832
833 conn =
834 conn
835 |> assign(:user, user)
836 |> post("/api/v1/accounts/#{other_user.id}/follow")
837
838 assert %{"id" => _id, "following" => true} = json_response(conn, 200)
839
840 user = User.get_cached_by_id(user.id)
841
842 conn =
843 build_conn()
844 |> assign(:user, user)
845 |> post("/api/v1/accounts/#{other_user.id}/unfollow")
846
847 assert %{"id" => _id, "following" => false} = json_response(conn, 200)
848
849 user = User.get_cached_by_id(user.id)
850
851 conn =
852 build_conn()
853 |> assign(:user, user)
854 |> post("/api/v1/follows", %{"uri" => other_user.nickname})
855
856 assert %{"id" => id} = json_response(conn, 200)
857 assert id == to_string(other_user.id)
858 end
859
860 test "following without reblogs" do
861 follower = insert(:user)
862 followed = insert(:user)
863 other_user = insert(:user)
864
865 conn =
866 build_conn()
867 |> assign(:user, follower)
868 |> post("/api/v1/accounts/#{followed.id}/follow?reblogs=false")
869
870 assert %{"showing_reblogs" => false} = json_response(conn, 200)
871
872 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "hey"})
873 {:ok, reblog, _} = CommonAPI.repeat(activity.id, followed)
874
875 conn =
876 build_conn()
877 |> assign(:user, User.get_cached_by_id(follower.id))
878 |> get("/api/v1/timelines/home")
879
880 assert [] == json_response(conn, 200)
881
882 conn =
883 build_conn()
884 |> assign(:user, follower)
885 |> post("/api/v1/accounts/#{followed.id}/follow?reblogs=true")
886
887 assert %{"showing_reblogs" => true} = json_response(conn, 200)
888
889 conn =
890 build_conn()
891 |> assign(:user, User.get_cached_by_id(follower.id))
892 |> get("/api/v1/timelines/home")
893
894 expected_activity_id = reblog.id
895 assert [%{"id" => ^expected_activity_id}] = json_response(conn, 200)
896 end
897
898 test "following / unfollowing errors" do
899 user = insert(:user)
900
901 conn =
902 build_conn()
903 |> assign(:user, user)
904
905 # self follow
906 conn_res = post(conn, "/api/v1/accounts/#{user.id}/follow")
907 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
908
909 # self unfollow
910 user = User.get_cached_by_id(user.id)
911 conn_res = post(conn, "/api/v1/accounts/#{user.id}/unfollow")
912 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
913
914 # self follow via uri
915 user = User.get_cached_by_id(user.id)
916 conn_res = post(conn, "/api/v1/follows", %{"uri" => user.nickname})
917 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
918
919 # follow non existing user
920 conn_res = post(conn, "/api/v1/accounts/doesntexist/follow")
921 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
922
923 # follow non existing user via uri
924 conn_res = post(conn, "/api/v1/follows", %{"uri" => "doesntexist"})
925 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
926
927 # unfollow non existing user
928 conn_res = post(conn, "/api/v1/accounts/doesntexist/unfollow")
929 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
930 end
931
932 describe "mute/unmute" do
933 test "with notifications", %{conn: conn} do
934 user = insert(:user)
935 other_user = insert(:user)
936
937 conn =
938 conn
939 |> assign(:user, user)
940 |> post("/api/v1/accounts/#{other_user.id}/mute")
941
942 response = json_response(conn, 200)
943
944 assert %{"id" => _id, "muting" => true, "muting_notifications" => true} = response
945 user = User.get_cached_by_id(user.id)
946
947 conn =
948 build_conn()
949 |> assign(:user, user)
950 |> post("/api/v1/accounts/#{other_user.id}/unmute")
951
952 response = json_response(conn, 200)
953 assert %{"id" => _id, "muting" => false, "muting_notifications" => false} = response
954 end
955
956 test "without notifications", %{conn: conn} do
957 user = insert(:user)
958 other_user = insert(:user)
959
960 conn =
961 conn
962 |> assign(:user, user)
963 |> post("/api/v1/accounts/#{other_user.id}/mute", %{"notifications" => "false"})
964
965 response = json_response(conn, 200)
966
967 assert %{"id" => _id, "muting" => true, "muting_notifications" => false} = response
968 user = User.get_cached_by_id(user.id)
969
970 conn =
971 build_conn()
972 |> assign(:user, user)
973 |> post("/api/v1/accounts/#{other_user.id}/unmute")
974
975 response = json_response(conn, 200)
976 assert %{"id" => _id, "muting" => false, "muting_notifications" => false} = response
977 end
978 end
979
980 test "subscribing / unsubscribing to a user", %{conn: conn} do
981 user = insert(:user)
982 subscription_target = insert(:user)
983
984 conn =
985 conn
986 |> assign(:user, user)
987 |> post("/api/v1/pleroma/accounts/#{subscription_target.id}/subscribe")
988
989 assert %{"id" => _id, "subscribing" => true} = json_response(conn, 200)
990
991 conn =
992 build_conn()
993 |> assign(:user, user)
994 |> post("/api/v1/pleroma/accounts/#{subscription_target.id}/unsubscribe")
995
996 assert %{"id" => _id, "subscribing" => false} = json_response(conn, 200)
997 end
998
999 test "getting a list of mutes", %{conn: conn} do
1000 user = insert(:user)
1001 other_user = insert(:user)
1002
1003 {:ok, user} = User.mute(user, other_user)
1004
1005 conn =
1006 conn
1007 |> assign(:user, user)
1008 |> get("/api/v1/mutes")
1009
1010 other_user_id = to_string(other_user.id)
1011 assert [%{"id" => ^other_user_id}] = json_response(conn, 200)
1012 end
1013
1014 test "blocking / unblocking a user", %{conn: conn} do
1015 user = insert(:user)
1016 other_user = insert(:user)
1017
1018 conn =
1019 conn
1020 |> assign(:user, user)
1021 |> post("/api/v1/accounts/#{other_user.id}/block")
1022
1023 assert %{"id" => _id, "blocking" => true} = json_response(conn, 200)
1024
1025 user = User.get_cached_by_id(user.id)
1026
1027 conn =
1028 build_conn()
1029 |> assign(:user, user)
1030 |> post("/api/v1/accounts/#{other_user.id}/unblock")
1031
1032 assert %{"id" => _id, "blocking" => false} = json_response(conn, 200)
1033 end
1034
1035 test "getting a list of blocks", %{conn: conn} do
1036 user = insert(:user)
1037 other_user = insert(:user)
1038
1039 {:ok, user} = User.block(user, other_user)
1040
1041 conn =
1042 conn
1043 |> assign(:user, user)
1044 |> get("/api/v1/blocks")
1045
1046 other_user_id = to_string(other_user.id)
1047 assert [%{"id" => ^other_user_id}] = json_response(conn, 200)
1048 end
1049
1050 test "blocking / unblocking a domain", %{conn: conn} do
1051 user = insert(:user)
1052 other_user = insert(:user, %{ap_id: "https://dogwhistle.zone/@pundit"})
1053
1054 conn =
1055 conn
1056 |> assign(:user, user)
1057 |> post("/api/v1/domain_blocks", %{"domain" => "dogwhistle.zone"})
1058
1059 assert %{} = json_response(conn, 200)
1060 user = User.get_cached_by_ap_id(user.ap_id)
1061 assert User.blocks?(user, other_user)
1062
1063 conn =
1064 build_conn()
1065 |> assign(:user, user)
1066 |> delete("/api/v1/domain_blocks", %{"domain" => "dogwhistle.zone"})
1067
1068 assert %{} = json_response(conn, 200)
1069 user = User.get_cached_by_ap_id(user.ap_id)
1070 refute User.blocks?(user, other_user)
1071 end
1072
1073 test "getting a list of domain blocks", %{conn: conn} do
1074 user = insert(:user)
1075
1076 {:ok, user} = User.block_domain(user, "bad.site")
1077 {:ok, user} = User.block_domain(user, "even.worse.site")
1078
1079 conn =
1080 conn
1081 |> assign(:user, user)
1082 |> get("/api/v1/domain_blocks")
1083
1084 domain_blocks = json_response(conn, 200)
1085
1086 assert "bad.site" in domain_blocks
1087 assert "even.worse.site" in domain_blocks
1088 end
1089
1090 test "unimplemented follow_requests, blocks, domain blocks" do
1091 user = insert(:user)
1092
1093 ["blocks", "domain_blocks", "follow_requests"]
1094 |> Enum.each(fn endpoint ->
1095 conn =
1096 build_conn()
1097 |> assign(:user, user)
1098 |> get("/api/v1/#{endpoint}")
1099
1100 assert [] = json_response(conn, 200)
1101 end)
1102 end
1103
1104 test "returns the favorites of a user", %{conn: conn} do
1105 user = insert(:user)
1106 other_user = insert(:user)
1107
1108 {:ok, _} = CommonAPI.post(other_user, %{"status" => "bla"})
1109 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "traps are happy"})
1110
1111 {:ok, _, _} = CommonAPI.favorite(activity.id, user)
1112
1113 first_conn =
1114 conn
1115 |> assign(:user, user)
1116 |> get("/api/v1/favourites")
1117
1118 assert [status] = json_response(first_conn, 200)
1119 assert status["id"] == to_string(activity.id)
1120
1121 assert [{"link", _link_header}] =
1122 Enum.filter(first_conn.resp_headers, fn element -> match?({"link", _}, element) end)
1123
1124 # Honours query params
1125 {:ok, second_activity} =
1126 CommonAPI.post(other_user, %{
1127 "status" =>
1128 "Trees Are Never Sad Look At Them Every Once In Awhile They're Quite Beautiful."
1129 })
1130
1131 {:ok, _, _} = CommonAPI.favorite(second_activity.id, user)
1132
1133 last_like = status["id"]
1134
1135 second_conn =
1136 conn
1137 |> assign(:user, user)
1138 |> get("/api/v1/favourites?since_id=#{last_like}")
1139
1140 assert [second_status] = json_response(second_conn, 200)
1141 assert second_status["id"] == to_string(second_activity.id)
1142
1143 third_conn =
1144 conn
1145 |> assign(:user, user)
1146 |> get("/api/v1/favourites?limit=0")
1147
1148 assert [] = json_response(third_conn, 200)
1149 end
1150
1151 describe "getting favorites timeline of specified user" do
1152 setup do
1153 [current_user, user] = insert_pair(:user, %{info: %{hide_favorites: false}})
1154 [current_user: current_user, user: user]
1155 end
1156
1157 test "returns list of statuses favorited by specified user", %{
1158 conn: conn,
1159 current_user: current_user,
1160 user: user
1161 } do
1162 [activity | _] = insert_pair(:note_activity)
1163 CommonAPI.favorite(activity.id, user)
1164
1165 response =
1166 conn
1167 |> assign(:user, current_user)
1168 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
1169 |> json_response(:ok)
1170
1171 [like] = response
1172
1173 assert length(response) == 1
1174 assert like["id"] == activity.id
1175 end
1176
1177 test "returns favorites for specified user_id when user is not logged in", %{
1178 conn: conn,
1179 user: user
1180 } do
1181 activity = insert(:note_activity)
1182 CommonAPI.favorite(activity.id, user)
1183
1184 response =
1185 conn
1186 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
1187 |> json_response(:ok)
1188
1189 assert length(response) == 1
1190 end
1191
1192 test "returns favorited DM only when user is logged in and he is one of recipients", %{
1193 conn: conn,
1194 current_user: current_user,
1195 user: user
1196 } do
1197 {:ok, direct} =
1198 CommonAPI.post(current_user, %{
1199 "status" => "Hi @#{user.nickname}!",
1200 "visibility" => "direct"
1201 })
1202
1203 CommonAPI.favorite(direct.id, user)
1204
1205 response =
1206 conn
1207 |> assign(:user, current_user)
1208 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
1209 |> json_response(:ok)
1210
1211 assert length(response) == 1
1212
1213 anonymous_response =
1214 conn
1215 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
1216 |> json_response(:ok)
1217
1218 assert Enum.empty?(anonymous_response)
1219 end
1220
1221 test "does not return others' favorited DM when user is not one of recipients", %{
1222 conn: conn,
1223 current_user: current_user,
1224 user: user
1225 } do
1226 user_two = insert(:user)
1227
1228 {:ok, direct} =
1229 CommonAPI.post(user_two, %{
1230 "status" => "Hi @#{user.nickname}!",
1231 "visibility" => "direct"
1232 })
1233
1234 CommonAPI.favorite(direct.id, user)
1235
1236 response =
1237 conn
1238 |> assign(:user, current_user)
1239 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
1240 |> json_response(:ok)
1241
1242 assert Enum.empty?(response)
1243 end
1244
1245 test "paginates favorites using since_id and max_id", %{
1246 conn: conn,
1247 current_user: current_user,
1248 user: user
1249 } do
1250 activities = insert_list(10, :note_activity)
1251
1252 Enum.each(activities, fn activity ->
1253 CommonAPI.favorite(activity.id, user)
1254 end)
1255
1256 third_activity = Enum.at(activities, 2)
1257 seventh_activity = Enum.at(activities, 6)
1258
1259 response =
1260 conn
1261 |> assign(:user, current_user)
1262 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites", %{
1263 since_id: third_activity.id,
1264 max_id: seventh_activity.id
1265 })
1266 |> json_response(:ok)
1267
1268 assert length(response) == 3
1269 refute third_activity in response
1270 refute seventh_activity in response
1271 end
1272
1273 test "limits favorites using limit parameter", %{
1274 conn: conn,
1275 current_user: current_user,
1276 user: user
1277 } do
1278 7
1279 |> insert_list(:note_activity)
1280 |> Enum.each(fn activity ->
1281 CommonAPI.favorite(activity.id, user)
1282 end)
1283
1284 response =
1285 conn
1286 |> assign(:user, current_user)
1287 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites", %{limit: "3"})
1288 |> json_response(:ok)
1289
1290 assert length(response) == 3
1291 end
1292
1293 test "returns empty response when user does not have any favorited statuses", %{
1294 conn: conn,
1295 current_user: current_user,
1296 user: user
1297 } do
1298 response =
1299 conn
1300 |> assign(:user, current_user)
1301 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
1302 |> json_response(:ok)
1303
1304 assert Enum.empty?(response)
1305 end
1306
1307 test "returns 404 error when specified user is not exist", %{conn: conn} do
1308 conn = get(conn, "/api/v1/pleroma/accounts/test/favourites")
1309
1310 assert json_response(conn, 404) == %{"error" => "Record not found"}
1311 end
1312
1313 test "returns 403 error when user has hidden own favorites", %{
1314 conn: conn,
1315 current_user: current_user
1316 } do
1317 user = insert(:user, %{info: %{hide_favorites: true}})
1318 activity = insert(:note_activity)
1319 CommonAPI.favorite(activity.id, user)
1320
1321 conn =
1322 conn
1323 |> assign(:user, current_user)
1324 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
1325
1326 assert json_response(conn, 403) == %{"error" => "Can't get favorites"}
1327 end
1328
1329 test "hides favorites for new users by default", %{conn: conn, current_user: current_user} do
1330 user = insert(:user)
1331 activity = insert(:note_activity)
1332 CommonAPI.favorite(activity.id, user)
1333
1334 conn =
1335 conn
1336 |> assign(:user, current_user)
1337 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
1338
1339 assert user.info.hide_favorites
1340 assert json_response(conn, 403) == %{"error" => "Can't get favorites"}
1341 end
1342 end
1343
1344 test "get instance information", %{conn: conn} do
1345 conn = get(conn, "/api/v1/instance")
1346 assert result = json_response(conn, 200)
1347
1348 email = Config.get([:instance, :email])
1349 # Note: not checking for "max_toot_chars" since it's optional
1350 assert %{
1351 "uri" => _,
1352 "title" => _,
1353 "description" => _,
1354 "version" => _,
1355 "email" => from_config_email,
1356 "urls" => %{
1357 "streaming_api" => _
1358 },
1359 "stats" => _,
1360 "thumbnail" => _,
1361 "languages" => _,
1362 "registrations" => _,
1363 "poll_limits" => _
1364 } = result
1365
1366 assert email == from_config_email
1367 end
1368
1369 test "get instance stats", %{conn: conn} do
1370 user = insert(:user, %{local: true})
1371
1372 user2 = insert(:user, %{local: true})
1373 {:ok, _user2} = User.deactivate(user2, !user2.info.deactivated)
1374
1375 insert(:user, %{local: false, nickname: "u@peer1.com"})
1376 insert(:user, %{local: false, nickname: "u@peer2.com"})
1377
1378 {:ok, _} = CommonAPI.post(user, %{"status" => "cofe"})
1379
1380 # Stats should count users with missing or nil `info.deactivated` value
1381
1382 {:ok, _user} =
1383 user.id
1384 |> User.get_cached_by_id()
1385 |> User.update_info(&Changeset.change(&1, %{deactivated: nil}))
1386
1387 Pleroma.Stats.force_update()
1388
1389 conn = get(conn, "/api/v1/instance")
1390
1391 assert result = json_response(conn, 200)
1392
1393 stats = result["stats"]
1394
1395 assert stats
1396 assert stats["user_count"] == 1
1397 assert stats["status_count"] == 1
1398 assert stats["domain_count"] == 2
1399 end
1400
1401 test "get peers", %{conn: conn} do
1402 insert(:user, %{local: false, nickname: "u@peer1.com"})
1403 insert(:user, %{local: false, nickname: "u@peer2.com"})
1404
1405 Pleroma.Stats.force_update()
1406
1407 conn = get(conn, "/api/v1/instance/peers")
1408
1409 assert result = json_response(conn, 200)
1410
1411 assert ["peer1.com", "peer2.com"] == Enum.sort(result)
1412 end
1413
1414 test "put settings", %{conn: conn} do
1415 user = insert(:user)
1416
1417 conn =
1418 conn
1419 |> assign(:user, user)
1420 |> put("/api/web/settings", %{"data" => %{"programming" => "socks"}})
1421
1422 assert _result = json_response(conn, 200)
1423
1424 user = User.get_cached_by_ap_id(user.ap_id)
1425 assert user.info.settings == %{"programming" => "socks"}
1426 end
1427
1428 describe "pinned statuses" do
1429 setup do
1430 user = insert(:user)
1431 {:ok, activity} = CommonAPI.post(user, %{"status" => "HI!!!"})
1432
1433 [user: user, activity: activity]
1434 end
1435
1436 test "returns pinned statuses", %{conn: conn, user: user, activity: activity} do
1437 {:ok, _} = CommonAPI.pin(activity.id, user)
1438
1439 result =
1440 conn
1441 |> assign(:user, user)
1442 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
1443 |> json_response(200)
1444
1445 id_str = to_string(activity.id)
1446
1447 assert [%{"id" => ^id_str, "pinned" => true}] = result
1448 end
1449 end
1450
1451 describe "reports" do
1452 setup do
1453 reporter = insert(:user)
1454 target_user = insert(:user)
1455
1456 {:ok, activity} = CommonAPI.post(target_user, %{"status" => "foobar"})
1457
1458 [reporter: reporter, target_user: target_user, activity: activity]
1459 end
1460
1461 test "submit a basic report", %{conn: conn, reporter: reporter, target_user: target_user} do
1462 assert %{"action_taken" => false, "id" => _} =
1463 conn
1464 |> assign(:user, reporter)
1465 |> post("/api/v1/reports", %{"account_id" => target_user.id})
1466 |> json_response(200)
1467 end
1468
1469 test "submit a report with statuses and comment", %{
1470 conn: conn,
1471 reporter: reporter,
1472 target_user: target_user,
1473 activity: activity
1474 } do
1475 assert %{"action_taken" => false, "id" => _} =
1476 conn
1477 |> assign(:user, reporter)
1478 |> post("/api/v1/reports", %{
1479 "account_id" => target_user.id,
1480 "status_ids" => [activity.id],
1481 "comment" => "bad status!",
1482 "forward" => "false"
1483 })
1484 |> json_response(200)
1485 end
1486
1487 test "account_id is required", %{
1488 conn: conn,
1489 reporter: reporter,
1490 activity: activity
1491 } do
1492 assert %{"error" => "Valid `account_id` required"} =
1493 conn
1494 |> assign(:user, reporter)
1495 |> post("/api/v1/reports", %{"status_ids" => [activity.id]})
1496 |> json_response(400)
1497 end
1498
1499 test "comment must be up to the size specified in the config", %{
1500 conn: conn,
1501 reporter: reporter,
1502 target_user: target_user
1503 } do
1504 max_size = Config.get([:instance, :max_report_comment_size], 1000)
1505 comment = String.pad_trailing("a", max_size + 1, "a")
1506
1507 error = %{"error" => "Comment must be up to #{max_size} characters"}
1508
1509 assert ^error =
1510 conn
1511 |> assign(:user, reporter)
1512 |> post("/api/v1/reports", %{"account_id" => target_user.id, "comment" => comment})
1513 |> json_response(400)
1514 end
1515
1516 test "returns error when account is not exist", %{
1517 conn: conn,
1518 reporter: reporter,
1519 activity: activity
1520 } do
1521 conn =
1522 conn
1523 |> assign(:user, reporter)
1524 |> post("/api/v1/reports", %{"status_ids" => [activity.id], "account_id" => "foo"})
1525
1526 assert json_response(conn, 400) == %{"error" => "Account not found"}
1527 end
1528 end
1529
1530 describe "link headers" do
1531 test "preserves parameters in link headers", %{conn: conn} do
1532 user = insert(:user)
1533 other_user = insert(:user)
1534
1535 {:ok, activity1} =
1536 CommonAPI.post(other_user, %{
1537 "status" => "hi @#{user.nickname}",
1538 "visibility" => "public"
1539 })
1540
1541 {:ok, activity2} =
1542 CommonAPI.post(other_user, %{
1543 "status" => "hi @#{user.nickname}",
1544 "visibility" => "public"
1545 })
1546
1547 notification1 = Repo.get_by(Notification, activity_id: activity1.id)
1548 notification2 = Repo.get_by(Notification, activity_id: activity2.id)
1549
1550 conn =
1551 conn
1552 |> assign(:user, user)
1553 |> get("/api/v1/notifications", %{media_only: true})
1554
1555 assert [link_header] = get_resp_header(conn, "link")
1556 assert link_header =~ ~r/media_only=true/
1557 assert link_header =~ ~r/min_id=#{notification2.id}/
1558 assert link_header =~ ~r/max_id=#{notification1.id}/
1559 end
1560 end
1561
1562 test "accounts fetches correct account for nicknames beginning with numbers", %{conn: conn} do
1563 # Need to set an old-style integer ID to reproduce the problem
1564 # (these are no longer assigned to new accounts but were preserved
1565 # for existing accounts during the migration to flakeIDs)
1566 user_one = insert(:user, %{id: 1212})
1567 user_two = insert(:user, %{nickname: "#{user_one.id}garbage"})
1568
1569 resp_one =
1570 conn
1571 |> get("/api/v1/accounts/#{user_one.id}")
1572
1573 resp_two =
1574 conn
1575 |> get("/api/v1/accounts/#{user_two.nickname}")
1576
1577 resp_three =
1578 conn
1579 |> get("/api/v1/accounts/#{user_two.id}")
1580
1581 acc_one = json_response(resp_one, 200)
1582 acc_two = json_response(resp_two, 200)
1583 acc_three = json_response(resp_three, 200)
1584 refute acc_one == acc_two
1585 assert acc_two == acc_three
1586 end
1587
1588 describe "custom emoji" do
1589 test "with tags", %{conn: conn} do
1590 [emoji | _body] =
1591 conn
1592 |> get("/api/v1/custom_emojis")
1593 |> json_response(200)
1594
1595 assert Map.has_key?(emoji, "shortcode")
1596 assert Map.has_key?(emoji, "static_url")
1597 assert Map.has_key?(emoji, "tags")
1598 assert is_list(emoji["tags"])
1599 assert Map.has_key?(emoji, "category")
1600 assert Map.has_key?(emoji, "url")
1601 assert Map.has_key?(emoji, "visible_in_picker")
1602 end
1603 end
1604
1605 describe "index/2 redirections" do
1606 setup %{conn: conn} do
1607 session_opts = [
1608 store: :cookie,
1609 key: "_test",
1610 signing_salt: "cooldude"
1611 ]
1612
1613 conn =
1614 conn
1615 |> Plug.Session.call(Plug.Session.init(session_opts))
1616 |> fetch_session()
1617
1618 test_path = "/web/statuses/test"
1619 %{conn: conn, path: test_path}
1620 end
1621
1622 test "redirects not logged-in users to the login page", %{conn: conn, path: path} do
1623 conn = get(conn, path)
1624
1625 assert conn.status == 302
1626 assert redirected_to(conn) == "/web/login"
1627 end
1628
1629 test "redirects not logged-in users to the login page on private instances", %{
1630 conn: conn,
1631 path: path
1632 } do
1633 Config.put([:instance, :public], false)
1634
1635 conn = get(conn, path)
1636
1637 assert conn.status == 302
1638 assert redirected_to(conn) == "/web/login"
1639 end
1640
1641 test "does not redirect logged in users to the login page", %{conn: conn, path: path} do
1642 token = insert(:oauth_token)
1643
1644 conn =
1645 conn
1646 |> assign(:user, token.user)
1647 |> put_session(:oauth_token, token.token)
1648 |> get(path)
1649
1650 assert conn.status == 200
1651 end
1652
1653 test "saves referer path to session", %{conn: conn, path: path} do
1654 conn = get(conn, path)
1655 return_to = Plug.Conn.get_session(conn, :return_to)
1656
1657 assert return_to == path
1658 end
1659
1660 test "redirects to the saved path after log in", %{conn: conn, path: path} do
1661 app = insert(:oauth_app, client_name: "Mastodon-Local", redirect_uris: ".")
1662 auth = insert(:oauth_authorization, app: app)
1663
1664 conn =
1665 conn
1666 |> put_session(:return_to, path)
1667 |> get("/web/login", %{code: auth.token})
1668
1669 assert conn.status == 302
1670 assert redirected_to(conn) == path
1671 end
1672
1673 test "redirects to the getting-started page when referer is not present", %{conn: conn} do
1674 app = insert(:oauth_app, client_name: "Mastodon-Local", redirect_uris: ".")
1675 auth = insert(:oauth_authorization, app: app)
1676
1677 conn = get(conn, "/web/login", %{code: auth.token})
1678
1679 assert conn.status == 302
1680 assert redirected_to(conn) == "/web/getting-started"
1681 end
1682 end
1683
1684 describe "scheduled activities" do
1685 test "creates a scheduled activity", %{conn: conn} do
1686 user = insert(:user)
1687 scheduled_at = NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond)
1688
1689 conn =
1690 conn
1691 |> assign(:user, user)
1692 |> post("/api/v1/statuses", %{
1693 "status" => "scheduled",
1694 "scheduled_at" => scheduled_at
1695 })
1696
1697 assert %{"scheduled_at" => expected_scheduled_at} = json_response(conn, 200)
1698 assert expected_scheduled_at == Pleroma.Web.CommonAPI.Utils.to_masto_date(scheduled_at)
1699 assert [] == Repo.all(Activity)
1700 end
1701
1702 test "creates a scheduled activity with a media attachment", %{conn: conn} do
1703 user = insert(:user)
1704 scheduled_at = NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond)
1705
1706 file = %Plug.Upload{
1707 content_type: "image/jpg",
1708 path: Path.absname("test/fixtures/image.jpg"),
1709 filename: "an_image.jpg"
1710 }
1711
1712 {:ok, upload} = ActivityPub.upload(file, actor: user.ap_id)
1713
1714 conn =
1715 conn
1716 |> assign(:user, user)
1717 |> post("/api/v1/statuses", %{
1718 "media_ids" => [to_string(upload.id)],
1719 "status" => "scheduled",
1720 "scheduled_at" => scheduled_at
1721 })
1722
1723 assert %{"media_attachments" => [media_attachment]} = json_response(conn, 200)
1724 assert %{"type" => "image"} = media_attachment
1725 end
1726
1727 test "skips the scheduling and creates the activity if scheduled_at is earlier than 5 minutes from now",
1728 %{conn: conn} do
1729 user = insert(:user)
1730
1731 scheduled_at =
1732 NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(5) - 1, :millisecond)
1733
1734 conn =
1735 conn
1736 |> assign(:user, user)
1737 |> post("/api/v1/statuses", %{
1738 "status" => "not scheduled",
1739 "scheduled_at" => scheduled_at
1740 })
1741
1742 assert %{"content" => "not scheduled"} = json_response(conn, 200)
1743 assert [] == Repo.all(ScheduledActivity)
1744 end
1745
1746 test "returns error when daily user limit is exceeded", %{conn: conn} do
1747 user = insert(:user)
1748
1749 today =
1750 NaiveDateTime.utc_now()
1751 |> NaiveDateTime.add(:timer.minutes(6), :millisecond)
1752 |> NaiveDateTime.to_iso8601()
1753
1754 attrs = %{params: %{}, scheduled_at: today}
1755 {:ok, _} = ScheduledActivity.create(user, attrs)
1756 {:ok, _} = ScheduledActivity.create(user, attrs)
1757
1758 conn =
1759 conn
1760 |> assign(:user, user)
1761 |> post("/api/v1/statuses", %{"status" => "scheduled", "scheduled_at" => today})
1762
1763 assert %{"error" => "daily limit exceeded"} == json_response(conn, 422)
1764 end
1765
1766 test "returns error when total user limit is exceeded", %{conn: conn} do
1767 user = insert(:user)
1768
1769 today =
1770 NaiveDateTime.utc_now()
1771 |> NaiveDateTime.add(:timer.minutes(6), :millisecond)
1772 |> NaiveDateTime.to_iso8601()
1773
1774 tomorrow =
1775 NaiveDateTime.utc_now()
1776 |> NaiveDateTime.add(:timer.hours(36), :millisecond)
1777 |> NaiveDateTime.to_iso8601()
1778
1779 attrs = %{params: %{}, scheduled_at: today}
1780 {:ok, _} = ScheduledActivity.create(user, attrs)
1781 {:ok, _} = ScheduledActivity.create(user, attrs)
1782 {:ok, _} = ScheduledActivity.create(user, %{params: %{}, scheduled_at: tomorrow})
1783
1784 conn =
1785 conn
1786 |> assign(:user, user)
1787 |> post("/api/v1/statuses", %{"status" => "scheduled", "scheduled_at" => tomorrow})
1788
1789 assert %{"error" => "total limit exceeded"} == json_response(conn, 422)
1790 end
1791
1792 test "shows scheduled activities", %{conn: conn} do
1793 user = insert(:user)
1794 scheduled_activity_id1 = insert(:scheduled_activity, user: user).id |> to_string()
1795 scheduled_activity_id2 = insert(:scheduled_activity, user: user).id |> to_string()
1796 scheduled_activity_id3 = insert(:scheduled_activity, user: user).id |> to_string()
1797 scheduled_activity_id4 = insert(:scheduled_activity, user: user).id |> to_string()
1798
1799 conn =
1800 conn
1801 |> assign(:user, user)
1802
1803 # min_id
1804 conn_res =
1805 conn
1806 |> get("/api/v1/scheduled_statuses?limit=2&min_id=#{scheduled_activity_id1}")
1807
1808 result = json_response(conn_res, 200)
1809 assert [%{"id" => ^scheduled_activity_id3}, %{"id" => ^scheduled_activity_id2}] = result
1810
1811 # since_id
1812 conn_res =
1813 conn
1814 |> get("/api/v1/scheduled_statuses?limit=2&since_id=#{scheduled_activity_id1}")
1815
1816 result = json_response(conn_res, 200)
1817 assert [%{"id" => ^scheduled_activity_id4}, %{"id" => ^scheduled_activity_id3}] = result
1818
1819 # max_id
1820 conn_res =
1821 conn
1822 |> get("/api/v1/scheduled_statuses?limit=2&max_id=#{scheduled_activity_id4}")
1823
1824 result = json_response(conn_res, 200)
1825 assert [%{"id" => ^scheduled_activity_id3}, %{"id" => ^scheduled_activity_id2}] = result
1826 end
1827
1828 test "shows a scheduled activity", %{conn: conn} do
1829 user = insert(:user)
1830 scheduled_activity = insert(:scheduled_activity, user: user)
1831
1832 res_conn =
1833 conn
1834 |> assign(:user, user)
1835 |> get("/api/v1/scheduled_statuses/#{scheduled_activity.id}")
1836
1837 assert %{"id" => scheduled_activity_id} = json_response(res_conn, 200)
1838 assert scheduled_activity_id == scheduled_activity.id |> to_string()
1839
1840 res_conn =
1841 conn
1842 |> assign(:user, user)
1843 |> get("/api/v1/scheduled_statuses/404")
1844
1845 assert %{"error" => "Record not found"} = json_response(res_conn, 404)
1846 end
1847
1848 test "updates a scheduled activity", %{conn: conn} do
1849 user = insert(:user)
1850 scheduled_activity = insert(:scheduled_activity, user: user)
1851
1852 new_scheduled_at =
1853 NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond)
1854
1855 res_conn =
1856 conn
1857 |> assign(:user, user)
1858 |> put("/api/v1/scheduled_statuses/#{scheduled_activity.id}", %{
1859 scheduled_at: new_scheduled_at
1860 })
1861
1862 assert %{"scheduled_at" => expected_scheduled_at} = json_response(res_conn, 200)
1863 assert expected_scheduled_at == Pleroma.Web.CommonAPI.Utils.to_masto_date(new_scheduled_at)
1864
1865 res_conn =
1866 conn
1867 |> assign(:user, user)
1868 |> put("/api/v1/scheduled_statuses/404", %{scheduled_at: new_scheduled_at})
1869
1870 assert %{"error" => "Record not found"} = json_response(res_conn, 404)
1871 end
1872
1873 test "deletes a scheduled activity", %{conn: conn} do
1874 user = insert(:user)
1875 scheduled_activity = insert(:scheduled_activity, user: user)
1876
1877 res_conn =
1878 conn
1879 |> assign(:user, user)
1880 |> delete("/api/v1/scheduled_statuses/#{scheduled_activity.id}")
1881
1882 assert %{} = json_response(res_conn, 200)
1883 assert nil == Repo.get(ScheduledActivity, scheduled_activity.id)
1884
1885 res_conn =
1886 conn
1887 |> assign(:user, user)
1888 |> delete("/api/v1/scheduled_statuses/#{scheduled_activity.id}")
1889
1890 assert %{"error" => "Record not found"} = json_response(res_conn, 404)
1891 end
1892 end
1893
1894 describe "create account by app" do
1895 test "Account registration via Application", %{conn: conn} do
1896 conn =
1897 conn
1898 |> post("/api/v1/apps", %{
1899 client_name: "client_name",
1900 redirect_uris: "urn:ietf:wg:oauth:2.0:oob",
1901 scopes: "read, write, follow"
1902 })
1903
1904 %{
1905 "client_id" => client_id,
1906 "client_secret" => client_secret,
1907 "id" => _,
1908 "name" => "client_name",
1909 "redirect_uri" => "urn:ietf:wg:oauth:2.0:oob",
1910 "vapid_key" => _,
1911 "website" => nil
1912 } = json_response(conn, 200)
1913
1914 conn =
1915 conn
1916 |> post("/oauth/token", %{
1917 grant_type: "client_credentials",
1918 client_id: client_id,
1919 client_secret: client_secret
1920 })
1921
1922 assert %{"access_token" => token, "refresh_token" => refresh, "scope" => scope} =
1923 json_response(conn, 200)
1924
1925 assert token
1926 token_from_db = Repo.get_by(Token, token: token)
1927 assert token_from_db
1928 assert refresh
1929 assert scope == "read write follow"
1930
1931 conn =
1932 build_conn()
1933 |> put_req_header("authorization", "Bearer " <> token)
1934 |> post("/api/v1/accounts", %{
1935 username: "lain",
1936 email: "lain@example.org",
1937 password: "PlzDontHackLain",
1938 agreement: true
1939 })
1940
1941 %{
1942 "access_token" => token,
1943 "created_at" => _created_at,
1944 "scope" => _scope,
1945 "token_type" => "Bearer"
1946 } = json_response(conn, 200)
1947
1948 token_from_db = Repo.get_by(Token, token: token)
1949 assert token_from_db
1950 token_from_db = Repo.preload(token_from_db, :user)
1951 assert token_from_db.user
1952
1953 assert token_from_db.user.info.confirmation_pending
1954 end
1955
1956 test "rate limit", %{conn: conn} do
1957 app_token = insert(:oauth_token, user: nil)
1958
1959 conn =
1960 put_req_header(conn, "authorization", "Bearer " <> app_token.token)
1961 |> Map.put(:remote_ip, {15, 15, 15, 15})
1962
1963 for i <- 1..5 do
1964 conn =
1965 conn
1966 |> post("/api/v1/accounts", %{
1967 username: "#{i}lain",
1968 email: "#{i}lain@example.org",
1969 password: "PlzDontHackLain",
1970 agreement: true
1971 })
1972
1973 %{
1974 "access_token" => token,
1975 "created_at" => _created_at,
1976 "scope" => _scope,
1977 "token_type" => "Bearer"
1978 } = json_response(conn, 200)
1979
1980 token_from_db = Repo.get_by(Token, token: token)
1981 assert token_from_db
1982 token_from_db = Repo.preload(token_from_db, :user)
1983 assert token_from_db.user
1984
1985 assert token_from_db.user.info.confirmation_pending
1986 end
1987
1988 conn =
1989 conn
1990 |> post("/api/v1/accounts", %{
1991 username: "6lain",
1992 email: "6lain@example.org",
1993 password: "PlzDontHackLain",
1994 agreement: true
1995 })
1996
1997 assert json_response(conn, :too_many_requests) == %{"error" => "Throttled"}
1998 end
1999 end
2000
2001 describe "GET /api/v1/polls/:id" do
2002 test "returns poll entity for object id", %{conn: conn} do
2003 user = insert(:user)
2004
2005 {:ok, activity} =
2006 CommonAPI.post(user, %{
2007 "status" => "Pleroma does",
2008 "poll" => %{"options" => ["what Mastodon't", "n't what Mastodoes"], "expires_in" => 20}
2009 })
2010
2011 object = Object.normalize(activity)
2012
2013 conn =
2014 conn
2015 |> assign(:user, user)
2016 |> get("/api/v1/polls/#{object.id}")
2017
2018 response = json_response(conn, 200)
2019 id = to_string(object.id)
2020 assert %{"id" => ^id, "expired" => false, "multiple" => false} = response
2021 end
2022
2023 test "does not expose polls for private statuses", %{conn: conn} do
2024 user = insert(:user)
2025 other_user = insert(:user)
2026
2027 {:ok, activity} =
2028 CommonAPI.post(user, %{
2029 "status" => "Pleroma does",
2030 "poll" => %{"options" => ["what Mastodon't", "n't what Mastodoes"], "expires_in" => 20},
2031 "visibility" => "private"
2032 })
2033
2034 object = Object.normalize(activity)
2035
2036 conn =
2037 conn
2038 |> assign(:user, other_user)
2039 |> get("/api/v1/polls/#{object.id}")
2040
2041 assert json_response(conn, 404)
2042 end
2043 end
2044
2045 describe "POST /api/v1/polls/:id/votes" do
2046 test "votes are added to the poll", %{conn: conn} do
2047 user = insert(:user)
2048 other_user = insert(:user)
2049
2050 {:ok, activity} =
2051 CommonAPI.post(user, %{
2052 "status" => "A very delicious sandwich",
2053 "poll" => %{
2054 "options" => ["Lettuce", "Grilled Bacon", "Tomato"],
2055 "expires_in" => 20,
2056 "multiple" => true
2057 }
2058 })
2059
2060 object = Object.normalize(activity)
2061
2062 conn =
2063 conn
2064 |> assign(:user, other_user)
2065 |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [0, 1, 2]})
2066
2067 assert json_response(conn, 200)
2068 object = Object.get_by_id(object.id)
2069
2070 assert Enum.all?(object.data["anyOf"], fn %{"replies" => %{"totalItems" => total_items}} ->
2071 total_items == 1
2072 end)
2073 end
2074
2075 test "author can't vote", %{conn: conn} do
2076 user = insert(:user)
2077
2078 {:ok, activity} =
2079 CommonAPI.post(user, %{
2080 "status" => "Am I cute?",
2081 "poll" => %{"options" => ["Yes", "No"], "expires_in" => 20}
2082 })
2083
2084 object = Object.normalize(activity)
2085
2086 assert conn
2087 |> assign(:user, user)
2088 |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [1]})
2089 |> json_response(422) == %{"error" => "Poll's author can't vote"}
2090
2091 object = Object.get_by_id(object.id)
2092
2093 refute Enum.at(object.data["oneOf"], 1)["replies"]["totalItems"] == 1
2094 end
2095
2096 test "does not allow multiple choices on a single-choice question", %{conn: conn} do
2097 user = insert(:user)
2098 other_user = insert(:user)
2099
2100 {:ok, activity} =
2101 CommonAPI.post(user, %{
2102 "status" => "The glass is",
2103 "poll" => %{"options" => ["half empty", "half full"], "expires_in" => 20}
2104 })
2105
2106 object = Object.normalize(activity)
2107
2108 assert conn
2109 |> assign(:user, other_user)
2110 |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [0, 1]})
2111 |> json_response(422) == %{"error" => "Too many choices"}
2112
2113 object = Object.get_by_id(object.id)
2114
2115 refute Enum.any?(object.data["oneOf"], fn %{"replies" => %{"totalItems" => total_items}} ->
2116 total_items == 1
2117 end)
2118 end
2119
2120 test "does not allow choice index to be greater than options count", %{conn: conn} do
2121 user = insert(:user)
2122 other_user = insert(:user)
2123
2124 {:ok, activity} =
2125 CommonAPI.post(user, %{
2126 "status" => "Am I cute?",
2127 "poll" => %{"options" => ["Yes", "No"], "expires_in" => 20}
2128 })
2129
2130 object = Object.normalize(activity)
2131
2132 conn =
2133 conn
2134 |> assign(:user, other_user)
2135 |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [2]})
2136
2137 assert json_response(conn, 422) == %{"error" => "Invalid indices"}
2138 end
2139
2140 test "returns 404 error when object is not exist", %{conn: conn} do
2141 user = insert(:user)
2142
2143 conn =
2144 conn
2145 |> assign(:user, user)
2146 |> post("/api/v1/polls/1/votes", %{"choices" => [0]})
2147
2148 assert json_response(conn, 404) == %{"error" => "Record not found"}
2149 end
2150
2151 test "returns 404 when poll is private and not available for user", %{conn: conn} do
2152 user = insert(:user)
2153 other_user = insert(:user)
2154
2155 {:ok, activity} =
2156 CommonAPI.post(user, %{
2157 "status" => "Am I cute?",
2158 "poll" => %{"options" => ["Yes", "No"], "expires_in" => 20},
2159 "visibility" => "private"
2160 })
2161
2162 object = Object.normalize(activity)
2163
2164 conn =
2165 conn
2166 |> assign(:user, other_user)
2167 |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [0]})
2168
2169 assert json_response(conn, 404) == %{"error" => "Record not found"}
2170 end
2171 end
2172
2173 describe "POST /auth/password, with valid parameters" do
2174 setup %{conn: conn} do
2175 user = insert(:user)
2176 conn = post(conn, "/auth/password?email=#{user.email}")
2177 %{conn: conn, user: user}
2178 end
2179
2180 test "it returns 204", %{conn: conn} do
2181 assert json_response(conn, :no_content)
2182 end
2183
2184 test "it creates a PasswordResetToken record for user", %{user: user} do
2185 token_record = Repo.get_by(Pleroma.PasswordResetToken, user_id: user.id)
2186 assert token_record
2187 end
2188
2189 test "it sends an email to user", %{user: user} do
2190 ObanHelpers.perform_all()
2191 token_record = Repo.get_by(Pleroma.PasswordResetToken, user_id: user.id)
2192
2193 email = Pleroma.Emails.UserEmail.password_reset_email(user, token_record.token)
2194 notify_email = Config.get([:instance, :notify_email])
2195 instance_name = Config.get([:instance, :name])
2196
2197 assert_email_sent(
2198 from: {instance_name, notify_email},
2199 to: {user.name, user.email},
2200 html_body: email.html_body
2201 )
2202 end
2203 end
2204
2205 describe "POST /auth/password, with invalid parameters" do
2206 setup do
2207 user = insert(:user)
2208 {:ok, user: user}
2209 end
2210
2211 test "it returns 404 when user is not found", %{conn: conn, user: user} do
2212 conn = post(conn, "/auth/password?email=nonexisting_#{user.email}")
2213 assert conn.status == 404
2214 assert conn.resp_body == ""
2215 end
2216
2217 test "it returns 400 when user is not local", %{conn: conn, user: user} do
2218 {:ok, user} = Repo.update(Changeset.change(user, local: false))
2219 conn = post(conn, "/auth/password?email=#{user.email}")
2220 assert conn.status == 400
2221 assert conn.resp_body == ""
2222 end
2223 end
2224
2225 describe "POST /api/v1/pleroma/accounts/confirmation_resend" do
2226 setup do
2227 {:ok, user} =
2228 insert(:user)
2229 |> User.change_info(&User.Info.confirmation_changeset(&1, need_confirmation: true))
2230 |> Repo.update()
2231
2232 assert user.info.confirmation_pending
2233
2234 [user: user]
2235 end
2236
2237 clear_config([:instance, :account_activation_required]) do
2238 Config.put([:instance, :account_activation_required], true)
2239 end
2240
2241 test "resend account confirmation email", %{conn: conn, user: user} do
2242 conn
2243 |> assign(:user, user)
2244 |> post("/api/v1/pleroma/accounts/confirmation_resend?email=#{user.email}")
2245 |> json_response(:no_content)
2246
2247 ObanHelpers.perform_all()
2248
2249 email = Pleroma.Emails.UserEmail.account_confirmation_email(user)
2250 notify_email = Config.get([:instance, :notify_email])
2251 instance_name = Config.get([:instance, :name])
2252
2253 assert_email_sent(
2254 from: {instance_name, notify_email},
2255 to: {user.name, user.email},
2256 html_body: email.html_body
2257 )
2258 end
2259 end
2260
2261 describe "GET /api/v1/suggestions" do
2262 setup do
2263 user = insert(:user)
2264 other_user = insert(:user)
2265 host = Config.get([Pleroma.Web.Endpoint, :url, :host])
2266 url500 = "http://test500?#{host}&#{user.nickname}"
2267 url200 = "http://test200?#{host}&#{user.nickname}"
2268
2269 mock(fn
2270 %{method: :get, url: ^url500} ->
2271 %Tesla.Env{status: 500, body: "bad request"}
2272
2273 %{method: :get, url: ^url200} ->
2274 %Tesla.Env{
2275 status: 200,
2276 body:
2277 ~s([{"acct":"yj455","avatar":"https://social.heldscal.la/avatar/201.jpeg","avatar_static":"https://social.heldscal.la/avatar/s/201.jpeg"}, {"acct":"#{
2278 other_user.ap_id
2279 }","avatar":"https://social.heldscal.la/avatar/202.jpeg","avatar_static":"https://social.heldscal.la/avatar/s/202.jpeg"}])
2280 }
2281 end)
2282
2283 [user: user, other_user: other_user]
2284 end
2285
2286 clear_config(:suggestions)
2287
2288 test "returns empty result when suggestions disabled", %{conn: conn, user: user} do
2289 Config.put([:suggestions, :enabled], false)
2290
2291 res =
2292 conn
2293 |> assign(:user, user)
2294 |> get("/api/v1/suggestions")
2295 |> json_response(200)
2296
2297 assert res == []
2298 end
2299
2300 test "returns error", %{conn: conn, user: user} do
2301 Config.put([:suggestions, :enabled], true)
2302 Config.put([:suggestions, :third_party_engine], "http://test500?{{host}}&{{user}}")
2303
2304 assert capture_log(fn ->
2305 res =
2306 conn
2307 |> assign(:user, user)
2308 |> get("/api/v1/suggestions")
2309 |> json_response(500)
2310
2311 assert res == "Something went wrong"
2312 end) =~ "Could not retrieve suggestions"
2313 end
2314
2315 test "returns suggestions", %{conn: conn, user: user, other_user: other_user} do
2316 Config.put([:suggestions, :enabled], true)
2317 Config.put([:suggestions, :third_party_engine], "http://test200?{{host}}&{{user}}")
2318
2319 res =
2320 conn
2321 |> assign(:user, user)
2322 |> get("/api/v1/suggestions")
2323 |> json_response(200)
2324
2325 assert res == [
2326 %{
2327 "acct" => "yj455",
2328 "avatar" => "https://social.heldscal.la/avatar/201.jpeg",
2329 "avatar_static" => "https://social.heldscal.la/avatar/s/201.jpeg",
2330 "id" => 0
2331 },
2332 %{
2333 "acct" => other_user.ap_id,
2334 "avatar" => "https://social.heldscal.la/avatar/202.jpeg",
2335 "avatar_static" => "https://social.heldscal.la/avatar/s/202.jpeg",
2336 "id" => other_user.id
2337 }
2338 ]
2339 end
2340 end
2341 end