restrict_unauthenticated setting
[akkoma] / test / web / mastodon_api / controllers / account_controller_test.exs
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2020 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.Config
9 alias Pleroma.Repo
10 alias Pleroma.User
11 alias Pleroma.Web.ActivityPub.ActivityPub
12 alias Pleroma.Web.ActivityPub.InternalFetchActor
13 alias Pleroma.Web.CommonAPI
14 alias Pleroma.Web.OAuth.Token
15
16 import Pleroma.Factory
17
18 describe "account fetching" do
19 clear_config([:instance, :limit_to_local_content])
20
21 test "works by id" do
22 user = insert(:user)
23
24 conn =
25 build_conn()
26 |> get("/api/v1/accounts/#{user.id}")
27
28 assert %{"id" => id} = json_response(conn, 200)
29 assert id == to_string(user.id)
30
31 conn =
32 build_conn()
33 |> get("/api/v1/accounts/-1")
34
35 assert %{"error" => "Can't find user"} = json_response(conn, 404)
36 end
37
38 test "works by nickname" do
39 user = insert(:user)
40
41 conn =
42 build_conn()
43 |> get("/api/v1/accounts/#{user.nickname}")
44
45 assert %{"id" => id} = json_response(conn, 200)
46 assert id == user.id
47 end
48
49 test "works by nickname for remote users" do
50 Config.put([:instance, :limit_to_local_content], false)
51 user = insert(:user, nickname: "user@example.com", local: false)
52
53 conn =
54 build_conn()
55 |> get("/api/v1/accounts/#{user.nickname}")
56
57 assert %{"id" => id} = json_response(conn, 200)
58 assert id == user.id
59 end
60
61 test "respects limit_to_local_content == :all for remote user nicknames" do
62 Config.put([:instance, :limit_to_local_content], :all)
63
64 user = insert(:user, nickname: "user@example.com", local: false)
65
66 conn =
67 build_conn()
68 |> get("/api/v1/accounts/#{user.nickname}")
69
70 assert json_response(conn, 404)
71 end
72
73 test "respects limit_to_local_content == :unauthenticated for remote user nicknames" do
74 Config.put([:instance, :limit_to_local_content], :unauthenticated)
75
76 user = insert(:user, nickname: "user@example.com", local: false)
77 reading_user = insert(:user)
78
79 conn =
80 build_conn()
81 |> get("/api/v1/accounts/#{user.nickname}")
82
83 assert json_response(conn, 404)
84
85 conn =
86 build_conn()
87 |> assign(:user, reading_user)
88 |> assign(:token, insert(:oauth_token, user: reading_user, scopes: ["read:accounts"]))
89 |> get("/api/v1/accounts/#{user.nickname}")
90
91 assert %{"id" => id} = json_response(conn, 200)
92 assert id == user.id
93 end
94
95 test "accounts fetches correct account for nicknames beginning with numbers", %{conn: conn} do
96 # Need to set an old-style integer ID to reproduce the problem
97 # (these are no longer assigned to new accounts but were preserved
98 # for existing accounts during the migration to flakeIDs)
99 user_one = insert(:user, %{id: 1212})
100 user_two = insert(:user, %{nickname: "#{user_one.id}garbage"})
101
102 resp_one =
103 conn
104 |> get("/api/v1/accounts/#{user_one.id}")
105
106 resp_two =
107 conn
108 |> get("/api/v1/accounts/#{user_two.nickname}")
109
110 resp_three =
111 conn
112 |> get("/api/v1/accounts/#{user_two.id}")
113
114 acc_one = json_response(resp_one, 200)
115 acc_two = json_response(resp_two, 200)
116 acc_three = json_response(resp_three, 200)
117 refute acc_one == acc_two
118 assert acc_two == acc_three
119 end
120
121 test "returns 404 when user is invisible", %{conn: conn} do
122 user = insert(:user, %{invisible: true})
123
124 resp =
125 conn
126 |> get("/api/v1/accounts/#{user.nickname}")
127 |> json_response(404)
128
129 assert %{"error" => "Can't find user"} = resp
130 end
131
132 test "returns 404 for internal.fetch actor", %{conn: conn} do
133 %User{nickname: "internal.fetch"} = InternalFetchActor.get_actor()
134
135 resp =
136 conn
137 |> get("/api/v1/accounts/internal.fetch")
138 |> json_response(404)
139
140 assert %{"error" => "Can't find user"} = resp
141 end
142 end
143
144 defp local_and_remote_users do
145 local = insert(:user)
146 remote = insert(:user, local: false)
147 {:ok, local: local, remote: remote}
148 end
149
150 describe "user fetching with restrict unauthenticated profiles for local and remote" do
151 setup do: local_and_remote_users()
152
153 clear_config([:restrict_unauthenticated, :profiles, :local]) do
154 Config.put([:restrict_unauthenticated, :profiles, :local], true)
155 end
156
157 clear_config([:restrict_unauthenticated, :profiles, :remote]) do
158 Config.put([:restrict_unauthenticated, :profiles, :remote], true)
159 end
160
161 test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do
162 res_conn = get(conn, "/api/v1/accounts/#{local.id}")
163
164 assert json_response(res_conn, :not_found) == %{
165 "error" => "Can't find user"
166 }
167
168 res_conn = get(conn, "/api/v1/accounts/#{remote.id}")
169
170 assert json_response(res_conn, :not_found) == %{
171 "error" => "Can't find user"
172 }
173 end
174
175 test "if user is authenticated", %{local: local, remote: remote} do
176 %{conn: conn} = oauth_access(["read"])
177
178 res_conn = get(conn, "/api/v1/accounts/#{local.id}")
179 assert %{"id" => _} = json_response(res_conn, 200)
180
181 res_conn = get(conn, "/api/v1/accounts/#{remote.id}")
182 assert %{"id" => _} = json_response(res_conn, 200)
183 end
184 end
185
186 describe "user fetching with restrict unauthenticated profiles for local" do
187 setup do: local_and_remote_users()
188
189 clear_config([:restrict_unauthenticated, :profiles, :local]) do
190 Config.put([:restrict_unauthenticated, :profiles, :local], true)
191 end
192
193 test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do
194 res_conn = get(conn, "/api/v1/accounts/#{local.id}")
195
196 assert json_response(res_conn, :not_found) == %{
197 "error" => "Can't find user"
198 }
199
200 res_conn = get(conn, "/api/v1/accounts/#{remote.id}")
201 assert %{"id" => _} = json_response(res_conn, 200)
202 end
203
204 test "if user is authenticated", %{local: local, remote: remote} do
205 %{conn: conn} = oauth_access(["read"])
206
207 res_conn = get(conn, "/api/v1/accounts/#{local.id}")
208 assert %{"id" => _} = json_response(res_conn, 200)
209
210 res_conn = get(conn, "/api/v1/accounts/#{remote.id}")
211 assert %{"id" => _} = json_response(res_conn, 200)
212 end
213 end
214
215 describe "user fetching with restrict unauthenticated profiles for remote" do
216 setup do: local_and_remote_users()
217
218 clear_config([:restrict_unauthenticated, :profiles, :remote]) do
219 Config.put([:restrict_unauthenticated, :profiles, :remote], true)
220 end
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 assert %{"id" => _} = json_response(res_conn, 200)
225
226 res_conn = get(conn, "/api/v1/accounts/#{remote.id}")
227
228 assert json_response(res_conn, :not_found) == %{
229 "error" => "Can't find user"
230 }
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(res_conn, 200)
238
239 res_conn = get(conn, "/api/v1/accounts/#{remote.id}")
240 assert %{"id" => _} = json_response(res_conn, 200)
241 end
242 end
243
244 describe "user timelines" do
245 setup do: oauth_access(["read:statuses"])
246
247 test "respects blocks", %{user: user_one, conn: conn} do
248 user_two = insert(:user)
249 user_three = insert(:user)
250
251 User.block(user_one, user_two)
252
253 {:ok, activity} = CommonAPI.post(user_two, %{"status" => "User one sux0rz"})
254 {:ok, repeat, _} = CommonAPI.repeat(activity.id, user_three)
255
256 resp = get(conn, "/api/v1/accounts/#{user_two.id}/statuses")
257
258 assert [%{"id" => id}] = json_response(resp, 200)
259 assert id == activity.id
260
261 # Even a blocked user will deliver the full user timeline, there would be
262 # no point in looking at a blocked users timeline otherwise
263 resp = get(conn, "/api/v1/accounts/#{user_two.id}/statuses")
264
265 assert [%{"id" => id}] = json_response(resp, 200)
266 assert id == activity.id
267
268 # Third user's timeline includes the repeat when viewed by unauthenticated user
269 resp = get(build_conn(), "/api/v1/accounts/#{user_three.id}/statuses")
270 assert [%{"id" => id}] = json_response(resp, 200)
271 assert id == repeat.id
272
273 # When viewing a third user's timeline, the blocked users' statuses will NOT be shown
274 resp = get(conn, "/api/v1/accounts/#{user_three.id}/statuses")
275
276 assert [] = json_response(resp, 200)
277 end
278
279 test "gets users statuses", %{conn: conn} do
280 user_one = insert(:user)
281 user_two = insert(:user)
282 user_three = insert(:user)
283
284 {:ok, _user_three} = User.follow(user_three, user_one)
285
286 {:ok, activity} = CommonAPI.post(user_one, %{"status" => "HI!!!"})
287
288 {:ok, direct_activity} =
289 CommonAPI.post(user_one, %{
290 "status" => "Hi, @#{user_two.nickname}.",
291 "visibility" => "direct"
292 })
293
294 {:ok, private_activity} =
295 CommonAPI.post(user_one, %{"status" => "private", "visibility" => "private"})
296
297 resp = get(conn, "/api/v1/accounts/#{user_one.id}/statuses")
298
299 assert [%{"id" => id}] = json_response(resp, 200)
300 assert id == to_string(activity.id)
301
302 resp =
303 conn
304 |> assign(:user, user_two)
305 |> assign(:token, insert(:oauth_token, user: user_two, scopes: ["read:statuses"]))
306 |> get("/api/v1/accounts/#{user_one.id}/statuses")
307
308 assert [%{"id" => id_one}, %{"id" => id_two}] = json_response(resp, 200)
309 assert id_one == to_string(direct_activity.id)
310 assert id_two == to_string(activity.id)
311
312 resp =
313 conn
314 |> assign(:user, user_three)
315 |> assign(:token, insert(:oauth_token, user: user_three, scopes: ["read:statuses"]))
316 |> get("/api/v1/accounts/#{user_one.id}/statuses")
317
318 assert [%{"id" => id_one}, %{"id" => id_two}] = json_response(resp, 200)
319 assert id_one == to_string(private_activity.id)
320 assert id_two == to_string(activity.id)
321 end
322
323 test "unimplemented pinned statuses feature", %{conn: conn} do
324 note = insert(:note_activity)
325 user = User.get_cached_by_ap_id(note.data["actor"])
326
327 conn = get(conn, "/api/v1/accounts/#{user.id}/statuses?pinned=true")
328
329 assert json_response(conn, 200) == []
330 end
331
332 test "gets an users media", %{conn: conn} do
333 note = insert(:note_activity)
334 user = User.get_cached_by_ap_id(note.data["actor"])
335
336 file = %Plug.Upload{
337 content_type: "image/jpg",
338 path: Path.absname("test/fixtures/image.jpg"),
339 filename: "an_image.jpg"
340 }
341
342 {:ok, %{id: media_id}} = ActivityPub.upload(file, actor: user.ap_id)
343
344 {:ok, image_post} = CommonAPI.post(user, %{"status" => "cofe", "media_ids" => [media_id]})
345
346 conn = get(conn, "/api/v1/accounts/#{user.id}/statuses", %{"only_media" => "true"})
347
348 assert [%{"id" => id}] = json_response(conn, 200)
349 assert id == to_string(image_post.id)
350
351 conn = get(build_conn(), "/api/v1/accounts/#{user.id}/statuses", %{"only_media" => "1"})
352
353 assert [%{"id" => id}] = json_response(conn, 200)
354 assert id == to_string(image_post.id)
355 end
356
357 test "gets a user's statuses without reblogs", %{user: user, conn: conn} do
358 {:ok, post} = CommonAPI.post(user, %{"status" => "HI!!!"})
359 {:ok, _, _} = CommonAPI.repeat(post.id, user)
360
361 conn = get(conn, "/api/v1/accounts/#{user.id}/statuses", %{"exclude_reblogs" => "true"})
362
363 assert [%{"id" => id}] = json_response(conn, 200)
364 assert id == to_string(post.id)
365
366 conn = get(conn, "/api/v1/accounts/#{user.id}/statuses", %{"exclude_reblogs" => "1"})
367
368 assert [%{"id" => id}] = json_response(conn, 200)
369 assert id == to_string(post.id)
370 end
371
372 test "filters user's statuses by a hashtag", %{user: user, conn: conn} do
373 {:ok, post} = CommonAPI.post(user, %{"status" => "#hashtag"})
374 {:ok, _post} = CommonAPI.post(user, %{"status" => "hashtag"})
375
376 conn = get(conn, "/api/v1/accounts/#{user.id}/statuses", %{"tagged" => "hashtag"})
377
378 assert [%{"id" => id}] = json_response(conn, 200)
379 assert id == to_string(post.id)
380 end
381
382 test "the user views their own timelines and excludes direct messages", %{
383 user: user,
384 conn: conn
385 } do
386 {:ok, public_activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "public"})
387 {:ok, _direct_activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "direct"})
388
389 conn =
390 get(conn, "/api/v1/accounts/#{user.id}/statuses", %{"exclude_visibilities" => ["direct"]})
391
392 assert [%{"id" => id}] = json_response(conn, 200)
393 assert id == to_string(public_activity.id)
394 end
395 end
396
397 defp local_and_remote_activities(%{local: local, remote: remote}) do
398 insert(:note_activity, user: local)
399 insert(:note_activity, user: remote, local: false)
400
401 :ok
402 end
403
404 describe "statuses with restrict unauthenticated profiles for local and remote" do
405 setup do: local_and_remote_users()
406 setup :local_and_remote_activities
407
408 clear_config([:restrict_unauthenticated, :profiles, :local]) do
409 Config.put([:restrict_unauthenticated, :profiles, :local], true)
410 end
411
412 clear_config([:restrict_unauthenticated, :profiles, :remote]) do
413 Config.put([:restrict_unauthenticated, :profiles, :remote], true)
414 end
415
416 test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do
417 res_conn = get(conn, "/api/v1/accounts/#{local.id}/statuses")
418
419 assert json_response(res_conn, :not_found) == %{
420 "error" => "Can't find user"
421 }
422
423 res_conn = get(conn, "/api/v1/accounts/#{remote.id}/statuses")
424
425 assert json_response(res_conn, :not_found) == %{
426 "error" => "Can't find user"
427 }
428 end
429
430 test "if user is authenticated", %{local: local, remote: remote} do
431 %{conn: conn} = oauth_access(["read"])
432
433 res_conn = get(conn, "/api/v1/accounts/#{local.id}/statuses")
434 assert length(json_response(res_conn, 200)) == 1
435
436 res_conn = get(conn, "/api/v1/accounts/#{remote.id}/statuses")
437 assert length(json_response(res_conn, 200)) == 1
438 end
439 end
440
441 describe "statuses with restrict unauthenticated profiles for local" do
442 setup do: local_and_remote_users()
443 setup :local_and_remote_activities
444
445 clear_config([:restrict_unauthenticated, :profiles, :local]) do
446 Config.put([:restrict_unauthenticated, :profiles, :local], true)
447 end
448
449 test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do
450 res_conn = get(conn, "/api/v1/accounts/#{local.id}/statuses")
451
452 assert json_response(res_conn, :not_found) == %{
453 "error" => "Can't find user"
454 }
455
456 res_conn = get(conn, "/api/v1/accounts/#{remote.id}/statuses")
457 assert length(json_response(res_conn, 200)) == 1
458 end
459
460 test "if user is authenticated", %{local: local, remote: remote} do
461 %{conn: conn} = oauth_access(["read"])
462
463 res_conn = get(conn, "/api/v1/accounts/#{local.id}/statuses")
464 assert length(json_response(res_conn, 200)) == 1
465
466 res_conn = get(conn, "/api/v1/accounts/#{remote.id}/statuses")
467 assert length(json_response(res_conn, 200)) == 1
468 end
469 end
470
471 describe "statuses with restrict unauthenticated profiles for remote" do
472 setup do: local_and_remote_users()
473 setup :local_and_remote_activities
474
475 clear_config([:restrict_unauthenticated, :profiles, :remote]) do
476 Config.put([:restrict_unauthenticated, :profiles, :remote], true)
477 end
478
479 test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do
480 res_conn = get(conn, "/api/v1/accounts/#{local.id}/statuses")
481 assert length(json_response(res_conn, 200)) == 1
482
483 res_conn = get(conn, "/api/v1/accounts/#{remote.id}/statuses")
484
485 assert json_response(res_conn, :not_found) == %{
486 "error" => "Can't find user"
487 }
488 end
489
490 test "if user is authenticated", %{local: local, remote: remote} do
491 %{conn: conn} = oauth_access(["read"])
492
493 res_conn = get(conn, "/api/v1/accounts/#{local.id}/statuses")
494 assert length(json_response(res_conn, 200)) == 1
495
496 res_conn = get(conn, "/api/v1/accounts/#{remote.id}/statuses")
497 assert length(json_response(res_conn, 200)) == 1
498 end
499 end
500
501 describe "followers" do
502 setup do: oauth_access(["read:accounts"])
503
504 test "getting followers", %{user: user, conn: conn} do
505 other_user = insert(:user)
506 {:ok, user} = User.follow(user, other_user)
507
508 conn = get(conn, "/api/v1/accounts/#{other_user.id}/followers")
509
510 assert [%{"id" => id}] = json_response(conn, 200)
511 assert id == to_string(user.id)
512 end
513
514 test "getting followers, hide_followers", %{user: user, conn: conn} do
515 other_user = insert(:user, hide_followers: true)
516 {:ok, _user} = User.follow(user, other_user)
517
518 conn = get(conn, "/api/v1/accounts/#{other_user.id}/followers")
519
520 assert [] == json_response(conn, 200)
521 end
522
523 test "getting followers, hide_followers, same user requesting" do
524 user = insert(:user)
525 other_user = insert(:user, hide_followers: true)
526 {:ok, _user} = User.follow(user, other_user)
527
528 conn =
529 build_conn()
530 |> assign(:user, other_user)
531 |> assign(:token, insert(:oauth_token, user: other_user, scopes: ["read:accounts"]))
532 |> get("/api/v1/accounts/#{other_user.id}/followers")
533
534 refute [] == json_response(conn, 200)
535 end
536
537 test "getting followers, pagination", %{user: user, conn: conn} do
538 follower1 = insert(:user)
539 follower2 = insert(:user)
540 follower3 = insert(:user)
541 {:ok, _} = User.follow(follower1, user)
542 {:ok, _} = User.follow(follower2, user)
543 {:ok, _} = User.follow(follower3, user)
544
545 res_conn = get(conn, "/api/v1/accounts/#{user.id}/followers?since_id=#{follower1.id}")
546
547 assert [%{"id" => id3}, %{"id" => id2}] = json_response(res_conn, 200)
548 assert id3 == follower3.id
549 assert id2 == follower2.id
550
551 res_conn = get(conn, "/api/v1/accounts/#{user.id}/followers?max_id=#{follower3.id}")
552
553 assert [%{"id" => id2}, %{"id" => id1}] = json_response(res_conn, 200)
554 assert id2 == follower2.id
555 assert id1 == follower1.id
556
557 res_conn = get(conn, "/api/v1/accounts/#{user.id}/followers?limit=1&max_id=#{follower3.id}")
558
559 assert [%{"id" => id2}] = json_response(res_conn, 200)
560 assert id2 == follower2.id
561
562 assert [link_header] = get_resp_header(res_conn, "link")
563 assert link_header =~ ~r/min_id=#{follower2.id}/
564 assert link_header =~ ~r/max_id=#{follower2.id}/
565 end
566 end
567
568 describe "following" do
569 setup do: oauth_access(["read:accounts"])
570
571 test "getting following", %{user: user, conn: conn} do
572 other_user = insert(:user)
573 {:ok, user} = User.follow(user, other_user)
574
575 conn = get(conn, "/api/v1/accounts/#{user.id}/following")
576
577 assert [%{"id" => id}] = json_response(conn, 200)
578 assert id == to_string(other_user.id)
579 end
580
581 test "getting following, hide_follows, other user requesting" do
582 user = insert(:user, hide_follows: true)
583 other_user = insert(:user)
584 {:ok, user} = User.follow(user, other_user)
585
586 conn =
587 build_conn()
588 |> assign(:user, other_user)
589 |> assign(:token, insert(:oauth_token, user: other_user, scopes: ["read:accounts"]))
590 |> get("/api/v1/accounts/#{user.id}/following")
591
592 assert [] == json_response(conn, 200)
593 end
594
595 test "getting following, hide_follows, same user requesting" do
596 user = insert(:user, hide_follows: true)
597 other_user = insert(:user)
598 {:ok, user} = User.follow(user, other_user)
599
600 conn =
601 build_conn()
602 |> assign(:user, user)
603 |> assign(:token, insert(:oauth_token, user: user, scopes: ["read:accounts"]))
604 |> get("/api/v1/accounts/#{user.id}/following")
605
606 refute [] == json_response(conn, 200)
607 end
608
609 test "getting following, pagination", %{user: user, conn: conn} do
610 following1 = insert(:user)
611 following2 = insert(:user)
612 following3 = insert(:user)
613 {:ok, _} = User.follow(user, following1)
614 {:ok, _} = User.follow(user, following2)
615 {:ok, _} = User.follow(user, following3)
616
617 res_conn = get(conn, "/api/v1/accounts/#{user.id}/following?since_id=#{following1.id}")
618
619 assert [%{"id" => id3}, %{"id" => id2}] = json_response(res_conn, 200)
620 assert id3 == following3.id
621 assert id2 == following2.id
622
623 res_conn = get(conn, "/api/v1/accounts/#{user.id}/following?max_id=#{following3.id}")
624
625 assert [%{"id" => id2}, %{"id" => id1}] = json_response(res_conn, 200)
626 assert id2 == following2.id
627 assert id1 == following1.id
628
629 res_conn =
630 get(conn, "/api/v1/accounts/#{user.id}/following?limit=1&max_id=#{following3.id}")
631
632 assert [%{"id" => id2}] = json_response(res_conn, 200)
633 assert id2 == following2.id
634
635 assert [link_header] = get_resp_header(res_conn, "link")
636 assert link_header =~ ~r/min_id=#{following2.id}/
637 assert link_header =~ ~r/max_id=#{following2.id}/
638 end
639 end
640
641 describe "follow/unfollow" do
642 setup do: oauth_access(["follow"])
643
644 test "following / unfollowing a user", %{conn: conn} do
645 other_user = insert(:user)
646
647 ret_conn = post(conn, "/api/v1/accounts/#{other_user.id}/follow")
648
649 assert %{"id" => _id, "following" => true} = json_response(ret_conn, 200)
650
651 ret_conn = post(conn, "/api/v1/accounts/#{other_user.id}/unfollow")
652
653 assert %{"id" => _id, "following" => false} = json_response(ret_conn, 200)
654
655 conn = post(conn, "/api/v1/follows", %{"uri" => other_user.nickname})
656
657 assert %{"id" => id} = json_response(conn, 200)
658 assert id == to_string(other_user.id)
659 end
660
661 test "cancelling follow request", %{conn: conn} do
662 %{id: other_user_id} = insert(:user, %{locked: true})
663
664 assert %{"id" => ^other_user_id, "following" => false, "requested" => true} =
665 conn |> post("/api/v1/accounts/#{other_user_id}/follow") |> json_response(:ok)
666
667 assert %{"id" => ^other_user_id, "following" => false, "requested" => false} =
668 conn |> post("/api/v1/accounts/#{other_user_id}/unfollow") |> json_response(:ok)
669 end
670
671 test "following without reblogs" do
672 %{conn: conn} = oauth_access(["follow", "read:statuses"])
673 followed = insert(:user)
674 other_user = insert(:user)
675
676 ret_conn = post(conn, "/api/v1/accounts/#{followed.id}/follow?reblogs=false")
677
678 assert %{"showing_reblogs" => false} = json_response(ret_conn, 200)
679
680 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "hey"})
681 {:ok, reblog, _} = CommonAPI.repeat(activity.id, followed)
682
683 ret_conn = get(conn, "/api/v1/timelines/home")
684
685 assert [] == json_response(ret_conn, 200)
686
687 ret_conn = post(conn, "/api/v1/accounts/#{followed.id}/follow?reblogs=true")
688
689 assert %{"showing_reblogs" => true} = json_response(ret_conn, 200)
690
691 conn = get(conn, "/api/v1/timelines/home")
692
693 expected_activity_id = reblog.id
694 assert [%{"id" => ^expected_activity_id}] = json_response(conn, 200)
695 end
696
697 test "following / unfollowing errors", %{user: user, conn: conn} do
698 # self follow
699 conn_res = post(conn, "/api/v1/accounts/#{user.id}/follow")
700 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
701
702 # self unfollow
703 user = User.get_cached_by_id(user.id)
704 conn_res = post(conn, "/api/v1/accounts/#{user.id}/unfollow")
705 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
706
707 # self follow via uri
708 user = User.get_cached_by_id(user.id)
709 conn_res = post(conn, "/api/v1/follows", %{"uri" => user.nickname})
710 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
711
712 # follow non existing user
713 conn_res = post(conn, "/api/v1/accounts/doesntexist/follow")
714 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
715
716 # follow non existing user via uri
717 conn_res = post(conn, "/api/v1/follows", %{"uri" => "doesntexist"})
718 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
719
720 # unfollow non existing user
721 conn_res = post(conn, "/api/v1/accounts/doesntexist/unfollow")
722 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
723 end
724 end
725
726 describe "mute/unmute" do
727 setup do: oauth_access(["write:mutes"])
728
729 test "with notifications", %{conn: conn} do
730 other_user = insert(:user)
731
732 ret_conn = post(conn, "/api/v1/accounts/#{other_user.id}/mute")
733
734 response = json_response(ret_conn, 200)
735
736 assert %{"id" => _id, "muting" => true, "muting_notifications" => true} = response
737
738 conn = post(conn, "/api/v1/accounts/#{other_user.id}/unmute")
739
740 response = json_response(conn, 200)
741 assert %{"id" => _id, "muting" => false, "muting_notifications" => false} = response
742 end
743
744 test "without notifications", %{conn: conn} do
745 other_user = insert(:user)
746
747 ret_conn =
748 post(conn, "/api/v1/accounts/#{other_user.id}/mute", %{"notifications" => "false"})
749
750 response = json_response(ret_conn, 200)
751
752 assert %{"id" => _id, "muting" => true, "muting_notifications" => false} = response
753
754 conn = post(conn, "/api/v1/accounts/#{other_user.id}/unmute")
755
756 response = json_response(conn, 200)
757 assert %{"id" => _id, "muting" => false, "muting_notifications" => false} = response
758 end
759 end
760
761 describe "pinned statuses" do
762 setup do
763 user = insert(:user)
764 {:ok, activity} = CommonAPI.post(user, %{"status" => "HI!!!"})
765 %{conn: conn} = oauth_access(["read:statuses"], user: user)
766
767 [conn: conn, user: user, activity: activity]
768 end
769
770 test "returns pinned statuses", %{conn: conn, user: user, activity: activity} do
771 {:ok, _} = CommonAPI.pin(activity.id, user)
772
773 result =
774 conn
775 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
776 |> json_response(200)
777
778 id_str = to_string(activity.id)
779
780 assert [%{"id" => ^id_str, "pinned" => true}] = result
781 end
782 end
783
784 test "blocking / unblocking a user" do
785 %{conn: conn} = oauth_access(["follow"])
786 other_user = insert(:user)
787
788 ret_conn = post(conn, "/api/v1/accounts/#{other_user.id}/block")
789
790 assert %{"id" => _id, "blocking" => true} = json_response(ret_conn, 200)
791
792 conn = post(conn, "/api/v1/accounts/#{other_user.id}/unblock")
793
794 assert %{"id" => _id, "blocking" => false} = json_response(conn, 200)
795 end
796
797 describe "create account by app" do
798 setup do
799 valid_params = %{
800 username: "lain",
801 email: "lain@example.org",
802 password: "PlzDontHackLain",
803 agreement: true
804 }
805
806 [valid_params: valid_params]
807 end
808
809 clear_config([:instance, :account_activation_required])
810
811 test "Account registration via Application", %{conn: conn} do
812 conn =
813 post(conn, "/api/v1/apps", %{
814 client_name: "client_name",
815 redirect_uris: "urn:ietf:wg:oauth:2.0:oob",
816 scopes: "read, write, follow"
817 })
818
819 %{
820 "client_id" => client_id,
821 "client_secret" => client_secret,
822 "id" => _,
823 "name" => "client_name",
824 "redirect_uri" => "urn:ietf:wg:oauth:2.0:oob",
825 "vapid_key" => _,
826 "website" => nil
827 } = json_response(conn, 200)
828
829 conn =
830 post(conn, "/oauth/token", %{
831 grant_type: "client_credentials",
832 client_id: client_id,
833 client_secret: client_secret
834 })
835
836 assert %{"access_token" => token, "refresh_token" => refresh, "scope" => scope} =
837 json_response(conn, 200)
838
839 assert token
840 token_from_db = Repo.get_by(Token, token: token)
841 assert token_from_db
842 assert refresh
843 assert scope == "read write follow"
844
845 conn =
846 build_conn()
847 |> put_req_header("authorization", "Bearer " <> token)
848 |> post("/api/v1/accounts", %{
849 username: "lain",
850 email: "lain@example.org",
851 password: "PlzDontHackLain",
852 bio: "Test Bio",
853 agreement: true
854 })
855
856 %{
857 "access_token" => token,
858 "created_at" => _created_at,
859 "scope" => _scope,
860 "token_type" => "Bearer"
861 } = json_response(conn, 200)
862
863 token_from_db = Repo.get_by(Token, token: token)
864 assert token_from_db
865 token_from_db = Repo.preload(token_from_db, :user)
866 assert token_from_db.user
867
868 assert token_from_db.user.confirmation_pending
869 end
870
871 test "returns error when user already registred", %{conn: conn, valid_params: valid_params} do
872 _user = insert(:user, email: "lain@example.org")
873 app_token = insert(:oauth_token, user: nil)
874
875 conn =
876 conn
877 |> put_req_header("authorization", "Bearer " <> app_token.token)
878
879 res = post(conn, "/api/v1/accounts", valid_params)
880 assert json_response(res, 400) == %{"error" => "{\"email\":[\"has already been taken\"]}"}
881 end
882
883 test "returns bad_request if missing required params", %{
884 conn: conn,
885 valid_params: valid_params
886 } do
887 app_token = insert(:oauth_token, user: nil)
888
889 conn = put_req_header(conn, "authorization", "Bearer " <> app_token.token)
890
891 res = post(conn, "/api/v1/accounts", valid_params)
892 assert json_response(res, 200)
893
894 [{127, 0, 0, 1}, {127, 0, 0, 2}, {127, 0, 0, 3}, {127, 0, 0, 4}]
895 |> Stream.zip(Map.delete(valid_params, :email))
896 |> Enum.each(fn {ip, {attr, _}} ->
897 res =
898 conn
899 |> Map.put(:remote_ip, ip)
900 |> post("/api/v1/accounts", Map.delete(valid_params, attr))
901 |> json_response(400)
902
903 assert res == %{"error" => "Missing parameters"}
904 end)
905 end
906
907 clear_config([:instance, :account_activation_required])
908
909 test "returns bad_request if missing email params when :account_activation_required is enabled",
910 %{conn: conn, valid_params: valid_params} do
911 Pleroma.Config.put([:instance, :account_activation_required], true)
912
913 app_token = insert(:oauth_token, user: nil)
914 conn = put_req_header(conn, "authorization", "Bearer " <> app_token.token)
915
916 res =
917 conn
918 |> Map.put(:remote_ip, {127, 0, 0, 5})
919 |> post("/api/v1/accounts", Map.delete(valid_params, :email))
920
921 assert json_response(res, 400) == %{"error" => "Missing parameters"}
922
923 res =
924 conn
925 |> Map.put(:remote_ip, {127, 0, 0, 6})
926 |> post("/api/v1/accounts", Map.put(valid_params, :email, ""))
927
928 assert json_response(res, 400) == %{"error" => "{\"email\":[\"can't be blank\"]}"}
929 end
930
931 test "allow registration without an email", %{conn: conn, valid_params: valid_params} do
932 app_token = insert(:oauth_token, user: nil)
933 conn = put_req_header(conn, "authorization", "Bearer " <> app_token.token)
934
935 res =
936 conn
937 |> Map.put(:remote_ip, {127, 0, 0, 7})
938 |> post("/api/v1/accounts", Map.delete(valid_params, :email))
939
940 assert json_response(res, 200)
941 end
942
943 test "allow registration with an empty email", %{conn: conn, valid_params: valid_params} do
944 app_token = insert(:oauth_token, user: nil)
945 conn = put_req_header(conn, "authorization", "Bearer " <> app_token.token)
946
947 res =
948 conn
949 |> Map.put(:remote_ip, {127, 0, 0, 8})
950 |> post("/api/v1/accounts", Map.put(valid_params, :email, ""))
951
952 assert json_response(res, 200)
953 end
954
955 test "returns forbidden if token is invalid", %{conn: conn, valid_params: valid_params} do
956 conn = put_req_header(conn, "authorization", "Bearer " <> "invalid-token")
957
958 res = post(conn, "/api/v1/accounts", valid_params)
959 assert json_response(res, 403) == %{"error" => "Invalid credentials"}
960 end
961 end
962
963 describe "create account by app / rate limit" do
964 clear_config([:rate_limit, :app_account_creation]) do
965 Config.put([:rate_limit, :app_account_creation], {10_000, 2})
966 end
967
968 test "respects rate limit setting", %{conn: conn} do
969 app_token = insert(:oauth_token, user: nil)
970
971 conn =
972 conn
973 |> put_req_header("authorization", "Bearer " <> app_token.token)
974 |> Map.put(:remote_ip, {15, 15, 15, 15})
975
976 for i <- 1..2 do
977 conn =
978 post(conn, "/api/v1/accounts", %{
979 username: "#{i}lain",
980 email: "#{i}lain@example.org",
981 password: "PlzDontHackLain",
982 agreement: true
983 })
984
985 %{
986 "access_token" => token,
987 "created_at" => _created_at,
988 "scope" => _scope,
989 "token_type" => "Bearer"
990 } = json_response(conn, 200)
991
992 token_from_db = Repo.get_by(Token, token: token)
993 assert token_from_db
994 token_from_db = Repo.preload(token_from_db, :user)
995 assert token_from_db.user
996
997 assert token_from_db.user.confirmation_pending
998 end
999
1000 conn =
1001 post(conn, "/api/v1/accounts", %{
1002 username: "6lain",
1003 email: "6lain@example.org",
1004 password: "PlzDontHackLain",
1005 agreement: true
1006 })
1007
1008 assert json_response(conn, :too_many_requests) == %{"error" => "Throttled"}
1009 end
1010 end
1011
1012 describe "GET /api/v1/accounts/:id/lists - account_lists" do
1013 test "returns lists to which the account belongs" do
1014 %{user: user, conn: conn} = oauth_access(["read:lists"])
1015 other_user = insert(:user)
1016 assert {:ok, %Pleroma.List{} = list} = Pleroma.List.create("Test List", user)
1017 {:ok, %{following: _following}} = Pleroma.List.follow(list, other_user)
1018
1019 res =
1020 conn
1021 |> get("/api/v1/accounts/#{other_user.id}/lists")
1022 |> json_response(200)
1023
1024 assert res == [%{"id" => to_string(list.id), "title" => "Test List"}]
1025 end
1026 end
1027
1028 describe "verify_credentials" do
1029 test "verify_credentials" do
1030 %{user: user, conn: conn} = oauth_access(["read:accounts"])
1031 conn = get(conn, "/api/v1/accounts/verify_credentials")
1032
1033 response = json_response(conn, 200)
1034
1035 assert %{"id" => id, "source" => %{"privacy" => "public"}} = response
1036 assert response["pleroma"]["chat_token"]
1037 assert id == to_string(user.id)
1038 end
1039
1040 test "verify_credentials default scope unlisted" do
1041 user = insert(:user, default_scope: "unlisted")
1042 %{conn: conn} = oauth_access(["read:accounts"], user: user)
1043
1044 conn = get(conn, "/api/v1/accounts/verify_credentials")
1045
1046 assert %{"id" => id, "source" => %{"privacy" => "unlisted"}} = json_response(conn, 200)
1047 assert id == to_string(user.id)
1048 end
1049
1050 test "locked accounts" do
1051 user = insert(:user, default_scope: "private")
1052 %{conn: conn} = oauth_access(["read:accounts"], user: user)
1053
1054 conn = get(conn, "/api/v1/accounts/verify_credentials")
1055
1056 assert %{"id" => id, "source" => %{"privacy" => "private"}} = json_response(conn, 200)
1057 assert id == to_string(user.id)
1058 end
1059 end
1060
1061 describe "user relationships" do
1062 setup do: oauth_access(["read:follows"])
1063
1064 test "returns the relationships for the current user", %{user: user, conn: conn} do
1065 other_user = insert(:user)
1066 {:ok, _user} = User.follow(user, other_user)
1067
1068 conn = get(conn, "/api/v1/accounts/relationships", %{"id" => [other_user.id]})
1069
1070 assert [relationship] = json_response(conn, 200)
1071
1072 assert to_string(other_user.id) == relationship["id"]
1073 end
1074
1075 test "returns an empty list on a bad request", %{conn: conn} do
1076 conn = get(conn, "/api/v1/accounts/relationships", %{})
1077
1078 assert [] = json_response(conn, 200)
1079 end
1080 end
1081
1082 test "getting a list of mutes" do
1083 %{user: user, conn: conn} = oauth_access(["read:mutes"])
1084 other_user = insert(:user)
1085
1086 {:ok, _user_relationships} = User.mute(user, other_user)
1087
1088 conn = get(conn, "/api/v1/mutes")
1089
1090 other_user_id = to_string(other_user.id)
1091 assert [%{"id" => ^other_user_id}] = json_response(conn, 200)
1092 end
1093
1094 test "getting a list of blocks" do
1095 %{user: user, conn: conn} = oauth_access(["read:blocks"])
1096 other_user = insert(:user)
1097
1098 {:ok, _user_relationship} = User.block(user, other_user)
1099
1100 conn =
1101 conn
1102 |> assign(:user, user)
1103 |> get("/api/v1/blocks")
1104
1105 other_user_id = to_string(other_user.id)
1106 assert [%{"id" => ^other_user_id}] = json_response(conn, 200)
1107 end
1108 end