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