total rebase
[anni] / test / pleroma / web / mastodon_api / controllers / account_controller_test.exs
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
5 defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
6   use Pleroma.Web.ConnCase
7
8   alias Pleroma.Object
9   alias Pleroma.Repo
10   alias Pleroma.Tests.ObanHelpers
11   alias Pleroma.User
12   alias Pleroma.UserRelationship
13   alias Pleroma.Web.ActivityPub.ActivityPub
14   alias Pleroma.Web.ActivityPub.InternalFetchActor
15   alias Pleroma.Web.CommonAPI
16   alias Pleroma.Web.OAuth.Token
17   alias Pleroma.Web.Plugs.SetLocalePlug
18
19   import Pleroma.Factory
20
21   setup do
22     Mox.stub_with(Pleroma.UnstubbedConfigMock, Pleroma.Config)
23     :ok
24   end
25
26   describe "account fetching" do
27     test "works by id" do
28       %User{id: user_id} = insert(:user)
29
30       assert %{"id" => ^user_id} =
31                build_conn()
32                |> get("/api/v1/accounts/#{user_id}")
33                |> json_response_and_validate_schema(200)
34
35       assert %{"error" => "Can't find user"} =
36                build_conn()
37                |> get("/api/v1/accounts/-1")
38                |> json_response_and_validate_schema(404)
39     end
40
41     test "relationship field" do
42       %{conn: conn, user: user} = oauth_access(["read"])
43
44       other_user = insert(:user)
45
46       response =
47         conn
48         |> get("/api/v1/accounts/#{other_user.id}")
49         |> json_response_and_validate_schema(200)
50
51       assert response["id"] == other_user.id
52       assert response["pleroma"]["relationship"] == %{}
53
54       assert %{"pleroma" => %{"relationship" => %{"following" => false, "followed_by" => false}}} =
55                conn
56                |> get("/api/v1/accounts/#{other_user.id}?with_relationships=true")
57                |> json_response_and_validate_schema(200)
58
59       {:ok, _, %{id: other_id}} = User.follow(user, other_user)
60
61       assert %{
62                "id" => ^other_id,
63                "pleroma" => %{"relationship" => %{"following" => true, "followed_by" => false}}
64              } =
65                conn
66                |> get("/api/v1/accounts/#{other_id}?with_relationships=true")
67                |> json_response_and_validate_schema(200)
68
69       {:ok, _, _} = User.follow(other_user, user)
70
71       assert %{
72                "id" => ^other_id,
73                "pleroma" => %{"relationship" => %{"following" => true, "followed_by" => true}}
74              } =
75                conn
76                |> get("/api/v1/accounts/#{other_id}?with_relationships=true")
77                |> json_response_and_validate_schema(200)
78     end
79
80     test "works by nickname" do
81       user = insert(:user)
82
83       assert %{"id" => _user_id} =
84                build_conn()
85                |> get("/api/v1/accounts/#{user.nickname}")
86                |> json_response_and_validate_schema(200)
87     end
88
89     test "works by nickname for remote users" do
90       clear_config([:instance, :limit_to_local_content], false)
91
92       user = insert(:user, nickname: "user@example.com", local: false)
93
94       assert %{"id" => _user_id} =
95                build_conn()
96                |> get("/api/v1/accounts/#{user.nickname}")
97                |> json_response_and_validate_schema(200)
98     end
99
100     test "respects limit_to_local_content == :all for remote user nicknames" do
101       clear_config([:instance, :limit_to_local_content], :all)
102
103       user = insert(:user, nickname: "user@example.com", local: false)
104
105       assert build_conn()
106              |> get("/api/v1/accounts/#{user.nickname}")
107              |> json_response_and_validate_schema(404)
108     end
109
110     test "respects limit_to_local_content == :unauthenticated for remote user nicknames" do
111       clear_config([:instance, :limit_to_local_content], :unauthenticated)
112
113       user = insert(:user, nickname: "user@example.com", local: false)
114       reading_user = insert(:user)
115
116       conn =
117         build_conn()
118         |> get("/api/v1/accounts/#{user.nickname}")
119
120       assert json_response_and_validate_schema(conn, 404)
121
122       conn =
123         build_conn()
124         |> assign(:user, reading_user)
125         |> assign(:token, insert(:oauth_token, user: reading_user, scopes: ["read:accounts"]))
126         |> get("/api/v1/accounts/#{user.nickname}")
127
128       assert %{"id" => id} = json_response_and_validate_schema(conn, 200)
129       assert id == user.id
130     end
131
132     test "accounts fetches correct account for nicknames beginning with numbers", %{conn: conn} do
133       # Need to set an old-style integer ID to reproduce the problem
134       # (these are no longer assigned to new accounts but were preserved
135       # for existing accounts during the migration to flakeIDs)
136       user_one = insert(:user, %{id: 1212})
137       user_two = insert(:user, %{nickname: "#{user_one.id}garbage"})
138
139       acc_one =
140         conn
141         |> get("/api/v1/accounts/#{user_one.id}")
142         |> json_response_and_validate_schema(:ok)
143
144       acc_two =
145         conn
146         |> get("/api/v1/accounts/#{user_two.nickname}")
147         |> json_response_and_validate_schema(:ok)
148
149       acc_three =
150         conn
151         |> get("/api/v1/accounts/#{user_two.id}")
152         |> json_response_and_validate_schema(:ok)
153
154       refute acc_one == acc_two
155       assert acc_two == acc_three
156     end
157
158     test "returns 404 when user is invisible", %{conn: conn} do
159       user = insert(:user, %{invisible: true})
160
161       assert %{"error" => "Can't find user"} =
162                conn
163                |> get("/api/v1/accounts/#{user.nickname}")
164                |> json_response_and_validate_schema(404)
165     end
166
167     test "returns 404 for internal.fetch actor", %{conn: conn} do
168       %User{nickname: "internal.fetch"} = InternalFetchActor.get_actor()
169
170       assert %{"error" => "Can't find user"} =
171                conn
172                |> get("/api/v1/accounts/internal.fetch")
173                |> json_response_and_validate_schema(404)
174     end
175
176     test "returns 404 for deactivated user", %{conn: conn} do
177       user = insert(:user, is_active: false)
178
179       assert %{"error" => "Can't find user"} =
180                conn
181                |> get("/api/v1/accounts/#{user.id}")
182                |> json_response_and_validate_schema(:not_found)
183     end
184   end
185
186   defp local_and_remote_users do
187     local = insert(:user)
188     remote = insert(:user, local: false)
189     {:ok, local: local, remote: remote}
190   end
191
192   describe "user fetching with restrict unauthenticated profiles for local and remote" do
193     setup do: local_and_remote_users()
194
195     setup do: clear_config([:restrict_unauthenticated, :profiles, :local], true)
196
197     setup do: clear_config([:restrict_unauthenticated, :profiles, :remote], true)
198
199     test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do
200       assert %{"error" => "This API requires an authenticated user"} ==
201                conn
202                |> get("/api/v1/accounts/#{local.id}")
203                |> json_response_and_validate_schema(:unauthorized)
204
205       assert %{"error" => "This API requires an authenticated user"} ==
206                conn
207                |> get("/api/v1/accounts/#{remote.id}")
208                |> json_response_and_validate_schema(:unauthorized)
209     end
210
211     test "if user is authenticated", %{local: local, remote: remote} do
212       %{conn: conn} = oauth_access(["read"])
213
214       res_conn = get(conn, "/api/v1/accounts/#{local.id}")
215       assert %{"id" => _} = json_response_and_validate_schema(res_conn, 200)
216
217       res_conn = get(conn, "/api/v1/accounts/#{remote.id}")
218       assert %{"id" => _} = json_response_and_validate_schema(res_conn, 200)
219     end
220   end
221
222   describe "user fetching with restrict unauthenticated profiles for local" do
223     setup do: local_and_remote_users()
224
225     setup do: clear_config([:restrict_unauthenticated, :profiles, :local], true)
226
227     test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do
228       res_conn = get(conn, "/api/v1/accounts/#{local.id}")
229
230       assert json_response_and_validate_schema(res_conn, :unauthorized) == %{
231                "error" => "This API requires an authenticated user"
232              }
233
234       res_conn = get(conn, "/api/v1/accounts/#{remote.id}")
235       assert %{"id" => _} = json_response_and_validate_schema(res_conn, 200)
236     end
237
238     test "if user is authenticated", %{local: local, remote: remote} do
239       %{conn: conn} = oauth_access(["read"])
240
241       res_conn = get(conn, "/api/v1/accounts/#{local.id}")
242       assert %{"id" => _} = json_response_and_validate_schema(res_conn, 200)
243
244       res_conn = get(conn, "/api/v1/accounts/#{remote.id}")
245       assert %{"id" => _} = json_response_and_validate_schema(res_conn, 200)
246     end
247   end
248
249   describe "user fetching with restrict unauthenticated profiles for remote" do
250     setup do: local_and_remote_users()
251
252     setup do: clear_config([:restrict_unauthenticated, :profiles, :remote], true)
253
254     test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do
255       res_conn = get(conn, "/api/v1/accounts/#{local.id}")
256       assert %{"id" => _} = json_response_and_validate_schema(res_conn, 200)
257
258       res_conn = get(conn, "/api/v1/accounts/#{remote.id}")
259
260       assert json_response_and_validate_schema(res_conn, :unauthorized) == %{
261                "error" => "This API requires an authenticated user"
262              }
263     end
264
265     test "if user is authenticated", %{local: local, remote: remote} do
266       %{conn: conn} = oauth_access(["read"])
267
268       res_conn = get(conn, "/api/v1/accounts/#{local.id}")
269       assert %{"id" => _} = json_response_and_validate_schema(res_conn, 200)
270
271       res_conn = get(conn, "/api/v1/accounts/#{remote.id}")
272       assert %{"id" => _} = json_response_and_validate_schema(res_conn, 200)
273     end
274   end
275
276   describe "user timelines" do
277     setup do: oauth_access(["read:statuses"])
278
279     test "works with announces that are just addressed to public", %{conn: conn} do
280       user = insert(:user, ap_id: "https://honktest/u/test", local: false)
281       other_user = insert(:user)
282
283       {:ok, post} = CommonAPI.post(other_user, %{status: "bonkeronk"})
284
285       {:ok, announce, _} =
286         %{
287           "@context" => "https://www.w3.org/ns/activitystreams",
288           "actor" => "https://honktest/u/test",
289           "id" => "https://honktest/u/test/bonk/1793M7B9MQ48847vdx",
290           "object" => post.data["object"],
291           "published" => "2019-06-25T19:33:58Z",
292           "to" => ["https://www.w3.org/ns/activitystreams#Public"],
293           "type" => "Announce"
294         }
295         |> ActivityPub.persist(local: false)
296
297       assert resp =
298                conn
299                |> get("/api/v1/accounts/#{user.id}/statuses")
300                |> json_response_and_validate_schema(200)
301
302       assert [%{"id" => id}] = resp
303       assert id == announce.id
304     end
305
306     test "deactivated user", %{conn: conn} do
307       user = insert(:user, is_active: false)
308
309       assert %{"error" => "Can't find user"} ==
310                conn
311                |> get("/api/v1/accounts/#{user.id}/statuses")
312                |> json_response_and_validate_schema(:not_found)
313     end
314
315     test "returns 404 when user is invisible", %{conn: conn} do
316       user = insert(:user, %{invisible: true})
317
318       assert %{"error" => "Can't find user"} =
319                conn
320                |> get("/api/v1/accounts/#{user.id}")
321                |> json_response_and_validate_schema(404)
322     end
323
324     test "respects blocks", %{user: user_one, conn: conn} do
325       user_two = insert(:user)
326       user_three = insert(:user)
327
328       User.block(user_one, user_two)
329
330       {:ok, activity} = CommonAPI.post(user_two, %{status: "User one sux0rz"})
331       {:ok, repeat} = CommonAPI.repeat(activity.id, user_three)
332
333       assert resp =
334                conn
335                |> get("/api/v1/accounts/#{user_two.id}/statuses")
336                |> json_response_and_validate_schema(200)
337
338       assert [%{"id" => id}] = resp
339       assert id == activity.id
340
341       # Even a blocked user will deliver the full user timeline, there would be
342       #   no point in looking at a blocked users timeline otherwise
343       assert resp =
344                conn
345                |> get("/api/v1/accounts/#{user_two.id}/statuses")
346                |> json_response_and_validate_schema(200)
347
348       assert [%{"id" => id}] = resp
349       assert id == activity.id
350
351       # Third user's timeline includes the repeat when viewed by unauthenticated user
352       resp =
353         build_conn()
354         |> get("/api/v1/accounts/#{user_three.id}/statuses")
355         |> json_response_and_validate_schema(200)
356
357       assert [%{"id" => id}] = resp
358       assert id == repeat.id
359
360       # When viewing a third user's timeline, the blocked users' statuses will NOT be shown
361       resp = get(conn, "/api/v1/accounts/#{user_three.id}/statuses")
362
363       assert [] == json_response_and_validate_schema(resp, 200)
364     end
365
366     test "gets users statuses", %{conn: conn} do
367       user_one = insert(:user)
368       user_two = insert(:user)
369       user_three = insert(:user)
370
371       {:ok, _user_three, _user_one} = User.follow(user_three, user_one)
372
373       {:ok, activity} = CommonAPI.post(user_one, %{status: "HI!!!"})
374
375       {:ok, direct_activity} =
376         CommonAPI.post(user_one, %{
377           status: "Hi, @#{user_two.nickname}.",
378           visibility: "direct"
379         })
380
381       {:ok, private_activity} =
382         CommonAPI.post(user_one, %{status: "private", visibility: "private"})
383
384       # TODO!!!
385       resp =
386         conn
387         |> get("/api/v1/accounts/#{user_one.id}/statuses")
388         |> json_response_and_validate_schema(200)
389
390       assert [%{"id" => id}] = resp
391       assert id == to_string(activity.id)
392
393       resp =
394         conn
395         |> assign(:user, user_two)
396         |> assign(:token, insert(:oauth_token, user: user_two, scopes: ["read:statuses"]))
397         |> get("/api/v1/accounts/#{user_one.id}/statuses")
398         |> json_response_and_validate_schema(200)
399
400       assert [%{"id" => id_one}, %{"id" => id_two}] = resp
401       assert id_one == to_string(direct_activity.id)
402       assert id_two == to_string(activity.id)
403
404       resp =
405         conn
406         |> assign(:user, user_three)
407         |> assign(:token, insert(:oauth_token, user: user_three, scopes: ["read:statuses"]))
408         |> get("/api/v1/accounts/#{user_one.id}/statuses")
409         |> json_response_and_validate_schema(200)
410
411       assert [%{"id" => id_one}, %{"id" => id_two}] = resp
412       assert id_one == to_string(private_activity.id)
413       assert id_two == to_string(activity.id)
414     end
415
416     test "gets local-only statuses for authenticated users", %{user: _user, conn: conn} do
417       user_one = insert(:user)
418
419       {:ok, activity} = CommonAPI.post(user_one, %{status: "HI!!!", visibility: "local"})
420
421       resp =
422         conn
423         |> get("/api/v1/accounts/#{user_one.id}/statuses")
424         |> json_response_and_validate_schema(200)
425
426       assert [%{"id" => id}] = resp
427       assert id == to_string(activity.id)
428     end
429
430     test "gets an users media, excludes reblogs", %{conn: conn} do
431       note = insert(:note_activity)
432       user = User.get_cached_by_ap_id(note.data["actor"])
433       other_user = insert(:user)
434
435       file = %Plug.Upload{
436         content_type: "image/jpeg",
437         path: Path.absname("test/fixtures/image.jpg"),
438         filename: "an_image.jpg"
439       }
440
441       {:ok, %{id: media_id}} = ActivityPub.upload(file, actor: user.ap_id)
442
443       {:ok, %{id: image_post_id}} = CommonAPI.post(user, %{status: "cofe", media_ids: [media_id]})
444
445       {:ok, %{id: media_id}} = ActivityPub.upload(file, actor: other_user.ap_id)
446
447       {:ok, %{id: other_image_post_id}} =
448         CommonAPI.post(other_user, %{status: "cofe2", media_ids: [media_id]})
449
450       {:ok, _announce} = CommonAPI.repeat(other_image_post_id, user)
451
452       conn = get(conn, "/api/v1/accounts/#{user.id}/statuses?only_media=true")
453
454       assert [%{"id" => ^image_post_id}] = json_response_and_validate_schema(conn, 200)
455
456       conn = get(build_conn(), "/api/v1/accounts/#{user.id}/statuses?only_media=1")
457
458       assert [%{"id" => ^image_post_id}] = json_response_and_validate_schema(conn, 200)
459     end
460
461     test "gets a user's statuses without reblogs", %{user: user, conn: conn} do
462       {:ok, %{id: post_id}} = CommonAPI.post(user, %{status: "HI!!!"})
463       {:ok, _} = CommonAPI.repeat(post_id, user)
464
465       conn = get(conn, "/api/v1/accounts/#{user.id}/statuses?exclude_reblogs=true")
466       assert [%{"id" => ^post_id}] = json_response_and_validate_schema(conn, 200)
467
468       conn = get(conn, "/api/v1/accounts/#{user.id}/statuses?exclude_reblogs=1")
469       assert [%{"id" => ^post_id}] = json_response_and_validate_schema(conn, 200)
470     end
471
472     test "filters user's statuses by a hashtag", %{user: user, conn: conn} do
473       {:ok, %{id: post_id}} = CommonAPI.post(user, %{status: "#hashtag"})
474       {:ok, _post} = CommonAPI.post(user, %{status: "hashtag"})
475
476       conn = get(conn, "/api/v1/accounts/#{user.id}/statuses?tagged=hashtag")
477       assert [%{"id" => ^post_id}] = json_response_and_validate_schema(conn, 200)
478     end
479
480     test "the user views their own timelines and excludes direct messages", %{
481       user: user,
482       conn: conn
483     } do
484       {:ok, %{id: public_activity_id}} =
485         CommonAPI.post(user, %{status: ".", visibility: "public"})
486
487       {:ok, _direct_activity} = CommonAPI.post(user, %{status: ".", visibility: "direct"})
488
489       conn = get(conn, "/api/v1/accounts/#{user.id}/statuses?exclude_visibilities[]=direct")
490       assert [%{"id" => ^public_activity_id}] = json_response_and_validate_schema(conn, 200)
491     end
492
493     test "muted reactions", %{user: user, conn: conn} do
494       user2 = insert(:user)
495       User.mute(user, user2)
496       {:ok, activity} = CommonAPI.post(user, %{status: "."})
497       {:ok, _} = CommonAPI.react_with_emoji(activity.id, user2, "🎅")
498
499       result =
500         conn
501         |> get("/api/v1/accounts/#{user.id}/statuses")
502         |> json_response_and_validate_schema(200)
503
504       assert [
505                %{
506                  "pleroma" => %{
507                    "emoji_reactions" => []
508                  }
509                }
510              ] = result
511
512       result =
513         conn
514         |> get("/api/v1/accounts/#{user.id}/statuses?with_muted=true")
515         |> json_response_and_validate_schema(200)
516
517       assert [
518                %{
519                  "pleroma" => %{
520                    "emoji_reactions" => [%{"count" => 1, "me" => false, "name" => "🎅"}]
521                  }
522                }
523              ] = result
524     end
525
526     test "paginates a user's statuses", %{user: user, conn: conn} do
527       {:ok, post_1} = CommonAPI.post(user, %{status: "first post"})
528       {:ok, post_2} = CommonAPI.post(user, %{status: "second post"})
529
530       response_1 = get(conn, "/api/v1/accounts/#{user.id}/statuses?limit=1")
531       assert [res] = json_response_and_validate_schema(response_1, 200)
532       assert res["id"] == post_2.id
533
534       response_2 = get(conn, "/api/v1/accounts/#{user.id}/statuses?limit=1&max_id=#{res["id"]}")
535       assert [res] = json_response_and_validate_schema(response_2, 200)
536       assert res["id"] == post_1.id
537
538       refute response_1 == response_2
539     end
540   end
541
542   defp local_and_remote_activities(%{local: local, remote: remote}) do
543     insert(:note_activity, user: local)
544     insert(:note_activity, user: remote, local: false)
545
546     :ok
547   end
548
549   describe "statuses with restrict unauthenticated profiles for local and remote" do
550     setup do: local_and_remote_users()
551     setup :local_and_remote_activities
552
553     setup do: clear_config([:restrict_unauthenticated, :profiles, :local], true)
554
555     setup do: clear_config([:restrict_unauthenticated, :profiles, :remote], true)
556
557     test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do
558       assert %{"error" => "This API requires an authenticated user"} ==
559                conn
560                |> get("/api/v1/accounts/#{local.id}/statuses")
561                |> json_response_and_validate_schema(:unauthorized)
562
563       assert %{"error" => "This API requires an authenticated user"} ==
564                conn
565                |> get("/api/v1/accounts/#{remote.id}/statuses")
566                |> json_response_and_validate_schema(:unauthorized)
567     end
568
569     test "if user is authenticated", %{local: local, remote: remote} do
570       %{conn: conn} = oauth_access(["read"])
571
572       res_conn = get(conn, "/api/v1/accounts/#{local.id}/statuses")
573       assert length(json_response_and_validate_schema(res_conn, 200)) == 1
574
575       res_conn = get(conn, "/api/v1/accounts/#{remote.id}/statuses")
576       assert length(json_response_and_validate_schema(res_conn, 200)) == 1
577     end
578   end
579
580   describe "statuses with restrict unauthenticated profiles for local" do
581     setup do: local_and_remote_users()
582     setup :local_and_remote_activities
583
584     setup do: clear_config([:restrict_unauthenticated, :profiles, :local], true)
585
586     test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do
587       assert %{"error" => "This API requires an authenticated user"} ==
588                conn
589                |> get("/api/v1/accounts/#{local.id}/statuses")
590                |> json_response_and_validate_schema(:unauthorized)
591
592       res_conn = get(conn, "/api/v1/accounts/#{remote.id}/statuses")
593       assert length(json_response_and_validate_schema(res_conn, 200)) == 1
594     end
595
596     test "if user is authenticated", %{local: local, remote: remote} do
597       %{conn: conn} = oauth_access(["read"])
598
599       res_conn = get(conn, "/api/v1/accounts/#{local.id}/statuses")
600       assert length(json_response_and_validate_schema(res_conn, 200)) == 1
601
602       res_conn = get(conn, "/api/v1/accounts/#{remote.id}/statuses")
603       assert length(json_response_and_validate_schema(res_conn, 200)) == 1
604     end
605   end
606
607   describe "statuses with restrict unauthenticated profiles for remote" do
608     setup do: local_and_remote_users()
609     setup :local_and_remote_activities
610
611     setup do: clear_config([:restrict_unauthenticated, :profiles, :remote], true)
612
613     test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do
614       res_conn = get(conn, "/api/v1/accounts/#{local.id}/statuses")
615       assert length(json_response_and_validate_schema(res_conn, 200)) == 1
616
617       assert %{"error" => "This API requires an authenticated user"} ==
618                conn
619                |> get("/api/v1/accounts/#{remote.id}/statuses")
620                |> json_response_and_validate_schema(:unauthorized)
621     end
622
623     test "if user is authenticated", %{local: local, remote: remote} do
624       %{conn: conn} = oauth_access(["read"])
625
626       res_conn = get(conn, "/api/v1/accounts/#{local.id}/statuses")
627       assert length(json_response_and_validate_schema(res_conn, 200)) == 1
628
629       res_conn = get(conn, "/api/v1/accounts/#{remote.id}/statuses")
630       assert length(json_response_and_validate_schema(res_conn, 200)) == 1
631     end
632   end
633
634   describe "followers" do
635     setup do: oauth_access(["read:accounts"])
636
637     test "getting followers", %{user: user, conn: conn} do
638       other_user = insert(:user)
639       {:ok, %{id: user_id}, other_user} = User.follow(user, other_user)
640
641       conn = get(conn, "/api/v1/accounts/#{other_user.id}/followers")
642
643       assert [%{"id" => ^user_id}] = json_response_and_validate_schema(conn, 200)
644     end
645
646     test "following with relationship", %{conn: conn, user: user} do
647       other_user = insert(:user)
648       {:ok, %{id: id}, _} = User.follow(other_user, user)
649
650       assert [
651                %{
652                  "id" => ^id,
653                  "pleroma" => %{
654                    "relationship" => %{
655                      "id" => ^id,
656                      "following" => false,
657                      "followed_by" => true
658                    }
659                  }
660                }
661              ] =
662                conn
663                |> get("/api/v1/accounts/#{user.id}/followers?with_relationships=true")
664                |> json_response_and_validate_schema(200)
665
666       {:ok, _, _} = User.follow(user, other_user)
667
668       assert [
669                %{
670                  "id" => ^id,
671                  "pleroma" => %{
672                    "relationship" => %{
673                      "id" => ^id,
674                      "following" => true,
675                      "followed_by" => true
676                    }
677                  }
678                }
679              ] =
680                conn
681                |> get("/api/v1/accounts/#{user.id}/followers?with_relationships=true")
682                |> json_response_and_validate_schema(200)
683     end
684
685     test "getting followers, hide_followers", %{user: user, conn: conn} do
686       other_user = insert(:user, hide_followers: true)
687       {:ok, _user, _other_user} = User.follow(user, other_user)
688
689       conn = get(conn, "/api/v1/accounts/#{other_user.id}/followers")
690
691       assert [] == json_response_and_validate_schema(conn, 200)
692     end
693
694     test "getting followers, hide_followers, same user requesting" do
695       user = insert(:user)
696       other_user = insert(:user, hide_followers: true)
697       {:ok, _user, _other_user} = User.follow(user, other_user)
698
699       conn =
700         build_conn()
701         |> assign(:user, other_user)
702         |> assign(:token, insert(:oauth_token, user: other_user, scopes: ["read:accounts"]))
703         |> get("/api/v1/accounts/#{other_user.id}/followers")
704
705       refute [] == json_response_and_validate_schema(conn, 200)
706     end
707
708     test "getting followers, pagination", %{user: user, conn: conn} do
709       {:ok, %User{id: follower1_id}, _user} = :user |> insert() |> User.follow(user)
710       {:ok, %User{id: follower2_id}, _user} = :user |> insert() |> User.follow(user)
711       {:ok, %User{id: follower3_id}, _user} = :user |> insert() |> User.follow(user)
712
713       assert [%{"id" => ^follower3_id}, %{"id" => ^follower2_id}] =
714                conn
715                |> get("/api/v1/accounts/#{user.id}/followers?since_id=#{follower1_id}")
716                |> json_response_and_validate_schema(200)
717
718       assert [%{"id" => ^follower2_id}, %{"id" => ^follower1_id}] =
719                conn
720                |> get("/api/v1/accounts/#{user.id}/followers?max_id=#{follower3_id}")
721                |> json_response_and_validate_schema(200)
722
723       assert [%{"id" => ^follower2_id}, %{"id" => ^follower1_id}] =
724                conn
725                |> get(
726                  "/api/v1/accounts/#{user.id}/followers?id=#{user.id}&limit=20&max_id=#{follower3_id}"
727                )
728                |> json_response_and_validate_schema(200)
729
730       res_conn = get(conn, "/api/v1/accounts/#{user.id}/followers?limit=1&max_id=#{follower3_id}")
731
732       assert [%{"id" => ^follower2_id}] = json_response_and_validate_schema(res_conn, 200)
733
734       assert [link_header] = get_resp_header(res_conn, "link")
735       assert link_header =~ ~r/min_id=#{follower2_id}/
736       assert link_header =~ ~r/max_id=#{follower2_id}/
737     end
738   end
739
740   describe "following" do
741     setup do: oauth_access(["read:accounts"])
742
743     test "getting following", %{user: user, conn: conn} do
744       other_user = insert(:user)
745       {:ok, user, other_user} = User.follow(user, other_user)
746
747       conn = get(conn, "/api/v1/accounts/#{user.id}/following")
748
749       assert [%{"id" => id}] = json_response_and_validate_schema(conn, 200)
750       assert id == to_string(other_user.id)
751     end
752
753     test "following with relationship", %{conn: conn, user: user} do
754       other_user = insert(:user)
755       {:ok, user, other_user} = User.follow(user, other_user)
756
757       conn = get(conn, "/api/v1/accounts/#{user.id}/following?with_relationships=true")
758
759       id = other_user.id
760
761       assert [
762                %{
763                  "id" => ^id,
764                  "pleroma" => %{
765                    "relationship" => %{"id" => ^id, "following" => true, "followed_by" => false}
766                  }
767                }
768              ] = json_response_and_validate_schema(conn, 200)
769     end
770
771     test "getting following, hide_follows, other user requesting" do
772       user = insert(:user, hide_follows: true)
773       other_user = insert(:user)
774       {:ok, user, other_user} = User.follow(user, other_user)
775
776       conn =
777         build_conn()
778         |> assign(:user, other_user)
779         |> assign(:token, insert(:oauth_token, user: other_user, scopes: ["read:accounts"]))
780         |> get("/api/v1/accounts/#{user.id}/following")
781
782       assert [] == json_response_and_validate_schema(conn, 200)
783     end
784
785     test "getting following, hide_follows, same user requesting" do
786       user = insert(:user, hide_follows: true)
787       other_user = insert(:user)
788       {:ok, user, _other_user} = User.follow(user, other_user)
789
790       conn =
791         build_conn()
792         |> assign(:user, user)
793         |> assign(:token, insert(:oauth_token, user: user, scopes: ["read:accounts"]))
794         |> get("/api/v1/accounts/#{user.id}/following")
795
796       refute [] == json_response_and_validate_schema(conn, 200)
797     end
798
799     test "getting following, pagination", %{user: user, conn: conn} do
800       following1 = insert(:user)
801       following2 = insert(:user)
802       following3 = insert(:user)
803       {:ok, _, _} = User.follow(user, following1)
804       {:ok, _, _} = User.follow(user, following2)
805       {:ok, _, _} = User.follow(user, following3)
806
807       res_conn = get(conn, "/api/v1/accounts/#{user.id}/following?since_id=#{following1.id}")
808
809       assert [%{"id" => id3}, %{"id" => id2}] = json_response_and_validate_schema(res_conn, 200)
810       assert id3 == following3.id
811       assert id2 == following2.id
812
813       res_conn = get(conn, "/api/v1/accounts/#{user.id}/following?max_id=#{following3.id}")
814
815       assert [%{"id" => id2}, %{"id" => id1}] = json_response_and_validate_schema(res_conn, 200)
816       assert id2 == following2.id
817       assert id1 == following1.id
818
819       res_conn =
820         get(
821           conn,
822           "/api/v1/accounts/#{user.id}/following?id=#{user.id}&limit=20&max_id=#{following3.id}"
823         )
824
825       assert [%{"id" => id2}, %{"id" => id1}] = json_response_and_validate_schema(res_conn, 200)
826       assert id2 == following2.id
827       assert id1 == following1.id
828
829       res_conn =
830         get(conn, "/api/v1/accounts/#{user.id}/following?limit=1&max_id=#{following3.id}")
831
832       assert [%{"id" => id2}] = json_response_and_validate_schema(res_conn, 200)
833       assert id2 == following2.id
834
835       assert [link_header] = get_resp_header(res_conn, "link")
836       assert link_header =~ ~r/min_id=#{following2.id}/
837       assert link_header =~ ~r/max_id=#{following2.id}/
838     end
839   end
840
841   describe "follow/unfollow" do
842     setup do: oauth_access(["follow"])
843
844     test "following / unfollowing a user", %{conn: conn} do
845       %{id: other_user_id, nickname: other_user_nickname} = insert(:user)
846
847       assert %{"id" => _id, "following" => true} =
848                conn
849                |> post("/api/v1/accounts/#{other_user_id}/follow")
850                |> json_response_and_validate_schema(200)
851
852       assert %{"id" => _id, "following" => false} =
853                conn
854                |> post("/api/v1/accounts/#{other_user_id}/unfollow")
855                |> json_response_and_validate_schema(200)
856
857       assert %{"id" => ^other_user_id} =
858                conn
859                |> put_req_header("content-type", "application/json")
860                |> post("/api/v1/follows", %{"uri" => other_user_nickname})
861                |> json_response_and_validate_schema(200)
862     end
863
864     test "cancelling follow request", %{conn: conn} do
865       %{id: other_user_id} = insert(:user, %{is_locked: true})
866
867       assert %{"id" => ^other_user_id, "following" => false, "requested" => true} =
868                conn
869                |> post("/api/v1/accounts/#{other_user_id}/follow")
870                |> json_response_and_validate_schema(:ok)
871
872       assert %{"id" => ^other_user_id, "following" => false, "requested" => false} =
873                conn
874                |> post("/api/v1/accounts/#{other_user_id}/unfollow")
875                |> json_response_and_validate_schema(:ok)
876     end
877
878     test "following without reblogs" do
879       %{conn: conn} = oauth_access(["follow", "read:statuses"])
880       followed = insert(:user)
881       other_user = insert(:user)
882
883       ret_conn =
884         conn
885         |> put_req_header("content-type", "application/json")
886         |> post("/api/v1/accounts/#{followed.id}/follow", %{reblogs: false})
887
888       assert %{"showing_reblogs" => false} = json_response_and_validate_schema(ret_conn, 200)
889
890       {:ok, activity} = CommonAPI.post(other_user, %{status: "hey"})
891       {:ok, %{id: reblog_id}} = CommonAPI.repeat(activity.id, followed)
892
893       assert [] ==
894                conn
895                |> get("/api/v1/timelines/home")
896                |> json_response_and_validate_schema(200)
897
898       assert %{"showing_reblogs" => true} =
899                conn
900                |> put_req_header("content-type", "application/json")
901                |> post("/api/v1/accounts/#{followed.id}/follow", %{reblogs: true})
902                |> json_response_and_validate_schema(200)
903
904       assert %{"showing_reblogs" => true} =
905                conn
906                |> put_req_header("content-type", "application/json")
907                |> post("/api/v1/accounts/#{followed.id}/follow", %{reblogs: "1"})
908                |> json_response_and_validate_schema(200)
909
910       assert [%{"id" => ^reblog_id}] =
911                conn
912                |> get("/api/v1/timelines/home")
913                |> json_response_and_validate_schema(200)
914     end
915
916     test "following with reblogs" do
917       %{conn: conn} = oauth_access(["follow", "read:statuses"])
918       followed = insert(:user)
919       other_user = insert(:user)
920
921       ret_conn = post(conn, "/api/v1/accounts/#{followed.id}/follow")
922
923       assert %{"showing_reblogs" => true} = json_response_and_validate_schema(ret_conn, 200)
924
925       {:ok, activity} = CommonAPI.post(other_user, %{status: "hey"})
926       {:ok, %{id: reblog_id}} = CommonAPI.repeat(activity.id, followed)
927
928       assert [%{"id" => ^reblog_id}] =
929                conn
930                |> get("/api/v1/timelines/home")
931                |> json_response_and_validate_schema(200)
932
933       assert %{"showing_reblogs" => false} =
934                conn
935                |> put_req_header("content-type", "application/json")
936                |> post("/api/v1/accounts/#{followed.id}/follow", %{reblogs: false})
937                |> json_response_and_validate_schema(200)
938
939       assert %{"showing_reblogs" => false} =
940                conn
941                |> put_req_header("content-type", "application/json")
942                |> post("/api/v1/accounts/#{followed.id}/follow", %{reblogs: "0"})
943                |> json_response_and_validate_schema(200)
944
945       assert [] ==
946                conn
947                |> get("/api/v1/timelines/home")
948                |> json_response_and_validate_schema(200)
949     end
950
951     test "following with subscription and unsubscribing" do
952       %{conn: conn} = oauth_access(["follow"])
953       followed = insert(:user)
954
955       assert %{"subscribing" => true} =
956                conn
957                |> put_req_header("content-type", "application/json")
958                |> post("/api/v1/accounts/#{followed.id}/follow", %{notify: true})
959                |> json_response_and_validate_schema(200)
960
961       assert %{"subscribing" => true} =
962                conn
963                |> put_req_header("content-type", "application/json")
964                |> post("/api/v1/accounts/#{followed.id}/follow", %{notify: "1"})
965                |> json_response_and_validate_schema(200)
966
967       assert %{"subscribing" => false} =
968                conn
969                |> put_req_header("content-type", "application/json")
970                |> post("/api/v1/accounts/#{followed.id}/follow", %{notify: false})
971                |> json_response_and_validate_schema(200)
972     end
973
974     test "following / unfollowing errors", %{user: user, conn: conn} do
975       # self follow
976       conn_res = post(conn, "/api/v1/accounts/#{user.id}/follow")
977
978       assert %{"error" => "Can not follow yourself"} =
979                json_response_and_validate_schema(conn_res, 400)
980
981       # self unfollow
982       user = User.get_cached_by_id(user.id)
983       conn_res = post(conn, "/api/v1/accounts/#{user.id}/unfollow")
984
985       assert %{"error" => "Can not unfollow yourself"} =
986                json_response_and_validate_schema(conn_res, 400)
987
988       # self follow via uri
989       user = User.get_cached_by_id(user.id)
990
991       assert %{"error" => "Can not follow yourself"} =
992                conn
993                |> put_req_header("content-type", "multipart/form-data")
994                |> post("/api/v1/follows", %{"uri" => user.nickname})
995                |> json_response_and_validate_schema(400)
996
997       # follow non existing user
998       conn_res = post(conn, "/api/v1/accounts/doesntexist/follow")
999       assert %{"error" => "Record not found"} = json_response_and_validate_schema(conn_res, 404)
1000
1001       # follow non existing user via uri
1002       conn_res =
1003         conn
1004         |> put_req_header("content-type", "multipart/form-data")
1005         |> post("/api/v1/follows", %{"uri" => "doesntexist"})
1006
1007       assert %{"error" => "Record not found"} = json_response_and_validate_schema(conn_res, 404)
1008
1009       # unfollow non existing user
1010       conn_res = post(conn, "/api/v1/accounts/doesntexist/unfollow")
1011       assert %{"error" => "Record not found"} = json_response_and_validate_schema(conn_res, 404)
1012     end
1013   end
1014
1015   describe "mute/unmute" do
1016     setup do: oauth_access(["write:mutes"])
1017
1018     test "with notifications", %{conn: conn} do
1019       other_user = insert(:user)
1020
1021       assert %{"id" => _id, "muting" => true, "muting_notifications" => true} =
1022                conn
1023                |> post("/api/v1/accounts/#{other_user.id}/mute")
1024                |> json_response_and_validate_schema(200)
1025
1026       conn = post(conn, "/api/v1/accounts/#{other_user.id}/unmute")
1027
1028       assert %{"id" => _id, "muting" => false, "muting_notifications" => false} =
1029                json_response_and_validate_schema(conn, 200)
1030     end
1031
1032     test "without notifications", %{conn: conn} do
1033       other_user = insert(:user)
1034
1035       ret_conn =
1036         conn
1037         |> put_req_header("content-type", "multipart/form-data")
1038         |> post("/api/v1/accounts/#{other_user.id}/mute", %{"notifications" => "false"})
1039
1040       assert %{"id" => _id, "muting" => true, "muting_notifications" => false} =
1041                json_response_and_validate_schema(ret_conn, 200)
1042
1043       conn = post(conn, "/api/v1/accounts/#{other_user.id}/unmute")
1044
1045       assert %{"id" => _id, "muting" => false, "muting_notifications" => false} =
1046                json_response_and_validate_schema(conn, 200)
1047     end
1048
1049     test "expiring", %{conn: conn, user: user} do
1050       other_user = insert(:user)
1051
1052       conn =
1053         conn
1054         |> put_req_header("content-type", "multipart/form-data")
1055         |> post("/api/v1/accounts/#{other_user.id}/mute", %{"duration" => "86400"})
1056
1057       assert %{"id" => _id, "muting" => true} = json_response_and_validate_schema(conn, 200)
1058
1059       mute_expires_at = UserRelationship.get_mute_expire_date(user, other_user)
1060
1061       assert DateTime.diff(
1062                mute_expires_at,
1063                DateTime.utc_now() |> DateTime.add(24 * 60 * 60)
1064              ) in -3..3
1065     end
1066
1067     test "falls back to expires_in", %{conn: conn, user: user} do
1068       other_user = insert(:user)
1069
1070       conn
1071       |> put_req_header("content-type", "multipart/form-data")
1072       |> post("/api/v1/accounts/#{other_user.id}/mute", %{"expires_in" => "86400"})
1073       |> json_response_and_validate_schema(200)
1074
1075       mute_expires_at = UserRelationship.get_mute_expire_date(user, other_user)
1076
1077       assert DateTime.diff(
1078                mute_expires_at,
1079                DateTime.utc_now() |> DateTime.add(24 * 60 * 60)
1080              ) in -3..3
1081     end
1082   end
1083
1084   describe "pinned statuses" do
1085     setup do
1086       user = insert(:user)
1087       {:ok, activity} = CommonAPI.post(user, %{status: "HI!!!"})
1088       %{conn: conn} = oauth_access(["read:statuses"], user: user)
1089
1090       [conn: conn, user: user, activity: activity]
1091     end
1092
1093     test "returns pinned statuses", %{conn: conn, user: user, activity: %{id: activity_id}} do
1094       {:ok, _} = CommonAPI.pin(activity_id, user)
1095
1096       assert [%{"id" => ^activity_id, "pinned" => true}] =
1097                conn
1098                |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
1099                |> json_response_and_validate_schema(200)
1100     end
1101   end
1102
1103   test "view pinned private statuses" do
1104     user = insert(:user)
1105     reader = insert(:user)
1106
1107     # Create a private status and pin it
1108     {:ok, %{id: activity_id} = activity} =
1109       CommonAPI.post(user, %{status: "psst", visibility: "private"})
1110
1111     %{data: %{"id" => object_ap_id}} = Object.normalize(activity)
1112     {:ok, _} = User.add_pinned_object_id(user, object_ap_id)
1113
1114     %{conn: conn} = oauth_access(["read:statuses"], user: reader)
1115
1116     # A non-follower can't see the pinned status
1117     assert [] ==
1118              conn
1119              |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
1120              |> json_response_and_validate_schema(200)
1121
1122     # Follow the user, then the pinned status can be seen
1123     CommonAPI.follow(reader, user)
1124     ObanHelpers.perform_all()
1125
1126     assert [%{"id" => ^activity_id, "pinned" => true}] =
1127              conn
1128              |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
1129              |> json_response_and_validate_schema(200)
1130   end
1131
1132   test "blocking / unblocking a user" do
1133     %{conn: conn} = oauth_access(["follow"])
1134     other_user = insert(:user)
1135
1136     ret_conn = post(conn, "/api/v1/accounts/#{other_user.id}/block")
1137
1138     assert %{"id" => _id, "blocking" => true} = json_response_and_validate_schema(ret_conn, 200)
1139
1140     conn = post(conn, "/api/v1/accounts/#{other_user.id}/unblock")
1141
1142     assert %{"id" => _id, "blocking" => false} = json_response_and_validate_schema(conn, 200)
1143   end
1144
1145   describe "create account by app" do
1146     setup do
1147       valid_params = %{
1148         username: "lain",
1149         email: "lain@example.org",
1150         password: "PlzDontHackLain",
1151         agreement: true
1152       }
1153
1154       [valid_params: valid_params]
1155     end
1156
1157     test "registers and logs in without :account_activation_required / :account_approval_required",
1158          %{conn: conn} do
1159       clear_config([:instance, :account_activation_required], false)
1160       clear_config([:instance, :account_approval_required], false)
1161
1162       conn =
1163         conn
1164         |> put_req_header("content-type", "application/json")
1165         |> post("/api/v1/apps", %{
1166           client_name: "client_name",
1167           redirect_uris: "urn:ietf:wg:oauth:2.0:oob",
1168           scopes: "read, write, follow"
1169         })
1170
1171       assert %{
1172                "client_id" => client_id,
1173                "client_secret" => client_secret,
1174                "id" => _,
1175                "name" => "client_name",
1176                "redirect_uri" => "urn:ietf:wg:oauth:2.0:oob",
1177                "vapid_key" => _,
1178                "website" => nil
1179              } = json_response_and_validate_schema(conn, 200)
1180
1181       conn =
1182         post(conn, "/oauth/token", %{
1183           grant_type: "client_credentials",
1184           client_id: client_id,
1185           client_secret: client_secret
1186         })
1187
1188       assert %{"access_token" => token, "refresh_token" => refresh, "scope" => scope} =
1189                json_response(conn, 200)
1190
1191       assert token
1192       token_from_db = Repo.get_by(Token, token: token)
1193       assert token_from_db
1194       assert refresh
1195       assert scope == "read write follow"
1196
1197       clear_config([User, :email_blacklist], ["example.org"])
1198
1199       params = %{
1200         username: "lain",
1201         email: "lain@example.org",
1202         password: "PlzDontHackLain",
1203         bio: "Test Bio",
1204         agreement: true
1205       }
1206
1207       conn =
1208         build_conn()
1209         |> put_req_header("content-type", "multipart/form-data")
1210         |> put_req_header("authorization", "Bearer " <> token)
1211         |> post("/api/v1/accounts", params)
1212
1213       assert %{"error" => "{\"email\":[\"Invalid email\"]}"} =
1214                json_response_and_validate_schema(conn, 400)
1215
1216       clear_config([User, :email_blacklist], [])
1217
1218       conn =
1219         build_conn()
1220         |> put_req_header("content-type", "multipart/form-data")
1221         |> put_req_header("authorization", "Bearer " <> token)
1222         |> post("/api/v1/accounts", params)
1223
1224       %{
1225         "access_token" => token,
1226         "created_at" => _created_at,
1227         "scope" => ^scope,
1228         "token_type" => "Bearer"
1229       } = json_response_and_validate_schema(conn, 200)
1230
1231       token_from_db = Repo.get_by(Token, token: token)
1232       assert token_from_db
1233       user = Repo.preload(token_from_db, :user).user
1234
1235       assert user
1236       assert user.is_confirmed
1237       assert user.is_approved
1238     end
1239
1240     test "registers but does not log in with :account_activation_required", %{conn: conn} do
1241       clear_config([:instance, :account_activation_required], true)
1242       clear_config([:instance, :account_approval_required], false)
1243
1244       conn =
1245         conn
1246         |> put_req_header("content-type", "application/json")
1247         |> post("/api/v1/apps", %{
1248           client_name: "client_name",
1249           redirect_uris: "urn:ietf:wg:oauth:2.0:oob",
1250           scopes: "read, write, follow"
1251         })
1252
1253       assert %{
1254                "client_id" => client_id,
1255                "client_secret" => client_secret,
1256                "id" => _,
1257                "name" => "client_name",
1258                "redirect_uri" => "urn:ietf:wg:oauth:2.0:oob",
1259                "vapid_key" => _,
1260                "website" => nil
1261              } = json_response_and_validate_schema(conn, 200)
1262
1263       conn =
1264         post(conn, "/oauth/token", %{
1265           grant_type: "client_credentials",
1266           client_id: client_id,
1267           client_secret: client_secret
1268         })
1269
1270       assert %{"access_token" => token, "refresh_token" => refresh, "scope" => scope} =
1271                json_response(conn, 200)
1272
1273       assert token
1274       token_from_db = Repo.get_by(Token, token: token)
1275       assert token_from_db
1276       assert refresh
1277       assert scope == "read write follow"
1278
1279       conn =
1280         build_conn()
1281         |> put_req_header("content-type", "multipart/form-data")
1282         |> put_req_header("authorization", "Bearer " <> token)
1283         |> post("/api/v1/accounts", %{
1284           username: "lain",
1285           email: "lain@example.org",
1286           password: "PlzDontHackLain",
1287           bio: "Test Bio",
1288           agreement: true
1289         })
1290
1291       response = json_response_and_validate_schema(conn, 200)
1292       assert %{"identifier" => "missing_confirmed_email"} = response
1293       refute response["access_token"]
1294       refute response["token_type"]
1295
1296       user = Repo.get_by(User, email: "lain@example.org")
1297       refute user.is_confirmed
1298     end
1299
1300     test "registers but does not log in with :account_approval_required", %{conn: conn} do
1301       clear_config([:instance, :account_approval_required], true)
1302       clear_config([:instance, :account_activation_required], false)
1303
1304       conn =
1305         conn
1306         |> put_req_header("content-type", "application/json")
1307         |> post("/api/v1/apps", %{
1308           client_name: "client_name",
1309           redirect_uris: "urn:ietf:wg:oauth:2.0:oob",
1310           scopes: "read, write, follow"
1311         })
1312
1313       assert %{
1314                "client_id" => client_id,
1315                "client_secret" => client_secret,
1316                "id" => _,
1317                "name" => "client_name",
1318                "redirect_uri" => "urn:ietf:wg:oauth:2.0:oob",
1319                "vapid_key" => _,
1320                "website" => nil
1321              } = json_response_and_validate_schema(conn, 200)
1322
1323       conn =
1324         post(conn, "/oauth/token", %{
1325           grant_type: "client_credentials",
1326           client_id: client_id,
1327           client_secret: client_secret
1328         })
1329
1330       assert %{"access_token" => token, "refresh_token" => refresh, "scope" => scope} =
1331                json_response(conn, 200)
1332
1333       assert token
1334       token_from_db = Repo.get_by(Token, token: token)
1335       assert token_from_db
1336       assert refresh
1337       assert scope == "read write follow"
1338
1339       conn =
1340         build_conn()
1341         |> put_req_header("content-type", "multipart/form-data")
1342         |> put_req_header("authorization", "Bearer " <> token)
1343         |> post("/api/v1/accounts", %{
1344           username: "lain",
1345           email: "lain@example.org",
1346           password: "PlzDontHackLain",
1347           bio: "Test Bio",
1348           agreement: true,
1349           reason: "I'm a cool dude, bro"
1350         })
1351
1352       response = json_response_and_validate_schema(conn, 200)
1353       assert %{"identifier" => "awaiting_approval"} = response
1354       refute response["access_token"]
1355       refute response["token_type"]
1356
1357       user = Repo.get_by(User, email: "lain@example.org")
1358
1359       refute user.is_approved
1360       assert user.registration_reason == "I'm a cool dude, bro"
1361     end
1362
1363     test "returns error when user already registered", %{conn: conn, valid_params: valid_params} do
1364       _user = insert(:user, email: "lain@example.org")
1365       app_token = insert(:oauth_token, user: nil)
1366
1367       res =
1368         conn
1369         |> put_req_header("authorization", "Bearer " <> app_token.token)
1370         |> put_req_header("content-type", "application/json")
1371         |> post("/api/v1/accounts", valid_params)
1372
1373       assert json_response_and_validate_schema(res, 400) == %{
1374                "error" => "{\"email\":[\"has already been taken\"]}"
1375              }
1376     end
1377
1378     test "returns bad_request if missing required params", %{
1379       conn: conn,
1380       valid_params: valid_params
1381     } do
1382       app_token = insert(:oauth_token, user: nil)
1383
1384       conn =
1385         conn
1386         |> put_req_header("authorization", "Bearer " <> app_token.token)
1387         |> put_req_header("content-type", "application/json")
1388
1389       res = post(conn, "/api/v1/accounts", valid_params)
1390       assert json_response_and_validate_schema(res, 200)
1391
1392       [{127, 0, 0, 1}, {127, 0, 0, 2}, {127, 0, 0, 3}, {127, 0, 0, 4}]
1393       |> Stream.zip(Map.delete(valid_params, :email))
1394       |> Enum.each(fn {ip, {attr, _}} ->
1395         res =
1396           conn
1397           |> Map.put(:remote_ip, ip)
1398           |> post("/api/v1/accounts", Map.delete(valid_params, attr))
1399           |> json_response_and_validate_schema(400)
1400
1401         assert res == %{
1402                  "error" => "Missing field: #{attr}.",
1403                  "errors" => [
1404                    %{
1405                      "message" => "Missing field: #{attr}",
1406                      "source" => %{"pointer" => "/#{attr}"},
1407                      "title" => "Invalid value"
1408                    }
1409                  ]
1410                }
1411       end)
1412     end
1413
1414     test "returns bad_request if missing email params when :account_activation_required is enabled",
1415          %{conn: conn, valid_params: valid_params} do
1416       clear_config([:instance, :account_activation_required], true)
1417
1418       app_token = insert(:oauth_token, user: nil)
1419
1420       conn =
1421         conn
1422         |> put_req_header("authorization", "Bearer " <> app_token.token)
1423         |> put_req_header("content-type", "application/json")
1424
1425       res =
1426         conn
1427         |> Map.put(:remote_ip, {127, 0, 0, 5})
1428         |> post("/api/v1/accounts", Map.delete(valid_params, :email))
1429
1430       assert json_response_and_validate_schema(res, 400) ==
1431                %{"error" => "Missing parameter: email"}
1432
1433       res =
1434         conn
1435         |> Map.put(:remote_ip, {127, 0, 0, 6})
1436         |> post("/api/v1/accounts", Map.put(valid_params, :email, ""))
1437
1438       assert json_response_and_validate_schema(res, 400) == %{
1439                "error" => "{\"email\":[\"can't be blank\"]}"
1440              }
1441     end
1442
1443     test "allow registration without an email", %{conn: conn, valid_params: valid_params} do
1444       app_token = insert(:oauth_token, user: nil)
1445       conn = put_req_header(conn, "authorization", "Bearer " <> app_token.token)
1446
1447       res =
1448         conn
1449         |> put_req_header("content-type", "application/json")
1450         |> Map.put(:remote_ip, {127, 0, 0, 7})
1451         |> post("/api/v1/accounts", Map.delete(valid_params, :email))
1452
1453       assert json_response_and_validate_schema(res, 200)
1454     end
1455
1456     test "allow registration with an empty email", %{conn: conn, valid_params: valid_params} do
1457       app_token = insert(:oauth_token, user: nil)
1458       conn = put_req_header(conn, "authorization", "Bearer " <> app_token.token)
1459
1460       res =
1461         conn
1462         |> put_req_header("content-type", "application/json")
1463         |> Map.put(:remote_ip, {127, 0, 0, 8})
1464         |> post("/api/v1/accounts", Map.put(valid_params, :email, ""))
1465
1466       assert json_response_and_validate_schema(res, 200)
1467     end
1468
1469     test "returns forbidden if token is invalid", %{conn: conn, valid_params: valid_params} do
1470       res =
1471         conn
1472         |> put_req_header("authorization", "Bearer " <> "invalid-token")
1473         |> put_req_header("content-type", "multipart/form-data")
1474         |> post("/api/v1/accounts", valid_params)
1475
1476       assert json_response_and_validate_schema(res, 403) == %{"error" => "Invalid credentials"}
1477     end
1478
1479     test "registration from trusted app" do
1480       clear_config([Pleroma.Captcha, :enabled], true)
1481       app = insert(:oauth_app, trusted: true, scopes: ["read", "write", "follow", "push"])
1482
1483       conn =
1484         build_conn()
1485         |> post("/oauth/token", %{
1486           "grant_type" => "client_credentials",
1487           "client_id" => app.client_id,
1488           "client_secret" => app.client_secret
1489         })
1490
1491       assert %{"access_token" => token, "token_type" => "Bearer"} = json_response(conn, 200)
1492
1493       response =
1494         build_conn()
1495         |> Plug.Conn.put_req_header("authorization", "Bearer " <> token)
1496         |> put_req_header("content-type", "multipart/form-data")
1497         |> post("/api/v1/accounts", %{
1498           nickname: "nickname",
1499           agreement: true,
1500           email: "email@example.com",
1501           fullname: "Lain",
1502           username: "Lain",
1503           password: "some_password",
1504           confirm: "some_password"
1505         })
1506         |> json_response_and_validate_schema(200)
1507
1508       assert %{
1509                "access_token" => access_token,
1510                "created_at" => _,
1511                "scope" => "read write follow push",
1512                "token_type" => "Bearer"
1513              } = response
1514
1515       response =
1516         build_conn()
1517         |> Plug.Conn.put_req_header("authorization", "Bearer " <> access_token)
1518         |> get("/api/v1/accounts/verify_credentials")
1519         |> json_response_and_validate_schema(200)
1520
1521       assert %{
1522                "acct" => "Lain",
1523                "bot" => false,
1524                "display_name" => "Lain",
1525                "follow_requests_count" => 0,
1526                "followers_count" => 0,
1527                "following_count" => 0,
1528                "locked" => false,
1529                "note" => "",
1530                "source" => %{
1531                  "fields" => [],
1532                  "note" => "",
1533                  "pleroma" => %{
1534                    "actor_type" => "Person",
1535                    "discoverable" => false,
1536                    "no_rich_text" => false,
1537                    "show_role" => true
1538                  },
1539                  "privacy" => "public",
1540                  "sensitive" => false
1541                },
1542                "statuses_count" => 0,
1543                "username" => "Lain"
1544              } = response
1545     end
1546   end
1547
1548   describe "create account by app / rate limit" do
1549     setup do: clear_config([:rate_limit, :app_account_creation], {10_000, 2})
1550
1551     test "respects rate limit setting", %{conn: conn} do
1552       app_token = insert(:oauth_token, user: nil)
1553
1554       conn =
1555         conn
1556         |> put_req_header("authorization", "Bearer " <> app_token.token)
1557         |> Map.put(:remote_ip, {15, 15, 15, 15})
1558         |> put_req_header("content-type", "multipart/form-data")
1559
1560       for i <- 1..2 do
1561         conn =
1562           conn
1563           |> post("/api/v1/accounts", %{
1564             username: "#{i}lain",
1565             email: "#{i}lain@example.org",
1566             password: "PlzDontHackLain",
1567             agreement: true
1568           })
1569
1570         %{
1571           "access_token" => token,
1572           "created_at" => _created_at,
1573           "scope" => _scope,
1574           "token_type" => "Bearer"
1575         } = json_response_and_validate_schema(conn, 200)
1576
1577         token_from_db = Repo.get_by(Token, token: token)
1578         assert token_from_db
1579         token_from_db = Repo.preload(token_from_db, :user)
1580         assert token_from_db.user
1581       end
1582
1583       conn =
1584         post(conn, "/api/v1/accounts", %{
1585           username: "6lain",
1586           email: "6lain@example.org",
1587           password: "PlzDontHackLain",
1588           agreement: true
1589         })
1590
1591       assert json_response_and_validate_schema(conn, :too_many_requests) == %{
1592                "error" => "Throttled"
1593              }
1594     end
1595   end
1596
1597   describe "create account with enabled captcha" do
1598     setup %{conn: conn} do
1599       app_token = insert(:oauth_token, user: nil)
1600
1601       conn =
1602         conn
1603         |> put_req_header("authorization", "Bearer " <> app_token.token)
1604         |> put_req_header("content-type", "multipart/form-data")
1605
1606       [conn: conn]
1607     end
1608
1609     setup do: clear_config([Pleroma.Captcha, :enabled], true)
1610
1611     test "creates an account and returns 200 if captcha is valid", %{conn: conn} do
1612       %{token: token, answer_data: answer_data} = Pleroma.Captcha.new()
1613
1614       params = %{
1615         username: "lain",
1616         email: "lain@example.org",
1617         password: "PlzDontHackLain",
1618         agreement: true,
1619         captcha_solution: Pleroma.Captcha.Mock.solution(),
1620         captcha_token: token,
1621         captcha_answer_data: answer_data
1622       }
1623
1624       assert %{
1625                "access_token" => access_token,
1626                "created_at" => _,
1627                "scope" => "read",
1628                "token_type" => "Bearer"
1629              } =
1630                conn
1631                |> post("/api/v1/accounts", params)
1632                |> json_response_and_validate_schema(:ok)
1633
1634       assert Token |> Repo.get_by(token: access_token) |> Repo.preload(:user) |> Map.get(:user)
1635     end
1636
1637     test "returns 400 if any captcha field is not provided", %{conn: conn} do
1638       captcha_fields = [:captcha_solution, :captcha_token, :captcha_answer_data]
1639
1640       valid_params = %{
1641         username: "lain",
1642         email: "lain@example.org",
1643         password: "PlzDontHackLain",
1644         agreement: true,
1645         captcha_solution: "xx",
1646         captcha_token: "xx",
1647         captcha_answer_data: "xx"
1648       }
1649
1650       for field <- captcha_fields do
1651         expected = %{
1652           "error" => "{\"captcha\":[\"Invalid CAPTCHA (Missing parameter: #{field})\"]}"
1653         }
1654
1655         assert expected ==
1656                  conn
1657                  |> post("/api/v1/accounts", Map.delete(valid_params, field))
1658                  |> json_response_and_validate_schema(:bad_request)
1659       end
1660     end
1661
1662     test "returns an error if captcha is invalid", %{conn: conn} do
1663       params = %{
1664         username: "lain",
1665         email: "lain@example.org",
1666         password: "PlzDontHackLain",
1667         agreement: true,
1668         captcha_solution: "cofe",
1669         captcha_token: "cofe",
1670         captcha_answer_data: "cofe"
1671       }
1672
1673       assert %{"error" => "{\"captcha\":[\"Invalid answer data\"]}"} ==
1674                conn
1675                |> post("/api/v1/accounts", params)
1676                |> json_response_and_validate_schema(:bad_request)
1677     end
1678   end
1679
1680   describe "create account with required birth date" do
1681     setup %{conn: conn} do
1682       clear_config([:instance, :birthday_required], true)
1683       clear_config([:instance, :birthday_min_age], 18 * 365)
1684
1685       app_token = insert(:oauth_token, user: nil)
1686
1687       conn =
1688         conn
1689         |> put_req_header("authorization", "Bearer " <> app_token.token)
1690         |> put_req_header("content-type", "multipart/form-data")
1691
1692       [conn: conn]
1693     end
1694
1695     test "creates an account if provided valid birth date", %{conn: conn} do
1696       birthday =
1697         Date.utc_today()
1698         |> Date.add(-19 * 365)
1699         |> Date.to_string()
1700
1701       params = %{
1702         username: "mkljczk",
1703         email: "mkljczk@example.org",
1704         password: "dupa.8",
1705         agreement: true,
1706         birthday: birthday
1707       }
1708
1709       res =
1710         conn
1711         |> post("/api/v1/accounts", params)
1712
1713       assert json_response_and_validate_schema(res, 200)
1714     end
1715
1716     test "returns an error if missing birth date", %{conn: conn} do
1717       params = %{
1718         username: "mkljczk",
1719         email: "mkljczk@example.org",
1720         password: "dupa.8",
1721         agreement: true
1722       }
1723
1724       res =
1725         conn
1726         |> post("/api/v1/accounts", params)
1727
1728       assert json_response_and_validate_schema(res, 400) == %{
1729                "error" => "{\"birthday\":[\"can't be blank\"]}"
1730              }
1731     end
1732   end
1733
1734   describe "create account with language" do
1735     setup %{conn: conn} do
1736       app_token = insert(:oauth_token, user: nil)
1737
1738       conn =
1739         conn
1740         |> put_req_header("authorization", "Bearer " <> app_token.token)
1741         |> put_req_header("content-type", "multipart/form-data")
1742         |> put_req_cookie(SetLocalePlug.frontend_language_cookie_name(), "zh-Hans")
1743         |> SetLocalePlug.call([])
1744
1745       [conn: conn]
1746     end
1747
1748     test "creates an account with language parameter", %{conn: conn} do
1749       params = %{
1750         username: "foo",
1751         email: "foo@example.org",
1752         password: "dupa.8",
1753         agreement: true,
1754         language: "ru"
1755       }
1756
1757       res =
1758         conn
1759         |> post("/api/v1/accounts", params)
1760
1761       assert json_response_and_validate_schema(res, 200)
1762
1763       assert %{language: "ru"} = Pleroma.User.get_by_nickname("foo")
1764     end
1765
1766     test "language parameter should be normalized", %{conn: conn} do
1767       params = %{
1768         username: "foo",
1769         email: "foo@example.org",
1770         password: "dupa.8",
1771         agreement: true,
1772         language: "ru-RU"
1773       }
1774
1775       res =
1776         conn
1777         |> post("/api/v1/accounts", params)
1778
1779       assert json_response_and_validate_schema(res, 200)
1780
1781       assert %{language: "ru_RU"} = Pleroma.User.get_by_nickname("foo")
1782     end
1783
1784     test "creating an account without language parameter should fallback to cookie/header language",
1785          %{conn: conn} do
1786       params = %{
1787         username: "foo2",
1788         email: "foo2@example.org",
1789         password: "dupa.8",
1790         agreement: true
1791       }
1792
1793       res =
1794         conn
1795         |> post("/api/v1/accounts", params)
1796
1797       assert json_response_and_validate_schema(res, 200)
1798
1799       assert %{language: "zh_Hans"} = Pleroma.User.get_by_nickname("foo2")
1800     end
1801   end
1802
1803   describe "GET /api/v1/accounts/:id/lists - account_lists" do
1804     test "returns lists to which the account belongs" do
1805       %{user: user, conn: conn} = oauth_access(["read:lists"])
1806       other_user = insert(:user)
1807       assert {:ok, %Pleroma.List{id: _list_id} = list} = Pleroma.List.create("Test List", user)
1808       {:ok, %{following: _following}} = Pleroma.List.follow(list, other_user)
1809
1810       assert [%{"id" => _list_id, "title" => "Test List"}] =
1811                conn
1812                |> get("/api/v1/accounts/#{other_user.id}/lists")
1813                |> json_response_and_validate_schema(200)
1814     end
1815   end
1816
1817   describe "verify_credentials" do
1818     test "verify_credentials" do
1819       %{user: user, conn: conn} = oauth_access(["read:accounts"])
1820
1821       [notification | _] =
1822         insert_list(7, :notification, user: user, activity: insert(:note_activity))
1823
1824       Pleroma.Notification.set_read_up_to(user, notification.id)
1825       conn = get(conn, "/api/v1/accounts/verify_credentials")
1826
1827       response = json_response_and_validate_schema(conn, 200)
1828
1829       assert %{"id" => id, "source" => %{"privacy" => "public"}} = response
1830       assert response["pleroma"]["chat_token"]
1831       assert response["pleroma"]["unread_notifications_count"] == 6
1832       assert id == to_string(user.id)
1833     end
1834
1835     test "verify_credentials default scope unlisted" do
1836       user = insert(:user, default_scope: "unlisted")
1837       %{conn: conn} = oauth_access(["read:accounts"], user: user)
1838
1839       conn = get(conn, "/api/v1/accounts/verify_credentials")
1840
1841       assert %{"id" => id, "source" => %{"privacy" => "unlisted"}} =
1842                json_response_and_validate_schema(conn, 200)
1843
1844       assert id == to_string(user.id)
1845     end
1846
1847     test "locked accounts" do
1848       user = insert(:user, default_scope: "private")
1849       %{conn: conn} = oauth_access(["read:accounts"], user: user)
1850
1851       conn = get(conn, "/api/v1/accounts/verify_credentials")
1852
1853       assert %{"id" => id, "source" => %{"privacy" => "private"}} =
1854                json_response_and_validate_schema(conn, 200)
1855
1856       assert id == to_string(user.id)
1857     end
1858   end
1859
1860   describe "user relationships" do
1861     setup do: oauth_access(["read:follows"])
1862
1863     test "returns the relationships for the current user", %{user: user, conn: conn} do
1864       %{id: other_user_id} = other_user = insert(:user)
1865       {:ok, _user, _other_user} = User.follow(user, other_user)
1866
1867       assert [%{"id" => ^other_user_id}] =
1868                conn
1869                |> get("/api/v1/accounts/relationships?id=#{other_user.id}")
1870                |> json_response_and_validate_schema(200)
1871
1872       assert [%{"id" => ^other_user_id}] =
1873                conn
1874                |> get("/api/v1/accounts/relationships?id[]=#{other_user.id}")
1875                |> json_response_and_validate_schema(200)
1876     end
1877
1878     test "returns an empty list on a bad request", %{conn: conn} do
1879       conn = get(conn, "/api/v1/accounts/relationships", %{})
1880
1881       assert [] = json_response_and_validate_schema(conn, 200)
1882     end
1883   end
1884
1885   test "getting a list of mutes" do
1886     %{user: user, conn: conn} = oauth_access(["read:mutes"])
1887     %{id: id1} = other_user1 = insert(:user)
1888     %{id: id2} = other_user2 = insert(:user)
1889     %{id: id3} = other_user3 = insert(:user)
1890
1891     {:ok, _user_relationships} = User.mute(user, other_user1)
1892     {:ok, _user_relationships} = User.mute(user, other_user2)
1893     {:ok, _user_relationships} = User.mute(user, other_user3)
1894
1895     result =
1896       conn
1897       |> get("/api/v1/mutes")
1898       |> json_response_and_validate_schema(200)
1899
1900     assert [id3, id2, id1] == Enum.map(result, & &1["id"])
1901
1902     result =
1903       conn
1904       |> get("/api/v1/mutes?limit=1")
1905       |> json_response_and_validate_schema(200)
1906
1907     assert [%{"id" => ^id3}] = result
1908
1909     result =
1910       conn
1911       |> get("/api/v1/mutes?since_id=#{id1}")
1912       |> json_response_and_validate_schema(200)
1913
1914     assert [%{"id" => ^id3}, %{"id" => ^id2}] = result
1915
1916     result =
1917       conn
1918       |> get("/api/v1/mutes?since_id=#{id1}&max_id=#{id3}")
1919       |> json_response_and_validate_schema(200)
1920
1921     assert [%{"id" => ^id2}] = result
1922
1923     result =
1924       conn
1925       |> get("/api/v1/mutes?since_id=#{id1}&limit=1")
1926       |> json_response_and_validate_schema(200)
1927
1928     assert [%{"id" => ^id3}] = result
1929   end
1930
1931   test "list of mutes with with_relationships parameter" do
1932     %{user: user, conn: conn} = oauth_access(["read:mutes"])
1933     %{id: id1} = other_user1 = insert(:user)
1934     %{id: id2} = other_user2 = insert(:user)
1935     %{id: id3} = other_user3 = insert(:user)
1936
1937     {:ok, _, _} = User.follow(other_user1, user)
1938     {:ok, _, _} = User.follow(other_user2, user)
1939     {:ok, _, _} = User.follow(other_user3, user)
1940
1941     {:ok, _} = User.mute(user, other_user1)
1942     {:ok, _} = User.mute(user, other_user2)
1943     {:ok, _} = User.mute(user, other_user3)
1944
1945     assert [
1946              %{
1947                "id" => ^id3,
1948                "pleroma" => %{"relationship" => %{"muting" => true, "followed_by" => true}}
1949              },
1950              %{
1951                "id" => ^id2,
1952                "pleroma" => %{"relationship" => %{"muting" => true, "followed_by" => true}}
1953              },
1954              %{
1955                "id" => ^id1,
1956                "pleroma" => %{"relationship" => %{"muting" => true, "followed_by" => true}}
1957              }
1958            ] =
1959              conn
1960              |> get("/api/v1/mutes?with_relationships=true")
1961              |> json_response_and_validate_schema(200)
1962   end
1963
1964   test "getting a list of blocks" do
1965     %{user: user, conn: conn} = oauth_access(["read:blocks"])
1966     %{id: id1} = other_user1 = insert(:user)
1967     %{id: id2} = other_user2 = insert(:user)
1968     %{id: id3} = other_user3 = insert(:user)
1969
1970     {:ok, _user_relationship} = User.block(user, other_user1)
1971     {:ok, _user_relationship} = User.block(user, other_user3)
1972     {:ok, _user_relationship} = User.block(user, other_user2)
1973
1974     result =
1975       conn
1976       |> assign(:user, user)
1977       |> get("/api/v1/blocks")
1978       |> json_response_and_validate_schema(200)
1979
1980     assert [id3, id2, id1] == Enum.map(result, & &1["id"])
1981
1982     result =
1983       conn
1984       |> assign(:user, user)
1985       |> get("/api/v1/blocks?limit=1")
1986       |> json_response_and_validate_schema(200)
1987
1988     assert [%{"id" => ^id3}] = result
1989
1990     result =
1991       conn
1992       |> assign(:user, user)
1993       |> get("/api/v1/blocks?since_id=#{id1}")
1994       |> json_response_and_validate_schema(200)
1995
1996     assert [%{"id" => ^id3}, %{"id" => ^id2}] = result
1997
1998     result =
1999       conn
2000       |> assign(:user, user)
2001       |> get("/api/v1/blocks?since_id=#{id1}&max_id=#{id3}")
2002       |> json_response_and_validate_schema(200)
2003
2004     assert [%{"id" => ^id2}] = result
2005
2006     result =
2007       conn
2008       |> assign(:user, user)
2009       |> get("/api/v1/blocks?since_id=#{id1}&limit=1")
2010       |> json_response_and_validate_schema(200)
2011
2012     assert [%{"id" => ^id3}] = result
2013
2014     conn_res =
2015       conn
2016       |> assign(:user, user)
2017       |> get("/api/v1/blocks?limit=2")
2018
2019     next_url =
2020       ~r{<.+?(?<link>/api[^>]+)>; rel=\"next\"}
2021       |> Regex.named_captures(get_resp_header(conn_res, "link") |> Enum.at(0))
2022       |> Map.get("link")
2023
2024     result =
2025       conn_res
2026       |> json_response_and_validate_schema(200)
2027
2028     assert [%{"id" => ^id3}, %{"id" => ^id2}] = result
2029
2030     result =
2031       conn
2032       |> assign(:user, user)
2033       |> get(next_url)
2034       |> json_response_and_validate_schema(200)
2035
2036     assert [%{"id" => ^id1}] = result
2037   end
2038
2039   test "list of blocks with with_relationships parameter" do
2040     %{user: user, conn: conn} = oauth_access(["read:blocks"])
2041     %{id: id1} = other_user1 = insert(:user)
2042     %{id: id2} = other_user2 = insert(:user)
2043     %{id: id3} = other_user3 = insert(:user)
2044
2045     {:ok, _, _} = User.follow(other_user1, user)
2046     {:ok, _, _} = User.follow(other_user2, user)
2047     {:ok, _, _} = User.follow(other_user3, user)
2048
2049     {:ok, _} = User.block(user, other_user1)
2050     {:ok, _} = User.block(user, other_user2)
2051     {:ok, _} = User.block(user, other_user3)
2052
2053     assert [
2054              %{
2055                "id" => ^id3,
2056                "pleroma" => %{"relationship" => %{"blocking" => true, "followed_by" => false}}
2057              },
2058              %{
2059                "id" => ^id2,
2060                "pleroma" => %{"relationship" => %{"blocking" => true, "followed_by" => false}}
2061              },
2062              %{
2063                "id" => ^id1,
2064                "pleroma" => %{"relationship" => %{"blocking" => true, "followed_by" => false}}
2065              }
2066            ] =
2067              conn
2068              |> get("/api/v1/blocks?with_relationships=true")
2069              |> json_response_and_validate_schema(200)
2070   end
2071
2072   test "account lookup", %{conn: conn} do
2073     %{nickname: acct} = insert(:user, %{nickname: "nickname"})
2074     %{nickname: acct_two} = insert(:user, %{nickname: "nickname@notlocaldoma.in"})
2075
2076     result =
2077       conn
2078       |> get("/api/v1/accounts/lookup?acct=#{acct}")
2079       |> json_response_and_validate_schema(200)
2080
2081     assert %{"acct" => ^acct} = result
2082
2083     result =
2084       conn
2085       |> get("/api/v1/accounts/lookup?acct=#{acct_two}")
2086       |> json_response_and_validate_schema(200)
2087
2088     assert %{"acct" => ^acct_two} = result
2089
2090     _result =
2091       conn
2092       |> get("/api/v1/accounts/lookup?acct=unexisting_nickname")
2093       |> json_response_and_validate_schema(404)
2094   end
2095
2096   test "create a note on a user" do
2097     %{conn: conn} = oauth_access(["write:accounts", "read:follows"])
2098     other_user = insert(:user)
2099
2100     conn
2101     |> put_req_header("content-type", "application/json")
2102     |> post("/api/v1/accounts/#{other_user.id}/note", %{
2103       "comment" => "Example note"
2104     })
2105
2106     assert [%{"note" => "Example note"}] =
2107              conn
2108              |> put_req_header("content-type", "application/json")
2109              |> get("/api/v1/accounts/relationships?id=#{other_user.id}")
2110              |> json_response_and_validate_schema(200)
2111   end
2112
2113   describe "account endorsements" do
2114     setup do: oauth_access(["read:accounts", "write:accounts", "write:follows"])
2115
2116     setup do: clear_config([:instance, :max_endorsed_users], 1)
2117
2118     test "pin account", %{user: user, conn: conn} do
2119       %{id: id1} = other_user1 = insert(:user)
2120
2121       CommonAPI.follow(user, other_user1)
2122
2123       assert %{"id" => ^id1, "endorsed" => true} =
2124                conn
2125                |> put_req_header("content-type", "application/json")
2126                |> post("/api/v1/accounts/#{id1}/pin")
2127                |> json_response_and_validate_schema(200)
2128
2129       assert [%{"id" => ^id1}] =
2130                conn
2131                |> put_req_header("content-type", "application/json")
2132                |> get("/api/v1/endorsements")
2133                |> json_response_and_validate_schema(200)
2134     end
2135
2136     test "unpin account", %{user: user, conn: conn} do
2137       %{id: id1} = other_user1 = insert(:user)
2138
2139       CommonAPI.follow(user, other_user1)
2140       User.endorse(user, other_user1)
2141
2142       assert %{"id" => ^id1, "endorsed" => false} =
2143                conn
2144                |> put_req_header("content-type", "application/json")
2145                |> post("/api/v1/accounts/#{id1}/unpin")
2146                |> json_response_and_validate_schema(200)
2147
2148       assert [] =
2149                conn
2150                |> put_req_header("content-type", "application/json")
2151                |> get("/api/v1/endorsements")
2152                |> json_response_and_validate_schema(200)
2153     end
2154
2155     test "max pinned accounts", %{user: user, conn: conn} do
2156       %{id: id1} = other_user1 = insert(:user)
2157       %{id: id2} = other_user2 = insert(:user)
2158
2159       CommonAPI.follow(user, other_user1)
2160       CommonAPI.follow(user, other_user2)
2161
2162       conn
2163       |> put_req_header("content-type", "application/json")
2164       |> post("/api/v1/accounts/#{id1}/pin")
2165       |> json_response_and_validate_schema(200)
2166
2167       assert %{"error" => "You have already pinned the maximum number of users"} =
2168                conn
2169                |> assign(:user, user)
2170                |> post("/api/v1/accounts/#{id2}/pin")
2171                |> json_response_and_validate_schema(400)
2172     end
2173   end
2174
2175   describe "remove from followers" do
2176     setup do: oauth_access(["follow"])
2177
2178     test "removing user from followers", %{conn: conn, user: user} do
2179       %{id: other_user_id} = other_user = insert(:user)
2180
2181       CommonAPI.follow(other_user, user)
2182
2183       assert %{"id" => ^other_user_id, "followed_by" => false} =
2184                conn
2185                |> post("/api/v1/accounts/#{other_user_id}/remove_from_followers")
2186                |> json_response_and_validate_schema(200)
2187
2188       refute User.following?(other_user, user)
2189     end
2190
2191     test "removing remote user from followers", %{conn: conn, user: user} do
2192       %{id: other_user_id} = other_user = insert(:user, local: false)
2193
2194       CommonAPI.follow(other_user, user)
2195
2196       assert User.following?(other_user, user)
2197
2198       assert %{"id" => ^other_user_id, "followed_by" => false} =
2199                conn
2200                |> post("/api/v1/accounts/#{other_user_id}/remove_from_followers")
2201                |> json_response_and_validate_schema(200)
2202
2203       refute User.following?(other_user, user)
2204     end
2205
2206     test "removing user from followers errors", %{user: user, conn: conn} do
2207       # self remove
2208       conn_res = post(conn, "/api/v1/accounts/#{user.id}/remove_from_followers")
2209
2210       assert %{"error" => "Can not unfollow yourself"} =
2211                json_response_and_validate_schema(conn_res, 400)
2212
2213       # remove non existing user
2214       conn_res = post(conn, "/api/v1/accounts/doesntexist/remove_from_followers")
2215       assert %{"error" => "Record not found"} = json_response_and_validate_schema(conn_res, 404)
2216     end
2217   end
2218 end