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