Add test to validate profile pagination works with keyset
[akkoma] / test / pleroma / 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.Repo
9 alias Pleroma.User
10 alias Pleroma.Web.ActivityPub.ActivityPub
11 alias Pleroma.Web.ActivityPub.InternalFetchActor
12 alias Pleroma.Web.CommonAPI
13 alias Pleroma.Web.OAuth.Token
14
15 import Pleroma.Factory
16
17 describe "account fetching" do
18 test "works by id" do
19 %User{id: user_id} = insert(:user)
20
21 assert %{"id" => ^user_id} =
22 build_conn()
23 |> get("/api/v1/accounts/#{user_id}")
24 |> json_response_and_validate_schema(200)
25
26 assert %{"error" => "Can't find user"} =
27 build_conn()
28 |> get("/api/v1/accounts/-1")
29 |> json_response_and_validate_schema(404)
30 end
31
32 test "works by nickname" do
33 user = insert(:user)
34
35 assert %{"id" => _user_id} =
36 build_conn()
37 |> get("/api/v1/accounts/#{user.nickname}")
38 |> json_response_and_validate_schema(200)
39 end
40
41 test "works by nickname for remote users" do
42 clear_config([:instance, :limit_to_local_content], false)
43
44 user = insert(:user, nickname: "user@example.com", local: false)
45
46 assert %{"id" => _user_id} =
47 build_conn()
48 |> get("/api/v1/accounts/#{user.nickname}")
49 |> json_response_and_validate_schema(200)
50 end
51
52 test "respects limit_to_local_content == :all for remote user nicknames" do
53 clear_config([:instance, :limit_to_local_content], :all)
54
55 user = insert(:user, nickname: "user@example.com", local: false)
56
57 assert build_conn()
58 |> get("/api/v1/accounts/#{user.nickname}")
59 |> json_response_and_validate_schema(404)
60 end
61
62 test "respects limit_to_local_content == :unauthenticated for remote user nicknames" do
63 clear_config([:instance, :limit_to_local_content], :unauthenticated)
64
65 user = insert(:user, nickname: "user@example.com", local: false)
66 reading_user = insert(:user)
67
68 conn =
69 build_conn()
70 |> get("/api/v1/accounts/#{user.nickname}")
71
72 assert json_response_and_validate_schema(conn, 404)
73
74 conn =
75 build_conn()
76 |> assign(:user, reading_user)
77 |> assign(:token, insert(:oauth_token, user: reading_user, scopes: ["read:accounts"]))
78 |> get("/api/v1/accounts/#{user.nickname}")
79
80 assert %{"id" => id} = json_response_and_validate_schema(conn, 200)
81 assert id == user.id
82 end
83
84 test "accounts fetches correct account for nicknames beginning with numbers", %{conn: conn} do
85 # Need to set an old-style integer ID to reproduce the problem
86 # (these are no longer assigned to new accounts but were preserved
87 # for existing accounts during the migration to flakeIDs)
88 user_one = insert(:user, %{id: 1212})
89 user_two = insert(:user, %{nickname: "#{user_one.id}garbage"})
90
91 acc_one =
92 conn
93 |> get("/api/v1/accounts/#{user_one.id}")
94 |> json_response_and_validate_schema(:ok)
95
96 acc_two =
97 conn
98 |> get("/api/v1/accounts/#{user_two.nickname}")
99 |> json_response_and_validate_schema(:ok)
100
101 acc_three =
102 conn
103 |> get("/api/v1/accounts/#{user_two.id}")
104 |> json_response_and_validate_schema(:ok)
105
106 refute acc_one == acc_two
107 assert acc_two == acc_three
108 end
109
110 test "returns 404 when user is invisible", %{conn: conn} do
111 user = insert(:user, %{invisible: true})
112
113 assert %{"error" => "Can't find user"} =
114 conn
115 |> get("/api/v1/accounts/#{user.nickname}")
116 |> json_response_and_validate_schema(404)
117 end
118
119 test "returns 404 for internal.fetch actor", %{conn: conn} do
120 %User{nickname: "internal.fetch"} = InternalFetchActor.get_actor()
121
122 assert %{"error" => "Can't find user"} =
123 conn
124 |> get("/api/v1/accounts/internal.fetch")
125 |> json_response_and_validate_schema(404)
126 end
127
128 test "returns 404 for deactivated user", %{conn: conn} do
129 user = insert(:user, deactivated: true)
130
131 assert %{"error" => "Can't find user"} =
132 conn
133 |> get("/api/v1/accounts/#{user.id}")
134 |> json_response_and_validate_schema(:not_found)
135 end
136 end
137
138 defp local_and_remote_users do
139 local = insert(:user)
140 remote = insert(:user, local: false)
141 {:ok, local: local, remote: remote}
142 end
143
144 describe "user fetching with restrict unauthenticated profiles for local and remote" do
145 setup do: local_and_remote_users()
146
147 setup do: clear_config([:restrict_unauthenticated, :profiles, :local], true)
148
149 setup do: clear_config([:restrict_unauthenticated, :profiles, :remote], true)
150
151 test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do
152 assert %{"error" => "This API requires an authenticated user"} ==
153 conn
154 |> get("/api/v1/accounts/#{local.id}")
155 |> json_response_and_validate_schema(:unauthorized)
156
157 assert %{"error" => "This API requires an authenticated user"} ==
158 conn
159 |> get("/api/v1/accounts/#{remote.id}")
160 |> json_response_and_validate_schema(:unauthorized)
161 end
162
163 test "if user is authenticated", %{local: local, remote: remote} do
164 %{conn: conn} = oauth_access(["read"])
165
166 res_conn = get(conn, "/api/v1/accounts/#{local.id}")
167 assert %{"id" => _} = json_response_and_validate_schema(res_conn, 200)
168
169 res_conn = get(conn, "/api/v1/accounts/#{remote.id}")
170 assert %{"id" => _} = json_response_and_validate_schema(res_conn, 200)
171 end
172 end
173
174 describe "user fetching with restrict unauthenticated profiles for local" do
175 setup do: local_and_remote_users()
176
177 setup do: clear_config([:restrict_unauthenticated, :profiles, :local], true)
178
179 test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do
180 res_conn = get(conn, "/api/v1/accounts/#{local.id}")
181
182 assert json_response_and_validate_schema(res_conn, :unauthorized) == %{
183 "error" => "This API requires an authenticated user"
184 }
185
186 res_conn = get(conn, "/api/v1/accounts/#{remote.id}")
187 assert %{"id" => _} = json_response_and_validate_schema(res_conn, 200)
188 end
189
190 test "if user is authenticated", %{local: local, remote: remote} do
191 %{conn: conn} = oauth_access(["read"])
192
193 res_conn = get(conn, "/api/v1/accounts/#{local.id}")
194 assert %{"id" => _} = json_response_and_validate_schema(res_conn, 200)
195
196 res_conn = get(conn, "/api/v1/accounts/#{remote.id}")
197 assert %{"id" => _} = json_response_and_validate_schema(res_conn, 200)
198 end
199 end
200
201 describe "user fetching with restrict unauthenticated profiles for remote" do
202 setup do: local_and_remote_users()
203
204 setup do: clear_config([:restrict_unauthenticated, :profiles, :remote], true)
205
206 test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do
207 res_conn = get(conn, "/api/v1/accounts/#{local.id}")
208 assert %{"id" => _} = json_response_and_validate_schema(res_conn, 200)
209
210 res_conn = get(conn, "/api/v1/accounts/#{remote.id}")
211
212 assert json_response_and_validate_schema(res_conn, :unauthorized) == %{
213 "error" => "This API requires an authenticated user"
214 }
215 end
216
217 test "if user is authenticated", %{local: local, remote: remote} do
218 %{conn: conn} = oauth_access(["read"])
219
220 res_conn = get(conn, "/api/v1/accounts/#{local.id}")
221 assert %{"id" => _} = json_response_and_validate_schema(res_conn, 200)
222
223 res_conn = get(conn, "/api/v1/accounts/#{remote.id}")
224 assert %{"id" => _} = json_response_and_validate_schema(res_conn, 200)
225 end
226 end
227
228 describe "user timelines" do
229 setup do: oauth_access(["read:statuses"])
230
231 test "works with announces that are just addressed to public", %{conn: conn} do
232 user = insert(:user, ap_id: "https://honktest/u/test", local: false)
233 other_user = insert(:user)
234
235 {:ok, post} = CommonAPI.post(other_user, %{status: "bonkeronk"})
236
237 {:ok, announce, _} =
238 %{
239 "@context" => "https://www.w3.org/ns/activitystreams",
240 "actor" => "https://honktest/u/test",
241 "id" => "https://honktest/u/test/bonk/1793M7B9MQ48847vdx",
242 "object" => post.data["object"],
243 "published" => "2019-06-25T19:33:58Z",
244 "to" => ["https://www.w3.org/ns/activitystreams#Public"],
245 "type" => "Announce"
246 }
247 |> ActivityPub.persist(local: false)
248
249 assert resp =
250 conn
251 |> get("/api/v1/accounts/#{user.id}/statuses")
252 |> json_response_and_validate_schema(200)
253
254 assert [%{"id" => id}] = resp
255 assert id == announce.id
256 end
257
258 test "deactivated user", %{conn: conn} do
259 user = insert(:user, deactivated: true)
260
261 assert %{"error" => "Can't find user"} ==
262 conn
263 |> get("/api/v1/accounts/#{user.id}/statuses")
264 |> json_response_and_validate_schema(:not_found)
265 end
266
267 test "returns 404 when user is invisible", %{conn: conn} do
268 user = insert(:user, %{invisible: true})
269
270 assert %{"error" => "Can't find user"} =
271 conn
272 |> get("/api/v1/accounts/#{user.id}")
273 |> json_response_and_validate_schema(404)
274 end
275
276 test "respects blocks", %{user: user_one, conn: conn} do
277 user_two = insert(:user)
278 user_three = insert(:user)
279
280 User.block(user_one, user_two)
281
282 {:ok, activity} = CommonAPI.post(user_two, %{status: "User one sux0rz"})
283 {:ok, repeat} = CommonAPI.repeat(activity.id, user_three)
284
285 assert resp =
286 conn
287 |> get("/api/v1/accounts/#{user_two.id}/statuses")
288 |> json_response_and_validate_schema(200)
289
290 assert [%{"id" => id}] = resp
291 assert id == activity.id
292
293 # Even a blocked user will deliver the full user timeline, there would be
294 # no point in looking at a blocked users timeline otherwise
295 assert resp =
296 conn
297 |> get("/api/v1/accounts/#{user_two.id}/statuses")
298 |> json_response_and_validate_schema(200)
299
300 assert [%{"id" => id}] = resp
301 assert id == activity.id
302
303 # Third user's timeline includes the repeat when viewed by unauthenticated user
304 resp =
305 build_conn()
306 |> get("/api/v1/accounts/#{user_three.id}/statuses")
307 |> json_response_and_validate_schema(200)
308
309 assert [%{"id" => id}] = resp
310 assert id == repeat.id
311
312 # When viewing a third user's timeline, the blocked users' statuses will NOT be shown
313 resp = get(conn, "/api/v1/accounts/#{user_three.id}/statuses")
314
315 assert [] == json_response_and_validate_schema(resp, 200)
316 end
317
318 test "gets users statuses", %{conn: conn} do
319 user_one = insert(:user)
320 user_two = insert(:user)
321 user_three = insert(:user)
322
323 {:ok, _user_three, _user_one} = User.follow(user_three, user_one)
324
325 {:ok, activity} = CommonAPI.post(user_one, %{status: "HI!!!"})
326
327 {:ok, direct_activity} =
328 CommonAPI.post(user_one, %{
329 status: "Hi, @#{user_two.nickname}.",
330 visibility: "direct"
331 })
332
333 {:ok, private_activity} =
334 CommonAPI.post(user_one, %{status: "private", visibility: "private"})
335
336 # TODO!!!
337 resp =
338 conn
339 |> get("/api/v1/accounts/#{user_one.id}/statuses")
340 |> json_response_and_validate_schema(200)
341
342 assert [%{"id" => id}] = resp
343 assert id == to_string(activity.id)
344
345 resp =
346 conn
347 |> assign(:user, user_two)
348 |> assign(:token, insert(:oauth_token, user: user_two, scopes: ["read:statuses"]))
349 |> get("/api/v1/accounts/#{user_one.id}/statuses")
350 |> json_response_and_validate_schema(200)
351
352 assert [%{"id" => id_one}, %{"id" => id_two}] = resp
353 assert id_one == to_string(direct_activity.id)
354 assert id_two == to_string(activity.id)
355
356 resp =
357 conn
358 |> assign(:user, user_three)
359 |> assign(:token, insert(:oauth_token, user: user_three, scopes: ["read:statuses"]))
360 |> get("/api/v1/accounts/#{user_one.id}/statuses")
361 |> json_response_and_validate_schema(200)
362
363 assert [%{"id" => id_one}, %{"id" => id_two}] = resp
364 assert id_one == to_string(private_activity.id)
365 assert id_two == to_string(activity.id)
366 end
367
368 test "unimplemented pinned statuses feature", %{conn: conn} do
369 note = insert(:note_activity)
370 user = User.get_cached_by_ap_id(note.data["actor"])
371
372 conn = get(conn, "/api/v1/accounts/#{user.id}/statuses?pinned=true")
373
374 assert json_response_and_validate_schema(conn, 200) == []
375 end
376
377 test "gets an users media, excludes reblogs", %{conn: conn} do
378 note = insert(:note_activity)
379 user = User.get_cached_by_ap_id(note.data["actor"])
380 other_user = insert(:user)
381
382 file = %Plug.Upload{
383 content_type: "image/jpeg",
384 path: Path.absname("test/fixtures/image.jpg"),
385 filename: "an_image.jpg"
386 }
387
388 {:ok, %{id: media_id}} = ActivityPub.upload(file, actor: user.ap_id)
389
390 {:ok, %{id: image_post_id}} = CommonAPI.post(user, %{status: "cofe", media_ids: [media_id]})
391
392 {:ok, %{id: media_id}} = ActivityPub.upload(file, actor: other_user.ap_id)
393
394 {:ok, %{id: other_image_post_id}} =
395 CommonAPI.post(other_user, %{status: "cofe2", media_ids: [media_id]})
396
397 {:ok, _announce} = CommonAPI.repeat(other_image_post_id, user)
398
399 conn = get(conn, "/api/v1/accounts/#{user.id}/statuses?only_media=true")
400
401 assert [%{"id" => ^image_post_id}] = json_response_and_validate_schema(conn, 200)
402
403 conn = get(build_conn(), "/api/v1/accounts/#{user.id}/statuses?only_media=1")
404
405 assert [%{"id" => ^image_post_id}] = json_response_and_validate_schema(conn, 200)
406 end
407
408 test "gets a user's statuses without reblogs", %{user: user, conn: conn} do
409 {:ok, %{id: post_id}} = CommonAPI.post(user, %{status: "HI!!!"})
410 {:ok, _} = CommonAPI.repeat(post_id, user)
411
412 conn = get(conn, "/api/v1/accounts/#{user.id}/statuses?exclude_reblogs=true")
413 assert [%{"id" => ^post_id}] = json_response_and_validate_schema(conn, 200)
414
415 conn = get(conn, "/api/v1/accounts/#{user.id}/statuses?exclude_reblogs=1")
416 assert [%{"id" => ^post_id}] = json_response_and_validate_schema(conn, 200)
417 end
418
419 test "filters user's statuses by a hashtag", %{user: user, conn: conn} do
420 {:ok, %{id: post_id}} = CommonAPI.post(user, %{status: "#hashtag"})
421 {:ok, _post} = CommonAPI.post(user, %{status: "hashtag"})
422
423 conn = get(conn, "/api/v1/accounts/#{user.id}/statuses?tagged=hashtag")
424 assert [%{"id" => ^post_id}] = json_response_and_validate_schema(conn, 200)
425 end
426
427 test "the user views their own timelines and excludes direct messages", %{
428 user: user,
429 conn: conn
430 } do
431 {:ok, %{id: public_activity_id}} =
432 CommonAPI.post(user, %{status: ".", visibility: "public"})
433
434 {:ok, _direct_activity} = CommonAPI.post(user, %{status: ".", visibility: "direct"})
435
436 conn = get(conn, "/api/v1/accounts/#{user.id}/statuses?exclude_visibilities[]=direct")
437 assert [%{"id" => ^public_activity_id}] = json_response_and_validate_schema(conn, 200)
438 end
439
440 test "muted reactions", %{user: user, conn: conn} do
441 user2 = insert(:user)
442 User.mute(user, user2)
443 {:ok, activity} = CommonAPI.post(user, %{status: "."})
444 {:ok, _} = CommonAPI.react_with_emoji(activity.id, user2, "🎅")
445
446 result =
447 conn
448 |> get("/api/v1/accounts/#{user.id}/statuses")
449 |> json_response_and_validate_schema(200)
450
451 assert [
452 %{
453 "pleroma" => %{
454 "emoji_reactions" => []
455 }
456 }
457 ] = result
458
459 result =
460 conn
461 |> get("/api/v1/accounts/#{user.id}/statuses?with_muted=true")
462 |> json_response_and_validate_schema(200)
463
464 assert [
465 %{
466 "pleroma" => %{
467 "emoji_reactions" => [%{"count" => 1, "me" => false, "name" => "🎅"}]
468 }
469 }
470 ] = result
471 end
472
473 test "paginates a user's statuses", %{user: user, conn: conn} do
474 {:ok, post1} = CommonAPI.post(user, %{status: "first post"})
475 {:ok, _} = CommonAPI.post(user, %{status: "second post"})
476
477 response1 = get(conn, "/api/v1/accounts/#{user.id}/statuses?limit=1")
478 assert json_response(response1, 200) |> length() == 1
479
480 response2 = get(conn, "/api/v1/accounts/#{user.id}/statuses?limit=1&min_id=#{post1.id}")
481 assert json_response(response2, 200) |> length() == 1
482
483 refute response1 == response2
484 end
485 end
486
487 defp local_and_remote_activities(%{local: local, remote: remote}) do
488 insert(:note_activity, user: local)
489 insert(:note_activity, user: remote, local: false)
490
491 :ok
492 end
493
494 describe "statuses with restrict unauthenticated profiles for local and remote" do
495 setup do: local_and_remote_users()
496 setup :local_and_remote_activities
497
498 setup do: clear_config([:restrict_unauthenticated, :profiles, :local], true)
499
500 setup do: clear_config([:restrict_unauthenticated, :profiles, :remote], true)
501
502 test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do
503 assert %{"error" => "This API requires an authenticated user"} ==
504 conn
505 |> get("/api/v1/accounts/#{local.id}/statuses")
506 |> json_response_and_validate_schema(:unauthorized)
507
508 assert %{"error" => "This API requires an authenticated user"} ==
509 conn
510 |> get("/api/v1/accounts/#{remote.id}/statuses")
511 |> json_response_and_validate_schema(:unauthorized)
512 end
513
514 test "if user is authenticated", %{local: local, remote: remote} do
515 %{conn: conn} = oauth_access(["read"])
516
517 res_conn = get(conn, "/api/v1/accounts/#{local.id}/statuses")
518 assert length(json_response_and_validate_schema(res_conn, 200)) == 1
519
520 res_conn = get(conn, "/api/v1/accounts/#{remote.id}/statuses")
521 assert length(json_response_and_validate_schema(res_conn, 200)) == 1
522 end
523 end
524
525 describe "statuses with restrict unauthenticated profiles for local" do
526 setup do: local_and_remote_users()
527 setup :local_and_remote_activities
528
529 setup do: clear_config([:restrict_unauthenticated, :profiles, :local], true)
530
531 test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do
532 assert %{"error" => "This API requires an authenticated user"} ==
533 conn
534 |> get("/api/v1/accounts/#{local.id}/statuses")
535 |> json_response_and_validate_schema(:unauthorized)
536
537 res_conn = get(conn, "/api/v1/accounts/#{remote.id}/statuses")
538 assert length(json_response_and_validate_schema(res_conn, 200)) == 1
539 end
540
541 test "if user is authenticated", %{local: local, remote: remote} do
542 %{conn: conn} = oauth_access(["read"])
543
544 res_conn = get(conn, "/api/v1/accounts/#{local.id}/statuses")
545 assert length(json_response_and_validate_schema(res_conn, 200)) == 1
546
547 res_conn = get(conn, "/api/v1/accounts/#{remote.id}/statuses")
548 assert length(json_response_and_validate_schema(res_conn, 200)) == 1
549 end
550 end
551
552 describe "statuses with restrict unauthenticated profiles for remote" do
553 setup do: local_and_remote_users()
554 setup :local_and_remote_activities
555
556 setup do: clear_config([:restrict_unauthenticated, :profiles, :remote], true)
557
558 test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do
559 res_conn = get(conn, "/api/v1/accounts/#{local.id}/statuses")
560 assert length(json_response_and_validate_schema(res_conn, 200)) == 1
561
562 assert %{"error" => "This API requires an authenticated user"} ==
563 conn
564 |> get("/api/v1/accounts/#{remote.id}/statuses")
565 |> json_response_and_validate_schema(:unauthorized)
566 end
567
568 test "if user is authenticated", %{local: local, remote: remote} do
569 %{conn: conn} = oauth_access(["read"])
570
571 res_conn = get(conn, "/api/v1/accounts/#{local.id}/statuses")
572 assert length(json_response_and_validate_schema(res_conn, 200)) == 1
573
574 res_conn = get(conn, "/api/v1/accounts/#{remote.id}/statuses")
575 assert length(json_response_and_validate_schema(res_conn, 200)) == 1
576 end
577 end
578
579 describe "followers" do
580 setup do: oauth_access(["read:accounts"])
581
582 test "getting followers", %{user: user, conn: conn} do
583 other_user = insert(:user)
584 {:ok, %{id: user_id}, other_user} = User.follow(user, other_user)
585
586 conn = get(conn, "/api/v1/accounts/#{other_user.id}/followers")
587
588 assert [%{"id" => ^user_id}] = json_response_and_validate_schema(conn, 200)
589 end
590
591 test "getting followers, hide_followers", %{user: user, conn: conn} do
592 other_user = insert(:user, hide_followers: true)
593 {:ok, _user, _other_user} = User.follow(user, other_user)
594
595 conn = get(conn, "/api/v1/accounts/#{other_user.id}/followers")
596
597 assert [] == json_response_and_validate_schema(conn, 200)
598 end
599
600 test "getting followers, hide_followers, same user requesting" do
601 user = insert(:user)
602 other_user = insert(:user, hide_followers: true)
603 {:ok, _user, _other_user} = User.follow(user, other_user)
604
605 conn =
606 build_conn()
607 |> assign(:user, other_user)
608 |> assign(:token, insert(:oauth_token, user: other_user, scopes: ["read:accounts"]))
609 |> get("/api/v1/accounts/#{other_user.id}/followers")
610
611 refute [] == json_response_and_validate_schema(conn, 200)
612 end
613
614 test "getting followers, pagination", %{user: user, conn: conn} do
615 {:ok, %User{id: follower1_id}, _user} = :user |> insert() |> User.follow(user)
616 {:ok, %User{id: follower2_id}, _user} = :user |> insert() |> User.follow(user)
617 {:ok, %User{id: follower3_id}, _user} = :user |> insert() |> User.follow(user)
618
619 assert [%{"id" => ^follower3_id}, %{"id" => ^follower2_id}] =
620 conn
621 |> get("/api/v1/accounts/#{user.id}/followers?since_id=#{follower1_id}")
622 |> json_response_and_validate_schema(200)
623
624 assert [%{"id" => ^follower2_id}, %{"id" => ^follower1_id}] =
625 conn
626 |> get("/api/v1/accounts/#{user.id}/followers?max_id=#{follower3_id}")
627 |> json_response_and_validate_schema(200)
628
629 assert [%{"id" => ^follower2_id}, %{"id" => ^follower1_id}] =
630 conn
631 |> get(
632 "/api/v1/accounts/#{user.id}/followers?id=#{user.id}&limit=20&max_id=#{
633 follower3_id
634 }"
635 )
636 |> json_response_and_validate_schema(200)
637
638 res_conn = get(conn, "/api/v1/accounts/#{user.id}/followers?limit=1&max_id=#{follower3_id}")
639
640 assert [%{"id" => ^follower2_id}] = json_response_and_validate_schema(res_conn, 200)
641
642 assert [link_header] = get_resp_header(res_conn, "link")
643 assert link_header =~ ~r/min_id=#{follower2_id}/
644 assert link_header =~ ~r/max_id=#{follower2_id}/
645 end
646 end
647
648 describe "following" do
649 setup do: oauth_access(["read:accounts"])
650
651 test "getting following", %{user: user, conn: conn} do
652 other_user = insert(:user)
653 {:ok, user, other_user} = User.follow(user, other_user)
654
655 conn = get(conn, "/api/v1/accounts/#{user.id}/following")
656
657 assert [%{"id" => id}] = json_response_and_validate_schema(conn, 200)
658 assert id == to_string(other_user.id)
659 end
660
661 test "getting following, hide_follows, other user requesting" do
662 user = insert(:user, hide_follows: true)
663 other_user = insert(:user)
664 {:ok, user, other_user} = User.follow(user, other_user)
665
666 conn =
667 build_conn()
668 |> assign(:user, other_user)
669 |> assign(:token, insert(:oauth_token, user: other_user, scopes: ["read:accounts"]))
670 |> get("/api/v1/accounts/#{user.id}/following")
671
672 assert [] == json_response_and_validate_schema(conn, 200)
673 end
674
675 test "getting following, hide_follows, same user requesting" do
676 user = insert(:user, hide_follows: true)
677 other_user = insert(:user)
678 {:ok, user, _other_user} = User.follow(user, other_user)
679
680 conn =
681 build_conn()
682 |> assign(:user, user)
683 |> assign(:token, insert(:oauth_token, user: user, scopes: ["read:accounts"]))
684 |> get("/api/v1/accounts/#{user.id}/following")
685
686 refute [] == json_response_and_validate_schema(conn, 200)
687 end
688
689 test "getting following, pagination", %{user: user, conn: conn} do
690 following1 = insert(:user)
691 following2 = insert(:user)
692 following3 = insert(:user)
693 {:ok, _, _} = User.follow(user, following1)
694 {:ok, _, _} = User.follow(user, following2)
695 {:ok, _, _} = User.follow(user, following3)
696
697 res_conn = get(conn, "/api/v1/accounts/#{user.id}/following?since_id=#{following1.id}")
698
699 assert [%{"id" => id3}, %{"id" => id2}] = json_response_and_validate_schema(res_conn, 200)
700 assert id3 == following3.id
701 assert id2 == following2.id
702
703 res_conn = get(conn, "/api/v1/accounts/#{user.id}/following?max_id=#{following3.id}")
704
705 assert [%{"id" => id2}, %{"id" => id1}] = json_response_and_validate_schema(res_conn, 200)
706 assert id2 == following2.id
707 assert id1 == following1.id
708
709 res_conn =
710 get(
711 conn,
712 "/api/v1/accounts/#{user.id}/following?id=#{user.id}&limit=20&max_id=#{following3.id}"
713 )
714
715 assert [%{"id" => id2}, %{"id" => id1}] = json_response_and_validate_schema(res_conn, 200)
716 assert id2 == following2.id
717 assert id1 == following1.id
718
719 res_conn =
720 get(conn, "/api/v1/accounts/#{user.id}/following?limit=1&max_id=#{following3.id}")
721
722 assert [%{"id" => id2}] = json_response_and_validate_schema(res_conn, 200)
723 assert id2 == following2.id
724
725 assert [link_header] = get_resp_header(res_conn, "link")
726 assert link_header =~ ~r/min_id=#{following2.id}/
727 assert link_header =~ ~r/max_id=#{following2.id}/
728 end
729 end
730
731 describe "follow/unfollow" do
732 setup do: oauth_access(["follow"])
733
734 test "following / unfollowing a user", %{conn: conn} do
735 %{id: other_user_id, nickname: other_user_nickname} = insert(:user)
736
737 assert %{"id" => _id, "following" => true} =
738 conn
739 |> post("/api/v1/accounts/#{other_user_id}/follow")
740 |> json_response_and_validate_schema(200)
741
742 assert %{"id" => _id, "following" => false} =
743 conn
744 |> post("/api/v1/accounts/#{other_user_id}/unfollow")
745 |> json_response_and_validate_schema(200)
746
747 assert %{"id" => ^other_user_id} =
748 conn
749 |> put_req_header("content-type", "application/json")
750 |> post("/api/v1/follows", %{"uri" => other_user_nickname})
751 |> json_response_and_validate_schema(200)
752 end
753
754 test "cancelling follow request", %{conn: conn} do
755 %{id: other_user_id} = insert(:user, %{is_locked: true})
756
757 assert %{"id" => ^other_user_id, "following" => false, "requested" => true} =
758 conn
759 |> post("/api/v1/accounts/#{other_user_id}/follow")
760 |> json_response_and_validate_schema(:ok)
761
762 assert %{"id" => ^other_user_id, "following" => false, "requested" => false} =
763 conn
764 |> post("/api/v1/accounts/#{other_user_id}/unfollow")
765 |> json_response_and_validate_schema(:ok)
766 end
767
768 test "following without reblogs" do
769 %{conn: conn} = oauth_access(["follow", "read:statuses"])
770 followed = insert(:user)
771 other_user = insert(:user)
772
773 ret_conn =
774 conn
775 |> put_req_header("content-type", "application/json")
776 |> post("/api/v1/accounts/#{followed.id}/follow", %{reblogs: false})
777
778 assert %{"showing_reblogs" => false} = json_response_and_validate_schema(ret_conn, 200)
779
780 {:ok, activity} = CommonAPI.post(other_user, %{status: "hey"})
781 {:ok, %{id: reblog_id}} = CommonAPI.repeat(activity.id, followed)
782
783 assert [] ==
784 conn
785 |> get("/api/v1/timelines/home")
786 |> json_response(200)
787
788 assert %{"showing_reblogs" => true} =
789 conn
790 |> put_req_header("content-type", "application/json")
791 |> post("/api/v1/accounts/#{followed.id}/follow", %{reblogs: true})
792 |> json_response_and_validate_schema(200)
793
794 assert [%{"id" => ^reblog_id}] =
795 conn
796 |> get("/api/v1/timelines/home")
797 |> json_response(200)
798 end
799
800 test "following with reblogs" do
801 %{conn: conn} = oauth_access(["follow", "read:statuses"])
802 followed = insert(:user)
803 other_user = insert(:user)
804
805 ret_conn = post(conn, "/api/v1/accounts/#{followed.id}/follow")
806
807 assert %{"showing_reblogs" => true} = json_response_and_validate_schema(ret_conn, 200)
808
809 {:ok, activity} = CommonAPI.post(other_user, %{status: "hey"})
810 {:ok, %{id: reblog_id}} = CommonAPI.repeat(activity.id, followed)
811
812 assert [%{"id" => ^reblog_id}] =
813 conn
814 |> get("/api/v1/timelines/home")
815 |> json_response(200)
816
817 assert %{"showing_reblogs" => false} =
818 conn
819 |> put_req_header("content-type", "application/json")
820 |> post("/api/v1/accounts/#{followed.id}/follow", %{reblogs: false})
821 |> json_response_and_validate_schema(200)
822
823 assert [] ==
824 conn
825 |> get("/api/v1/timelines/home")
826 |> json_response(200)
827 end
828
829 test "following / unfollowing errors", %{user: user, conn: conn} do
830 # self follow
831 conn_res = post(conn, "/api/v1/accounts/#{user.id}/follow")
832
833 assert %{"error" => "Can not follow yourself"} =
834 json_response_and_validate_schema(conn_res, 400)
835
836 # self unfollow
837 user = User.get_cached_by_id(user.id)
838 conn_res = post(conn, "/api/v1/accounts/#{user.id}/unfollow")
839
840 assert %{"error" => "Can not unfollow yourself"} =
841 json_response_and_validate_schema(conn_res, 400)
842
843 # self follow via uri
844 user = User.get_cached_by_id(user.id)
845
846 assert %{"error" => "Can not follow yourself"} =
847 conn
848 |> put_req_header("content-type", "multipart/form-data")
849 |> post("/api/v1/follows", %{"uri" => user.nickname})
850 |> json_response_and_validate_schema(400)
851
852 # follow non existing user
853 conn_res = post(conn, "/api/v1/accounts/doesntexist/follow")
854 assert %{"error" => "Record not found"} = json_response_and_validate_schema(conn_res, 404)
855
856 # follow non existing user via uri
857 conn_res =
858 conn
859 |> put_req_header("content-type", "multipart/form-data")
860 |> post("/api/v1/follows", %{"uri" => "doesntexist"})
861
862 assert %{"error" => "Record not found"} = json_response_and_validate_schema(conn_res, 404)
863
864 # unfollow non existing user
865 conn_res = post(conn, "/api/v1/accounts/doesntexist/unfollow")
866 assert %{"error" => "Record not found"} = json_response_and_validate_schema(conn_res, 404)
867 end
868 end
869
870 describe "mute/unmute" do
871 setup do: oauth_access(["write:mutes"])
872
873 test "with notifications", %{conn: conn} do
874 other_user = insert(:user)
875
876 assert %{"id" => _id, "muting" => true, "muting_notifications" => true} =
877 conn
878 |> post("/api/v1/accounts/#{other_user.id}/mute")
879 |> json_response_and_validate_schema(200)
880
881 conn = post(conn, "/api/v1/accounts/#{other_user.id}/unmute")
882
883 assert %{"id" => _id, "muting" => false, "muting_notifications" => false} =
884 json_response_and_validate_schema(conn, 200)
885 end
886
887 test "without notifications", %{conn: conn} do
888 other_user = insert(:user)
889
890 ret_conn =
891 conn
892 |> put_req_header("content-type", "multipart/form-data")
893 |> post("/api/v1/accounts/#{other_user.id}/mute", %{"notifications" => "false"})
894
895 assert %{"id" => _id, "muting" => true, "muting_notifications" => false} =
896 json_response_and_validate_schema(ret_conn, 200)
897
898 conn = post(conn, "/api/v1/accounts/#{other_user.id}/unmute")
899
900 assert %{"id" => _id, "muting" => false, "muting_notifications" => false} =
901 json_response_and_validate_schema(conn, 200)
902 end
903 end
904
905 describe "pinned statuses" do
906 setup do
907 user = insert(:user)
908 {:ok, activity} = CommonAPI.post(user, %{status: "HI!!!"})
909 %{conn: conn} = oauth_access(["read:statuses"], user: user)
910
911 [conn: conn, user: user, activity: activity]
912 end
913
914 test "returns pinned statuses", %{conn: conn, user: user, activity: %{id: activity_id}} do
915 {:ok, _} = CommonAPI.pin(activity_id, user)
916
917 assert [%{"id" => ^activity_id, "pinned" => true}] =
918 conn
919 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
920 |> json_response_and_validate_schema(200)
921 end
922 end
923
924 test "blocking / unblocking a user" do
925 %{conn: conn} = oauth_access(["follow"])
926 other_user = insert(:user)
927
928 ret_conn = post(conn, "/api/v1/accounts/#{other_user.id}/block")
929
930 assert %{"id" => _id, "blocking" => true} = json_response_and_validate_schema(ret_conn, 200)
931
932 conn = post(conn, "/api/v1/accounts/#{other_user.id}/unblock")
933
934 assert %{"id" => _id, "blocking" => false} = json_response_and_validate_schema(conn, 200)
935 end
936
937 describe "create account by app" do
938 setup do
939 valid_params = %{
940 username: "lain",
941 email: "lain@example.org",
942 password: "PlzDontHackLain",
943 agreement: true
944 }
945
946 [valid_params: valid_params]
947 end
948
949 test "registers and logs in without :account_activation_required / :account_approval_required",
950 %{conn: conn} do
951 clear_config([:instance, :account_activation_required], false)
952 clear_config([:instance, :account_approval_required], false)
953
954 conn =
955 conn
956 |> put_req_header("content-type", "application/json")
957 |> post("/api/v1/apps", %{
958 client_name: "client_name",
959 redirect_uris: "urn:ietf:wg:oauth:2.0:oob",
960 scopes: "read, write, follow"
961 })
962
963 assert %{
964 "client_id" => client_id,
965 "client_secret" => client_secret,
966 "id" => _,
967 "name" => "client_name",
968 "redirect_uri" => "urn:ietf:wg:oauth:2.0:oob",
969 "vapid_key" => _,
970 "website" => nil
971 } = json_response_and_validate_schema(conn, 200)
972
973 conn =
974 post(conn, "/oauth/token", %{
975 grant_type: "client_credentials",
976 client_id: client_id,
977 client_secret: client_secret
978 })
979
980 assert %{"access_token" => token, "refresh_token" => refresh, "scope" => scope} =
981 json_response(conn, 200)
982
983 assert token
984 token_from_db = Repo.get_by(Token, token: token)
985 assert token_from_db
986 assert refresh
987 assert scope == "read write follow"
988
989 clear_config([User, :email_blacklist], ["example.org"])
990
991 params = %{
992 username: "lain",
993 email: "lain@example.org",
994 password: "PlzDontHackLain",
995 bio: "Test Bio",
996 agreement: true
997 }
998
999 conn =
1000 build_conn()
1001 |> put_req_header("content-type", "multipart/form-data")
1002 |> put_req_header("authorization", "Bearer " <> token)
1003 |> post("/api/v1/accounts", params)
1004
1005 assert %{"error" => "{\"email\":[\"Invalid email\"]}"} =
1006 json_response_and_validate_schema(conn, 400)
1007
1008 Pleroma.Config.put([User, :email_blacklist], [])
1009
1010 conn =
1011 build_conn()
1012 |> put_req_header("content-type", "multipart/form-data")
1013 |> put_req_header("authorization", "Bearer " <> token)
1014 |> post("/api/v1/accounts", params)
1015
1016 %{
1017 "access_token" => token,
1018 "created_at" => _created_at,
1019 "scope" => ^scope,
1020 "token_type" => "Bearer"
1021 } = json_response_and_validate_schema(conn, 200)
1022
1023 token_from_db = Repo.get_by(Token, token: token)
1024 assert token_from_db
1025 user = Repo.preload(token_from_db, :user).user
1026
1027 assert user
1028 refute user.confirmation_pending
1029 refute user.approval_pending
1030 end
1031
1032 test "registers but does not log in with :account_activation_required", %{conn: conn} do
1033 clear_config([:instance, :account_activation_required], true)
1034 clear_config([:instance, :account_approval_required], false)
1035
1036 conn =
1037 conn
1038 |> put_req_header("content-type", "application/json")
1039 |> post("/api/v1/apps", %{
1040 client_name: "client_name",
1041 redirect_uris: "urn:ietf:wg:oauth:2.0:oob",
1042 scopes: "read, write, follow"
1043 })
1044
1045 assert %{
1046 "client_id" => client_id,
1047 "client_secret" => client_secret,
1048 "id" => _,
1049 "name" => "client_name",
1050 "redirect_uri" => "urn:ietf:wg:oauth:2.0:oob",
1051 "vapid_key" => _,
1052 "website" => nil
1053 } = json_response_and_validate_schema(conn, 200)
1054
1055 conn =
1056 post(conn, "/oauth/token", %{
1057 grant_type: "client_credentials",
1058 client_id: client_id,
1059 client_secret: client_secret
1060 })
1061
1062 assert %{"access_token" => token, "refresh_token" => refresh, "scope" => scope} =
1063 json_response(conn, 200)
1064
1065 assert token
1066 token_from_db = Repo.get_by(Token, token: token)
1067 assert token_from_db
1068 assert refresh
1069 assert scope == "read write follow"
1070
1071 conn =
1072 build_conn()
1073 |> put_req_header("content-type", "multipart/form-data")
1074 |> put_req_header("authorization", "Bearer " <> token)
1075 |> post("/api/v1/accounts", %{
1076 username: "lain",
1077 email: "lain@example.org",
1078 password: "PlzDontHackLain",
1079 bio: "Test Bio",
1080 agreement: true
1081 })
1082
1083 response = json_response_and_validate_schema(conn, 200)
1084 assert %{"identifier" => "missing_confirmed_email"} = response
1085 refute response["access_token"]
1086 refute response["token_type"]
1087
1088 user = Repo.get_by(User, email: "lain@example.org")
1089 assert user.confirmation_pending
1090 end
1091
1092 test "registers but does not log in with :account_approval_required", %{conn: conn} do
1093 clear_config([:instance, :account_approval_required], true)
1094 clear_config([:instance, :account_activation_required], false)
1095
1096 conn =
1097 conn
1098 |> put_req_header("content-type", "application/json")
1099 |> post("/api/v1/apps", %{
1100 client_name: "client_name",
1101 redirect_uris: "urn:ietf:wg:oauth:2.0:oob",
1102 scopes: "read, write, follow"
1103 })
1104
1105 assert %{
1106 "client_id" => client_id,
1107 "client_secret" => client_secret,
1108 "id" => _,
1109 "name" => "client_name",
1110 "redirect_uri" => "urn:ietf:wg:oauth:2.0:oob",
1111 "vapid_key" => _,
1112 "website" => nil
1113 } = json_response_and_validate_schema(conn, 200)
1114
1115 conn =
1116 post(conn, "/oauth/token", %{
1117 grant_type: "client_credentials",
1118 client_id: client_id,
1119 client_secret: client_secret
1120 })
1121
1122 assert %{"access_token" => token, "refresh_token" => refresh, "scope" => scope} =
1123 json_response(conn, 200)
1124
1125 assert token
1126 token_from_db = Repo.get_by(Token, token: token)
1127 assert token_from_db
1128 assert refresh
1129 assert scope == "read write follow"
1130
1131 conn =
1132 build_conn()
1133 |> put_req_header("content-type", "multipart/form-data")
1134 |> put_req_header("authorization", "Bearer " <> token)
1135 |> post("/api/v1/accounts", %{
1136 username: "lain",
1137 email: "lain@example.org",
1138 password: "PlzDontHackLain",
1139 bio: "Test Bio",
1140 agreement: true,
1141 reason: "I'm a cool dude, bro"
1142 })
1143
1144 response = json_response_and_validate_schema(conn, 200)
1145 assert %{"identifier" => "awaiting_approval"} = response
1146 refute response["access_token"]
1147 refute response["token_type"]
1148
1149 user = Repo.get_by(User, email: "lain@example.org")
1150
1151 assert user.approval_pending
1152 assert user.registration_reason == "I'm a cool dude, bro"
1153 end
1154
1155 test "returns error when user already registred", %{conn: conn, valid_params: valid_params} do
1156 _user = insert(:user, email: "lain@example.org")
1157 app_token = insert(:oauth_token, user: nil)
1158
1159 res =
1160 conn
1161 |> put_req_header("authorization", "Bearer " <> app_token.token)
1162 |> put_req_header("content-type", "application/json")
1163 |> post("/api/v1/accounts", valid_params)
1164
1165 assert json_response_and_validate_schema(res, 400) == %{
1166 "error" => "{\"email\":[\"has already been taken\"]}"
1167 }
1168 end
1169
1170 test "returns bad_request if missing required params", %{
1171 conn: conn,
1172 valid_params: valid_params
1173 } do
1174 app_token = insert(:oauth_token, user: nil)
1175
1176 conn =
1177 conn
1178 |> put_req_header("authorization", "Bearer " <> app_token.token)
1179 |> put_req_header("content-type", "application/json")
1180
1181 res = post(conn, "/api/v1/accounts", valid_params)
1182 assert json_response_and_validate_schema(res, 200)
1183
1184 [{127, 0, 0, 1}, {127, 0, 0, 2}, {127, 0, 0, 3}, {127, 0, 0, 4}]
1185 |> Stream.zip(Map.delete(valid_params, :email))
1186 |> Enum.each(fn {ip, {attr, _}} ->
1187 res =
1188 conn
1189 |> Map.put(:remote_ip, ip)
1190 |> post("/api/v1/accounts", Map.delete(valid_params, attr))
1191 |> json_response_and_validate_schema(400)
1192
1193 assert res == %{
1194 "error" => "Missing field: #{attr}.",
1195 "errors" => [
1196 %{
1197 "message" => "Missing field: #{attr}",
1198 "source" => %{"pointer" => "/#{attr}"},
1199 "title" => "Invalid value"
1200 }
1201 ]
1202 }
1203 end)
1204 end
1205
1206 test "returns bad_request if missing email params when :account_activation_required is enabled",
1207 %{conn: conn, valid_params: valid_params} do
1208 clear_config([:instance, :account_activation_required], true)
1209
1210 app_token = insert(:oauth_token, user: nil)
1211
1212 conn =
1213 conn
1214 |> put_req_header("authorization", "Bearer " <> app_token.token)
1215 |> put_req_header("content-type", "application/json")
1216
1217 res =
1218 conn
1219 |> Map.put(:remote_ip, {127, 0, 0, 5})
1220 |> post("/api/v1/accounts", Map.delete(valid_params, :email))
1221
1222 assert json_response_and_validate_schema(res, 400) ==
1223 %{"error" => "Missing parameter: email"}
1224
1225 res =
1226 conn
1227 |> Map.put(:remote_ip, {127, 0, 0, 6})
1228 |> post("/api/v1/accounts", Map.put(valid_params, :email, ""))
1229
1230 assert json_response_and_validate_schema(res, 400) == %{
1231 "error" => "{\"email\":[\"can't be blank\"]}"
1232 }
1233 end
1234
1235 test "allow registration without an email", %{conn: conn, valid_params: valid_params} do
1236 app_token = insert(:oauth_token, user: nil)
1237 conn = put_req_header(conn, "authorization", "Bearer " <> app_token.token)
1238
1239 res =
1240 conn
1241 |> put_req_header("content-type", "application/json")
1242 |> Map.put(:remote_ip, {127, 0, 0, 7})
1243 |> post("/api/v1/accounts", Map.delete(valid_params, :email))
1244
1245 assert json_response_and_validate_schema(res, 200)
1246 end
1247
1248 test "allow registration with an empty email", %{conn: conn, valid_params: valid_params} do
1249 app_token = insert(:oauth_token, user: nil)
1250 conn = put_req_header(conn, "authorization", "Bearer " <> app_token.token)
1251
1252 res =
1253 conn
1254 |> put_req_header("content-type", "application/json")
1255 |> Map.put(:remote_ip, {127, 0, 0, 8})
1256 |> post("/api/v1/accounts", Map.put(valid_params, :email, ""))
1257
1258 assert json_response_and_validate_schema(res, 200)
1259 end
1260
1261 test "returns forbidden if token is invalid", %{conn: conn, valid_params: valid_params} do
1262 res =
1263 conn
1264 |> put_req_header("authorization", "Bearer " <> "invalid-token")
1265 |> put_req_header("content-type", "multipart/form-data")
1266 |> post("/api/v1/accounts", valid_params)
1267
1268 assert json_response_and_validate_schema(res, 403) == %{"error" => "Invalid credentials"}
1269 end
1270
1271 test "registration from trusted app" do
1272 clear_config([Pleroma.Captcha, :enabled], true)
1273 app = insert(:oauth_app, trusted: true, scopes: ["read", "write", "follow", "push"])
1274
1275 conn =
1276 build_conn()
1277 |> post("/oauth/token", %{
1278 "grant_type" => "client_credentials",
1279 "client_id" => app.client_id,
1280 "client_secret" => app.client_secret
1281 })
1282
1283 assert %{"access_token" => token, "token_type" => "Bearer"} = json_response(conn, 200)
1284
1285 response =
1286 build_conn()
1287 |> Plug.Conn.put_req_header("authorization", "Bearer " <> token)
1288 |> put_req_header("content-type", "multipart/form-data")
1289 |> post("/api/v1/accounts", %{
1290 nickname: "nickanme",
1291 agreement: true,
1292 email: "email@example.com",
1293 fullname: "Lain",
1294 username: "Lain",
1295 password: "some_password",
1296 confirm: "some_password"
1297 })
1298 |> json_response_and_validate_schema(200)
1299
1300 assert %{
1301 "access_token" => access_token,
1302 "created_at" => _,
1303 "scope" => "read write follow push",
1304 "token_type" => "Bearer"
1305 } = response
1306
1307 response =
1308 build_conn()
1309 |> Plug.Conn.put_req_header("authorization", "Bearer " <> access_token)
1310 |> get("/api/v1/accounts/verify_credentials")
1311 |> json_response_and_validate_schema(200)
1312
1313 assert %{
1314 "acct" => "Lain",
1315 "bot" => false,
1316 "display_name" => "Lain",
1317 "follow_requests_count" => 0,
1318 "followers_count" => 0,
1319 "following_count" => 0,
1320 "locked" => false,
1321 "note" => "",
1322 "source" => %{
1323 "fields" => [],
1324 "note" => "",
1325 "pleroma" => %{
1326 "actor_type" => "Person",
1327 "discoverable" => false,
1328 "no_rich_text" => false,
1329 "show_role" => true
1330 },
1331 "privacy" => "public",
1332 "sensitive" => false
1333 },
1334 "statuses_count" => 0,
1335 "username" => "Lain"
1336 } = response
1337 end
1338 end
1339
1340 describe "create account by app / rate limit" do
1341 setup do: clear_config([:rate_limit, :app_account_creation], {10_000, 2})
1342
1343 test "respects rate limit setting", %{conn: conn} do
1344 app_token = insert(:oauth_token, user: nil)
1345
1346 conn =
1347 conn
1348 |> put_req_header("authorization", "Bearer " <> app_token.token)
1349 |> Map.put(:remote_ip, {15, 15, 15, 15})
1350 |> put_req_header("content-type", "multipart/form-data")
1351
1352 for i <- 1..2 do
1353 conn =
1354 conn
1355 |> post("/api/v1/accounts", %{
1356 username: "#{i}lain",
1357 email: "#{i}lain@example.org",
1358 password: "PlzDontHackLain",
1359 agreement: true
1360 })
1361
1362 %{
1363 "access_token" => token,
1364 "created_at" => _created_at,
1365 "scope" => _scope,
1366 "token_type" => "Bearer"
1367 } = json_response_and_validate_schema(conn, 200)
1368
1369 token_from_db = Repo.get_by(Token, token: token)
1370 assert token_from_db
1371 token_from_db = Repo.preload(token_from_db, :user)
1372 assert token_from_db.user
1373 end
1374
1375 conn =
1376 post(conn, "/api/v1/accounts", %{
1377 username: "6lain",
1378 email: "6lain@example.org",
1379 password: "PlzDontHackLain",
1380 agreement: true
1381 })
1382
1383 assert json_response_and_validate_schema(conn, :too_many_requests) == %{
1384 "error" => "Throttled"
1385 }
1386 end
1387 end
1388
1389 describe "create account with enabled captcha" do
1390 setup %{conn: conn} do
1391 app_token = insert(:oauth_token, user: nil)
1392
1393 conn =
1394 conn
1395 |> put_req_header("authorization", "Bearer " <> app_token.token)
1396 |> put_req_header("content-type", "multipart/form-data")
1397
1398 [conn: conn]
1399 end
1400
1401 setup do: clear_config([Pleroma.Captcha, :enabled], true)
1402
1403 test "creates an account and returns 200 if captcha is valid", %{conn: conn} do
1404 %{token: token, answer_data: answer_data} = Pleroma.Captcha.new()
1405
1406 params = %{
1407 username: "lain",
1408 email: "lain@example.org",
1409 password: "PlzDontHackLain",
1410 agreement: true,
1411 captcha_solution: Pleroma.Captcha.Mock.solution(),
1412 captcha_token: token,
1413 captcha_answer_data: answer_data
1414 }
1415
1416 assert %{
1417 "access_token" => access_token,
1418 "created_at" => _,
1419 "scope" => "read",
1420 "token_type" => "Bearer"
1421 } =
1422 conn
1423 |> post("/api/v1/accounts", params)
1424 |> json_response_and_validate_schema(:ok)
1425
1426 assert Token |> Repo.get_by(token: access_token) |> Repo.preload(:user) |> Map.get(:user)
1427 end
1428
1429 test "returns 400 if any captcha field is not provided", %{conn: conn} do
1430 captcha_fields = [:captcha_solution, :captcha_token, :captcha_answer_data]
1431
1432 valid_params = %{
1433 username: "lain",
1434 email: "lain@example.org",
1435 password: "PlzDontHackLain",
1436 agreement: true,
1437 captcha_solution: "xx",
1438 captcha_token: "xx",
1439 captcha_answer_data: "xx"
1440 }
1441
1442 for field <- captcha_fields do
1443 expected = %{
1444 "error" => "{\"captcha\":[\"Invalid CAPTCHA (Missing parameter: #{field})\"]}"
1445 }
1446
1447 assert expected ==
1448 conn
1449 |> post("/api/v1/accounts", Map.delete(valid_params, field))
1450 |> json_response_and_validate_schema(:bad_request)
1451 end
1452 end
1453
1454 test "returns an error if captcha is invalid", %{conn: conn} do
1455 params = %{
1456 username: "lain",
1457 email: "lain@example.org",
1458 password: "PlzDontHackLain",
1459 agreement: true,
1460 captcha_solution: "cofe",
1461 captcha_token: "cofe",
1462 captcha_answer_data: "cofe"
1463 }
1464
1465 assert %{"error" => "{\"captcha\":[\"Invalid answer data\"]}"} ==
1466 conn
1467 |> post("/api/v1/accounts", params)
1468 |> json_response_and_validate_schema(:bad_request)
1469 end
1470 end
1471
1472 describe "GET /api/v1/accounts/:id/lists - account_lists" do
1473 test "returns lists to which the account belongs" do
1474 %{user: user, conn: conn} = oauth_access(["read:lists"])
1475 other_user = insert(:user)
1476 assert {:ok, %Pleroma.List{id: _list_id} = list} = Pleroma.List.create("Test List", user)
1477 {:ok, %{following: _following}} = Pleroma.List.follow(list, other_user)
1478
1479 assert [%{"id" => _list_id, "title" => "Test List"}] =
1480 conn
1481 |> get("/api/v1/accounts/#{other_user.id}/lists")
1482 |> json_response_and_validate_schema(200)
1483 end
1484 end
1485
1486 describe "verify_credentials" do
1487 test "verify_credentials" do
1488 %{user: user, conn: conn} = oauth_access(["read:accounts"])
1489
1490 [notification | _] =
1491 insert_list(7, :notification, user: user, activity: insert(:note_activity))
1492
1493 Pleroma.Notification.set_read_up_to(user, notification.id)
1494 conn = get(conn, "/api/v1/accounts/verify_credentials")
1495
1496 response = json_response_and_validate_schema(conn, 200)
1497
1498 assert %{"id" => id, "source" => %{"privacy" => "public"}} = response
1499 assert response["pleroma"]["chat_token"]
1500 assert response["pleroma"]["unread_notifications_count"] == 6
1501 assert id == to_string(user.id)
1502 end
1503
1504 test "verify_credentials default scope unlisted" do
1505 user = insert(:user, default_scope: "unlisted")
1506 %{conn: conn} = oauth_access(["read:accounts"], user: user)
1507
1508 conn = get(conn, "/api/v1/accounts/verify_credentials")
1509
1510 assert %{"id" => id, "source" => %{"privacy" => "unlisted"}} =
1511 json_response_and_validate_schema(conn, 200)
1512
1513 assert id == to_string(user.id)
1514 end
1515
1516 test "locked accounts" do
1517 user = insert(:user, default_scope: "private")
1518 %{conn: conn} = oauth_access(["read:accounts"], user: user)
1519
1520 conn = get(conn, "/api/v1/accounts/verify_credentials")
1521
1522 assert %{"id" => id, "source" => %{"privacy" => "private"}} =
1523 json_response_and_validate_schema(conn, 200)
1524
1525 assert id == to_string(user.id)
1526 end
1527 end
1528
1529 describe "user relationships" do
1530 setup do: oauth_access(["read:follows"])
1531
1532 test "returns the relationships for the current user", %{user: user, conn: conn} do
1533 %{id: other_user_id} = other_user = insert(:user)
1534 {:ok, _user, _other_user} = User.follow(user, other_user)
1535
1536 assert [%{"id" => ^other_user_id}] =
1537 conn
1538 |> get("/api/v1/accounts/relationships?id=#{other_user.id}")
1539 |> json_response_and_validate_schema(200)
1540
1541 assert [%{"id" => ^other_user_id}] =
1542 conn
1543 |> get("/api/v1/accounts/relationships?id[]=#{other_user.id}")
1544 |> json_response_and_validate_schema(200)
1545 end
1546
1547 test "returns an empty list on a bad request", %{conn: conn} do
1548 conn = get(conn, "/api/v1/accounts/relationships", %{})
1549
1550 assert [] = json_response_and_validate_schema(conn, 200)
1551 end
1552 end
1553
1554 test "getting a list of mutes" do
1555 %{user: user, conn: conn} = oauth_access(["read:mutes"])
1556 %{id: id1} = other_user1 = insert(:user)
1557 %{id: id2} = other_user2 = insert(:user)
1558 %{id: id3} = other_user3 = insert(:user)
1559
1560 {:ok, _user_relationships} = User.mute(user, other_user1)
1561 {:ok, _user_relationships} = User.mute(user, other_user2)
1562 {:ok, _user_relationships} = User.mute(user, other_user3)
1563
1564 result =
1565 conn
1566 |> assign(:user, user)
1567 |> get("/api/v1/mutes")
1568 |> json_response_and_validate_schema(200)
1569
1570 assert [id1, id2, id3] == Enum.map(result, & &1["id"])
1571
1572 result =
1573 conn
1574 |> assign(:user, user)
1575 |> get("/api/v1/mutes?limit=1")
1576 |> json_response_and_validate_schema(200)
1577
1578 assert [%{"id" => ^id1}] = result
1579
1580 result =
1581 conn
1582 |> assign(:user, user)
1583 |> get("/api/v1/mutes?since_id=#{id1}")
1584 |> json_response_and_validate_schema(200)
1585
1586 assert [%{"id" => ^id2}, %{"id" => ^id3}] = result
1587
1588 result =
1589 conn
1590 |> assign(:user, user)
1591 |> get("/api/v1/mutes?since_id=#{id1}&max_id=#{id3}")
1592 |> json_response_and_validate_schema(200)
1593
1594 assert [%{"id" => ^id2}] = result
1595
1596 result =
1597 conn
1598 |> assign(:user, user)
1599 |> get("/api/v1/mutes?since_id=#{id1}&limit=1")
1600 |> json_response_and_validate_schema(200)
1601
1602 assert [%{"id" => ^id2}] = result
1603 end
1604
1605 test "getting a list of blocks" do
1606 %{user: user, conn: conn} = oauth_access(["read:blocks"])
1607 %{id: id1} = other_user1 = insert(:user)
1608 %{id: id2} = other_user2 = insert(:user)
1609 %{id: id3} = other_user3 = insert(:user)
1610
1611 {:ok, _user_relationship} = User.block(user, other_user1)
1612 {:ok, _user_relationship} = User.block(user, other_user3)
1613 {:ok, _user_relationship} = User.block(user, other_user2)
1614
1615 result =
1616 conn
1617 |> assign(:user, user)
1618 |> get("/api/v1/blocks")
1619 |> json_response_and_validate_schema(200)
1620
1621 assert [id1, id2, id3] == Enum.map(result, & &1["id"])
1622
1623 result =
1624 conn
1625 |> assign(:user, user)
1626 |> get("/api/v1/blocks?limit=1")
1627 |> json_response_and_validate_schema(200)
1628
1629 assert [%{"id" => ^id1}] = result
1630
1631 result =
1632 conn
1633 |> assign(:user, user)
1634 |> get("/api/v1/blocks?since_id=#{id1}")
1635 |> json_response_and_validate_schema(200)
1636
1637 assert [%{"id" => ^id2}, %{"id" => ^id3}] = result
1638
1639 result =
1640 conn
1641 |> assign(:user, user)
1642 |> get("/api/v1/blocks?since_id=#{id1}&max_id=#{id3}")
1643 |> json_response_and_validate_schema(200)
1644
1645 assert [%{"id" => ^id2}] = result
1646
1647 result =
1648 conn
1649 |> assign(:user, user)
1650 |> get("/api/v1/blocks?since_id=#{id1}&limit=1")
1651 |> json_response_and_validate_schema(200)
1652
1653 assert [%{"id" => ^id2}] = result
1654 end
1655 end