1c310bb07193effd84cbaa5a6060128abd502eee
[akkoma] / test / pleroma / web / mastodon_api / controllers / account_controller_test.exs
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2021 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, post_1} = CommonAPI.post(user, %{status: "first post"})
475 {:ok, post_2} = CommonAPI.post(user, %{status: "second post"})
476
477 response_1 = get(conn, "/api/v1/accounts/#{user.id}/statuses?limit=1")
478 assert [res] = json_response(response_1, 200)
479 assert res["id"] == post_2.id
480
481 response_2 = get(conn, "/api/v1/accounts/#{user.id}/statuses?limit=1&max_id=#{res["id"]}")
482 assert [res] = json_response(response_2, 200)
483 assert res["id"] == post_1.id
484
485 refute response_1 == response_2
486 end
487 end
488
489 defp local_and_remote_activities(%{local: local, remote: remote}) do
490 insert(:note_activity, user: local)
491 insert(:note_activity, user: remote, local: false)
492
493 :ok
494 end
495
496 describe "statuses with restrict unauthenticated profiles for local and remote" do
497 setup do: local_and_remote_users()
498 setup :local_and_remote_activities
499
500 setup do: clear_config([:restrict_unauthenticated, :profiles, :local], true)
501
502 setup do: clear_config([:restrict_unauthenticated, :profiles, :remote], true)
503
504 test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do
505 assert %{"error" => "This API requires an authenticated user"} ==
506 conn
507 |> get("/api/v1/accounts/#{local.id}/statuses")
508 |> json_response_and_validate_schema(:unauthorized)
509
510 assert %{"error" => "This API requires an authenticated user"} ==
511 conn
512 |> get("/api/v1/accounts/#{remote.id}/statuses")
513 |> json_response_and_validate_schema(:unauthorized)
514 end
515
516 test "if user is authenticated", %{local: local, remote: remote} do
517 %{conn: conn} = oauth_access(["read"])
518
519 res_conn = get(conn, "/api/v1/accounts/#{local.id}/statuses")
520 assert length(json_response_and_validate_schema(res_conn, 200)) == 1
521
522 res_conn = get(conn, "/api/v1/accounts/#{remote.id}/statuses")
523 assert length(json_response_and_validate_schema(res_conn, 200)) == 1
524 end
525 end
526
527 describe "statuses with restrict unauthenticated profiles for local" do
528 setup do: local_and_remote_users()
529 setup :local_and_remote_activities
530
531 setup do: clear_config([:restrict_unauthenticated, :profiles, :local], true)
532
533 test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do
534 assert %{"error" => "This API requires an authenticated user"} ==
535 conn
536 |> get("/api/v1/accounts/#{local.id}/statuses")
537 |> json_response_and_validate_schema(:unauthorized)
538
539 res_conn = get(conn, "/api/v1/accounts/#{remote.id}/statuses")
540 assert length(json_response_and_validate_schema(res_conn, 200)) == 1
541 end
542
543 test "if user is authenticated", %{local: local, remote: remote} do
544 %{conn: conn} = oauth_access(["read"])
545
546 res_conn = get(conn, "/api/v1/accounts/#{local.id}/statuses")
547 assert length(json_response_and_validate_schema(res_conn, 200)) == 1
548
549 res_conn = get(conn, "/api/v1/accounts/#{remote.id}/statuses")
550 assert length(json_response_and_validate_schema(res_conn, 200)) == 1
551 end
552 end
553
554 describe "statuses with restrict unauthenticated profiles for remote" do
555 setup do: local_and_remote_users()
556 setup :local_and_remote_activities
557
558 setup do: clear_config([:restrict_unauthenticated, :profiles, :remote], true)
559
560 test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do
561 res_conn = get(conn, "/api/v1/accounts/#{local.id}/statuses")
562 assert length(json_response_and_validate_schema(res_conn, 200)) == 1
563
564 assert %{"error" => "This API requires an authenticated user"} ==
565 conn
566 |> get("/api/v1/accounts/#{remote.id}/statuses")
567 |> json_response_and_validate_schema(:unauthorized)
568 end
569
570 test "if user is authenticated", %{local: local, remote: remote} do
571 %{conn: conn} = oauth_access(["read"])
572
573 res_conn = get(conn, "/api/v1/accounts/#{local.id}/statuses")
574 assert length(json_response_and_validate_schema(res_conn, 200)) == 1
575
576 res_conn = get(conn, "/api/v1/accounts/#{remote.id}/statuses")
577 assert length(json_response_and_validate_schema(res_conn, 200)) == 1
578 end
579 end
580
581 describe "followers" do
582 setup do: oauth_access(["read:accounts"])
583
584 test "getting followers", %{user: user, conn: conn} do
585 other_user = insert(:user)
586 {:ok, %{id: user_id}, other_user} = User.follow(user, other_user)
587
588 conn = get(conn, "/api/v1/accounts/#{other_user.id}/followers")
589
590 assert [%{"id" => ^user_id}] = json_response_and_validate_schema(conn, 200)
591 end
592
593 test "getting followers, hide_followers", %{user: user, conn: conn} do
594 other_user = insert(:user, hide_followers: true)
595 {:ok, _user, _other_user} = User.follow(user, other_user)
596
597 conn = get(conn, "/api/v1/accounts/#{other_user.id}/followers")
598
599 assert [] == json_response_and_validate_schema(conn, 200)
600 end
601
602 test "getting followers, hide_followers, same user requesting" do
603 user = insert(:user)
604 other_user = insert(:user, hide_followers: true)
605 {:ok, _user, _other_user} = User.follow(user, other_user)
606
607 conn =
608 build_conn()
609 |> assign(:user, other_user)
610 |> assign(:token, insert(:oauth_token, user: other_user, scopes: ["read:accounts"]))
611 |> get("/api/v1/accounts/#{other_user.id}/followers")
612
613 refute [] == json_response_and_validate_schema(conn, 200)
614 end
615
616 test "getting followers, pagination", %{user: user, conn: conn} do
617 {:ok, %User{id: follower1_id}, _user} = :user |> insert() |> User.follow(user)
618 {:ok, %User{id: follower2_id}, _user} = :user |> insert() |> User.follow(user)
619 {:ok, %User{id: follower3_id}, _user} = :user |> insert() |> User.follow(user)
620
621 assert [%{"id" => ^follower3_id}, %{"id" => ^follower2_id}] =
622 conn
623 |> get("/api/v1/accounts/#{user.id}/followers?since_id=#{follower1_id}")
624 |> json_response_and_validate_schema(200)
625
626 assert [%{"id" => ^follower2_id}, %{"id" => ^follower1_id}] =
627 conn
628 |> get("/api/v1/accounts/#{user.id}/followers?max_id=#{follower3_id}")
629 |> json_response_and_validate_schema(200)
630
631 assert [%{"id" => ^follower2_id}, %{"id" => ^follower1_id}] =
632 conn
633 |> get(
634 "/api/v1/accounts/#{user.id}/followers?id=#{user.id}&limit=20&max_id=#{
635 follower3_id
636 }"
637 )
638 |> json_response_and_validate_schema(200)
639
640 res_conn = get(conn, "/api/v1/accounts/#{user.id}/followers?limit=1&max_id=#{follower3_id}")
641
642 assert [%{"id" => ^follower2_id}] = json_response_and_validate_schema(res_conn, 200)
643
644 assert [link_header] = get_resp_header(res_conn, "link")
645 assert link_header =~ ~r/min_id=#{follower2_id}/
646 assert link_header =~ ~r/max_id=#{follower2_id}/
647 end
648 end
649
650 describe "following" do
651 setup do: oauth_access(["read:accounts"])
652
653 test "getting following", %{user: user, conn: conn} do
654 other_user = insert(:user)
655 {:ok, user, other_user} = User.follow(user, other_user)
656
657 conn = get(conn, "/api/v1/accounts/#{user.id}/following")
658
659 assert [%{"id" => id}] = json_response_and_validate_schema(conn, 200)
660 assert id == to_string(other_user.id)
661 end
662
663 test "getting following, hide_follows, other user requesting" do
664 user = insert(:user, hide_follows: true)
665 other_user = insert(:user)
666 {:ok, user, other_user} = User.follow(user, other_user)
667
668 conn =
669 build_conn()
670 |> assign(:user, other_user)
671 |> assign(:token, insert(:oauth_token, user: other_user, scopes: ["read:accounts"]))
672 |> get("/api/v1/accounts/#{user.id}/following")
673
674 assert [] == json_response_and_validate_schema(conn, 200)
675 end
676
677 test "getting following, hide_follows, same user requesting" do
678 user = insert(:user, hide_follows: true)
679 other_user = insert(:user)
680 {:ok, user, _other_user} = User.follow(user, other_user)
681
682 conn =
683 build_conn()
684 |> assign(:user, user)
685 |> assign(:token, insert(:oauth_token, user: user, scopes: ["read:accounts"]))
686 |> get("/api/v1/accounts/#{user.id}/following")
687
688 refute [] == json_response_and_validate_schema(conn, 200)
689 end
690
691 test "getting following, pagination", %{user: user, conn: conn} do
692 following1 = insert(:user)
693 following2 = insert(:user)
694 following3 = insert(:user)
695 {:ok, _, _} = User.follow(user, following1)
696 {:ok, _, _} = User.follow(user, following2)
697 {:ok, _, _} = User.follow(user, following3)
698
699 res_conn = get(conn, "/api/v1/accounts/#{user.id}/following?since_id=#{following1.id}")
700
701 assert [%{"id" => id3}, %{"id" => id2}] = json_response_and_validate_schema(res_conn, 200)
702 assert id3 == following3.id
703 assert id2 == following2.id
704
705 res_conn = get(conn, "/api/v1/accounts/#{user.id}/following?max_id=#{following3.id}")
706
707 assert [%{"id" => id2}, %{"id" => id1}] = json_response_and_validate_schema(res_conn, 200)
708 assert id2 == following2.id
709 assert id1 == following1.id
710
711 res_conn =
712 get(
713 conn,
714 "/api/v1/accounts/#{user.id}/following?id=#{user.id}&limit=20&max_id=#{following3.id}"
715 )
716
717 assert [%{"id" => id2}, %{"id" => id1}] = json_response_and_validate_schema(res_conn, 200)
718 assert id2 == following2.id
719 assert id1 == following1.id
720
721 res_conn =
722 get(conn, "/api/v1/accounts/#{user.id}/following?limit=1&max_id=#{following3.id}")
723
724 assert [%{"id" => id2}] = json_response_and_validate_schema(res_conn, 200)
725 assert id2 == following2.id
726
727 assert [link_header] = get_resp_header(res_conn, "link")
728 assert link_header =~ ~r/min_id=#{following2.id}/
729 assert link_header =~ ~r/max_id=#{following2.id}/
730 end
731 end
732
733 describe "follow/unfollow" do
734 setup do: oauth_access(["follow"])
735
736 test "following / unfollowing a user", %{conn: conn} do
737 %{id: other_user_id, nickname: other_user_nickname} = insert(:user)
738
739 assert %{"id" => _id, "following" => true} =
740 conn
741 |> post("/api/v1/accounts/#{other_user_id}/follow")
742 |> json_response_and_validate_schema(200)
743
744 assert %{"id" => _id, "following" => false} =
745 conn
746 |> post("/api/v1/accounts/#{other_user_id}/unfollow")
747 |> json_response_and_validate_schema(200)
748
749 assert %{"id" => ^other_user_id} =
750 conn
751 |> put_req_header("content-type", "application/json")
752 |> post("/api/v1/follows", %{"uri" => other_user_nickname})
753 |> json_response_and_validate_schema(200)
754 end
755
756 test "cancelling follow request", %{conn: conn} do
757 %{id: other_user_id} = insert(:user, %{is_locked: true})
758
759 assert %{"id" => ^other_user_id, "following" => false, "requested" => true} =
760 conn
761 |> post("/api/v1/accounts/#{other_user_id}/follow")
762 |> json_response_and_validate_schema(:ok)
763
764 assert %{"id" => ^other_user_id, "following" => false, "requested" => false} =
765 conn
766 |> post("/api/v1/accounts/#{other_user_id}/unfollow")
767 |> json_response_and_validate_schema(:ok)
768 end
769
770 test "following without reblogs" do
771 %{conn: conn} = oauth_access(["follow", "read:statuses"])
772 followed = insert(:user)
773 other_user = insert(:user)
774
775 ret_conn =
776 conn
777 |> put_req_header("content-type", "application/json")
778 |> post("/api/v1/accounts/#{followed.id}/follow", %{reblogs: false})
779
780 assert %{"showing_reblogs" => false} = json_response_and_validate_schema(ret_conn, 200)
781
782 {:ok, activity} = CommonAPI.post(other_user, %{status: "hey"})
783 {:ok, %{id: reblog_id}} = CommonAPI.repeat(activity.id, followed)
784
785 assert [] ==
786 conn
787 |> get("/api/v1/timelines/home")
788 |> json_response(200)
789
790 assert %{"showing_reblogs" => true} =
791 conn
792 |> put_req_header("content-type", "application/json")
793 |> post("/api/v1/accounts/#{followed.id}/follow", %{reblogs: true})
794 |> json_response_and_validate_schema(200)
795
796 assert [%{"id" => ^reblog_id}] =
797 conn
798 |> get("/api/v1/timelines/home")
799 |> json_response(200)
800 end
801
802 test "following with reblogs" do
803 %{conn: conn} = oauth_access(["follow", "read:statuses"])
804 followed = insert(:user)
805 other_user = insert(:user)
806
807 ret_conn = post(conn, "/api/v1/accounts/#{followed.id}/follow")
808
809 assert %{"showing_reblogs" => true} = json_response_and_validate_schema(ret_conn, 200)
810
811 {:ok, activity} = CommonAPI.post(other_user, %{status: "hey"})
812 {:ok, %{id: reblog_id}} = CommonAPI.repeat(activity.id, followed)
813
814 assert [%{"id" => ^reblog_id}] =
815 conn
816 |> get("/api/v1/timelines/home")
817 |> json_response(200)
818
819 assert %{"showing_reblogs" => false} =
820 conn
821 |> put_req_header("content-type", "application/json")
822 |> post("/api/v1/accounts/#{followed.id}/follow", %{reblogs: false})
823 |> json_response_and_validate_schema(200)
824
825 assert [] ==
826 conn
827 |> get("/api/v1/timelines/home")
828 |> json_response(200)
829 end
830
831 test "following / unfollowing errors", %{user: user, conn: conn} do
832 # self follow
833 conn_res = post(conn, "/api/v1/accounts/#{user.id}/follow")
834
835 assert %{"error" => "Can not follow yourself"} =
836 json_response_and_validate_schema(conn_res, 400)
837
838 # self unfollow
839 user = User.get_cached_by_id(user.id)
840 conn_res = post(conn, "/api/v1/accounts/#{user.id}/unfollow")
841
842 assert %{"error" => "Can not unfollow yourself"} =
843 json_response_and_validate_schema(conn_res, 400)
844
845 # self follow via uri
846 user = User.get_cached_by_id(user.id)
847
848 assert %{"error" => "Can not follow yourself"} =
849 conn
850 |> put_req_header("content-type", "multipart/form-data")
851 |> post("/api/v1/follows", %{"uri" => user.nickname})
852 |> json_response_and_validate_schema(400)
853
854 # follow non existing user
855 conn_res = post(conn, "/api/v1/accounts/doesntexist/follow")
856 assert %{"error" => "Record not found"} = json_response_and_validate_schema(conn_res, 404)
857
858 # follow non existing user via uri
859 conn_res =
860 conn
861 |> put_req_header("content-type", "multipart/form-data")
862 |> post("/api/v1/follows", %{"uri" => "doesntexist"})
863
864 assert %{"error" => "Record not found"} = json_response_and_validate_schema(conn_res, 404)
865
866 # unfollow non existing user
867 conn_res = post(conn, "/api/v1/accounts/doesntexist/unfollow")
868 assert %{"error" => "Record not found"} = json_response_and_validate_schema(conn_res, 404)
869 end
870 end
871
872 describe "mute/unmute" do
873 setup do: oauth_access(["write:mutes"])
874
875 test "with notifications", %{conn: conn} do
876 other_user = insert(:user)
877
878 assert %{"id" => _id, "muting" => true, "muting_notifications" => true} =
879 conn
880 |> post("/api/v1/accounts/#{other_user.id}/mute")
881 |> json_response_and_validate_schema(200)
882
883 conn = post(conn, "/api/v1/accounts/#{other_user.id}/unmute")
884
885 assert %{"id" => _id, "muting" => false, "muting_notifications" => false} =
886 json_response_and_validate_schema(conn, 200)
887 end
888
889 test "without notifications", %{conn: conn} do
890 other_user = insert(:user)
891
892 ret_conn =
893 conn
894 |> put_req_header("content-type", "multipart/form-data")
895 |> post("/api/v1/accounts/#{other_user.id}/mute", %{"notifications" => "false"})
896
897 assert %{"id" => _id, "muting" => true, "muting_notifications" => false} =
898 json_response_and_validate_schema(ret_conn, 200)
899
900 conn = post(conn, "/api/v1/accounts/#{other_user.id}/unmute")
901
902 assert %{"id" => _id, "muting" => false, "muting_notifications" => false} =
903 json_response_and_validate_schema(conn, 200)
904 end
905 end
906
907 describe "pinned statuses" do
908 setup do
909 user = insert(:user)
910 {:ok, activity} = CommonAPI.post(user, %{status: "HI!!!"})
911 %{conn: conn} = oauth_access(["read:statuses"], user: user)
912
913 [conn: conn, user: user, activity: activity]
914 end
915
916 test "returns pinned statuses", %{conn: conn, user: user, activity: %{id: activity_id}} do
917 {:ok, _} = CommonAPI.pin(activity_id, user)
918
919 assert [%{"id" => ^activity_id, "pinned" => true}] =
920 conn
921 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
922 |> json_response_and_validate_schema(200)
923 end
924 end
925
926 test "blocking / unblocking a user" do
927 %{conn: conn} = oauth_access(["follow"])
928 other_user = insert(:user)
929
930 ret_conn = post(conn, "/api/v1/accounts/#{other_user.id}/block")
931
932 assert %{"id" => _id, "blocking" => true} = json_response_and_validate_schema(ret_conn, 200)
933
934 conn = post(conn, "/api/v1/accounts/#{other_user.id}/unblock")
935
936 assert %{"id" => _id, "blocking" => false} = json_response_and_validate_schema(conn, 200)
937 end
938
939 describe "create account by app" do
940 setup do
941 valid_params = %{
942 username: "lain",
943 email: "lain@example.org",
944 password: "PlzDontHackLain",
945 agreement: true
946 }
947
948 [valid_params: valid_params]
949 end
950
951 test "registers and logs in without :account_activation_required / :account_approval_required",
952 %{conn: conn} do
953 clear_config([:instance, :account_activation_required], false)
954 clear_config([:instance, :account_approval_required], false)
955
956 conn =
957 conn
958 |> put_req_header("content-type", "application/json")
959 |> post("/api/v1/apps", %{
960 client_name: "client_name",
961 redirect_uris: "urn:ietf:wg:oauth:2.0:oob",
962 scopes: "read, write, follow"
963 })
964
965 assert %{
966 "client_id" => client_id,
967 "client_secret" => client_secret,
968 "id" => _,
969 "name" => "client_name",
970 "redirect_uri" => "urn:ietf:wg:oauth:2.0:oob",
971 "vapid_key" => _,
972 "website" => nil
973 } = json_response_and_validate_schema(conn, 200)
974
975 conn =
976 post(conn, "/oauth/token", %{
977 grant_type: "client_credentials",
978 client_id: client_id,
979 client_secret: client_secret
980 })
981
982 assert %{"access_token" => token, "refresh_token" => refresh, "scope" => scope} =
983 json_response(conn, 200)
984
985 assert token
986 token_from_db = Repo.get_by(Token, token: token)
987 assert token_from_db
988 assert refresh
989 assert scope == "read write follow"
990
991 clear_config([User, :email_blacklist], ["example.org"])
992
993 params = %{
994 username: "lain",
995 email: "lain@example.org",
996 password: "PlzDontHackLain",
997 bio: "Test Bio",
998 agreement: true
999 }
1000
1001 conn =
1002 build_conn()
1003 |> put_req_header("content-type", "multipart/form-data")
1004 |> put_req_header("authorization", "Bearer " <> token)
1005 |> post("/api/v1/accounts", params)
1006
1007 assert %{"error" => "{\"email\":[\"Invalid email\"]}"} =
1008 json_response_and_validate_schema(conn, 400)
1009
1010 Pleroma.Config.put([User, :email_blacklist], [])
1011
1012 conn =
1013 build_conn()
1014 |> put_req_header("content-type", "multipart/form-data")
1015 |> put_req_header("authorization", "Bearer " <> token)
1016 |> post("/api/v1/accounts", params)
1017
1018 %{
1019 "access_token" => token,
1020 "created_at" => _created_at,
1021 "scope" => ^scope,
1022 "token_type" => "Bearer"
1023 } = json_response_and_validate_schema(conn, 200)
1024
1025 token_from_db = Repo.get_by(Token, token: token)
1026 assert token_from_db
1027 user = Repo.preload(token_from_db, :user).user
1028
1029 assert user
1030 refute user.confirmation_pending
1031 assert user.is_approved
1032 end
1033
1034 test "registers but does not log in with :account_activation_required", %{conn: conn} do
1035 clear_config([:instance, :account_activation_required], true)
1036 clear_config([:instance, :account_approval_required], false)
1037
1038 conn =
1039 conn
1040 |> put_req_header("content-type", "application/json")
1041 |> post("/api/v1/apps", %{
1042 client_name: "client_name",
1043 redirect_uris: "urn:ietf:wg:oauth:2.0:oob",
1044 scopes: "read, write, follow"
1045 })
1046
1047 assert %{
1048 "client_id" => client_id,
1049 "client_secret" => client_secret,
1050 "id" => _,
1051 "name" => "client_name",
1052 "redirect_uri" => "urn:ietf:wg:oauth:2.0:oob",
1053 "vapid_key" => _,
1054 "website" => nil
1055 } = json_response_and_validate_schema(conn, 200)
1056
1057 conn =
1058 post(conn, "/oauth/token", %{
1059 grant_type: "client_credentials",
1060 client_id: client_id,
1061 client_secret: client_secret
1062 })
1063
1064 assert %{"access_token" => token, "refresh_token" => refresh, "scope" => scope} =
1065 json_response(conn, 200)
1066
1067 assert token
1068 token_from_db = Repo.get_by(Token, token: token)
1069 assert token_from_db
1070 assert refresh
1071 assert scope == "read write follow"
1072
1073 conn =
1074 build_conn()
1075 |> put_req_header("content-type", "multipart/form-data")
1076 |> put_req_header("authorization", "Bearer " <> token)
1077 |> post("/api/v1/accounts", %{
1078 username: "lain",
1079 email: "lain@example.org",
1080 password: "PlzDontHackLain",
1081 bio: "Test Bio",
1082 agreement: true
1083 })
1084
1085 response = json_response_and_validate_schema(conn, 200)
1086 assert %{"identifier" => "missing_confirmed_email"} = response
1087 refute response["access_token"]
1088 refute response["token_type"]
1089
1090 user = Repo.get_by(User, email: "lain@example.org")
1091 assert user.confirmation_pending
1092 end
1093
1094 test "registers but does not log in with :account_approval_required", %{conn: conn} do
1095 clear_config([:instance, :account_approval_required], true)
1096 clear_config([:instance, :account_activation_required], false)
1097
1098 conn =
1099 conn
1100 |> put_req_header("content-type", "application/json")
1101 |> post("/api/v1/apps", %{
1102 client_name: "client_name",
1103 redirect_uris: "urn:ietf:wg:oauth:2.0:oob",
1104 scopes: "read, write, follow"
1105 })
1106
1107 assert %{
1108 "client_id" => client_id,
1109 "client_secret" => client_secret,
1110 "id" => _,
1111 "name" => "client_name",
1112 "redirect_uri" => "urn:ietf:wg:oauth:2.0:oob",
1113 "vapid_key" => _,
1114 "website" => nil
1115 } = json_response_and_validate_schema(conn, 200)
1116
1117 conn =
1118 post(conn, "/oauth/token", %{
1119 grant_type: "client_credentials",
1120 client_id: client_id,
1121 client_secret: client_secret
1122 })
1123
1124 assert %{"access_token" => token, "refresh_token" => refresh, "scope" => scope} =
1125 json_response(conn, 200)
1126
1127 assert token
1128 token_from_db = Repo.get_by(Token, token: token)
1129 assert token_from_db
1130 assert refresh
1131 assert scope == "read write follow"
1132
1133 conn =
1134 build_conn()
1135 |> put_req_header("content-type", "multipart/form-data")
1136 |> put_req_header("authorization", "Bearer " <> token)
1137 |> post("/api/v1/accounts", %{
1138 username: "lain",
1139 email: "lain@example.org",
1140 password: "PlzDontHackLain",
1141 bio: "Test Bio",
1142 agreement: true,
1143 reason: "I'm a cool dude, bro"
1144 })
1145
1146 response = json_response_and_validate_schema(conn, 200)
1147 assert %{"identifier" => "awaiting_approval"} = response
1148 refute response["access_token"]
1149 refute response["token_type"]
1150
1151 user = Repo.get_by(User, email: "lain@example.org")
1152
1153 refute user.is_approved
1154 assert user.registration_reason == "I'm a cool dude, bro"
1155 end
1156
1157 test "returns error when user already registred", %{conn: conn, valid_params: valid_params} do
1158 _user = insert(:user, email: "lain@example.org")
1159 app_token = insert(:oauth_token, user: nil)
1160
1161 res =
1162 conn
1163 |> put_req_header("authorization", "Bearer " <> app_token.token)
1164 |> put_req_header("content-type", "application/json")
1165 |> post("/api/v1/accounts", valid_params)
1166
1167 assert json_response_and_validate_schema(res, 400) == %{
1168 "error" => "{\"email\":[\"has already been taken\"]}"
1169 }
1170 end
1171
1172 test "returns bad_request if missing required params", %{
1173 conn: conn,
1174 valid_params: valid_params
1175 } do
1176 app_token = insert(:oauth_token, user: nil)
1177
1178 conn =
1179 conn
1180 |> put_req_header("authorization", "Bearer " <> app_token.token)
1181 |> put_req_header("content-type", "application/json")
1182
1183 res = post(conn, "/api/v1/accounts", valid_params)
1184 assert json_response_and_validate_schema(res, 200)
1185
1186 [{127, 0, 0, 1}, {127, 0, 0, 2}, {127, 0, 0, 3}, {127, 0, 0, 4}]
1187 |> Stream.zip(Map.delete(valid_params, :email))
1188 |> Enum.each(fn {ip, {attr, _}} ->
1189 res =
1190 conn
1191 |> Map.put(:remote_ip, ip)
1192 |> post("/api/v1/accounts", Map.delete(valid_params, attr))
1193 |> json_response_and_validate_schema(400)
1194
1195 assert res == %{
1196 "error" => "Missing field: #{attr}.",
1197 "errors" => [
1198 %{
1199 "message" => "Missing field: #{attr}",
1200 "source" => %{"pointer" => "/#{attr}"},
1201 "title" => "Invalid value"
1202 }
1203 ]
1204 }
1205 end)
1206 end
1207
1208 test "returns bad_request if missing email params when :account_activation_required is enabled",
1209 %{conn: conn, valid_params: valid_params} do
1210 clear_config([:instance, :account_activation_required], true)
1211
1212 app_token = insert(:oauth_token, user: nil)
1213
1214 conn =
1215 conn
1216 |> put_req_header("authorization", "Bearer " <> app_token.token)
1217 |> put_req_header("content-type", "application/json")
1218
1219 res =
1220 conn
1221 |> Map.put(:remote_ip, {127, 0, 0, 5})
1222 |> post("/api/v1/accounts", Map.delete(valid_params, :email))
1223
1224 assert json_response_and_validate_schema(res, 400) ==
1225 %{"error" => "Missing parameter: email"}
1226
1227 res =
1228 conn
1229 |> Map.put(:remote_ip, {127, 0, 0, 6})
1230 |> post("/api/v1/accounts", Map.put(valid_params, :email, ""))
1231
1232 assert json_response_and_validate_schema(res, 400) == %{
1233 "error" => "{\"email\":[\"can't be blank\"]}"
1234 }
1235 end
1236
1237 test "allow registration without an email", %{conn: conn, valid_params: valid_params} do
1238 app_token = insert(:oauth_token, user: nil)
1239 conn = put_req_header(conn, "authorization", "Bearer " <> app_token.token)
1240
1241 res =
1242 conn
1243 |> put_req_header("content-type", "application/json")
1244 |> Map.put(:remote_ip, {127, 0, 0, 7})
1245 |> post("/api/v1/accounts", Map.delete(valid_params, :email))
1246
1247 assert json_response_and_validate_schema(res, 200)
1248 end
1249
1250 test "allow registration with an empty email", %{conn: conn, valid_params: valid_params} do
1251 app_token = insert(:oauth_token, user: nil)
1252 conn = put_req_header(conn, "authorization", "Bearer " <> app_token.token)
1253
1254 res =
1255 conn
1256 |> put_req_header("content-type", "application/json")
1257 |> Map.put(:remote_ip, {127, 0, 0, 8})
1258 |> post("/api/v1/accounts", Map.put(valid_params, :email, ""))
1259
1260 assert json_response_and_validate_schema(res, 200)
1261 end
1262
1263 test "returns forbidden if token is invalid", %{conn: conn, valid_params: valid_params} do
1264 res =
1265 conn
1266 |> put_req_header("authorization", "Bearer " <> "invalid-token")
1267 |> put_req_header("content-type", "multipart/form-data")
1268 |> post("/api/v1/accounts", valid_params)
1269
1270 assert json_response_and_validate_schema(res, 403) == %{"error" => "Invalid credentials"}
1271 end
1272
1273 test "registration from trusted app" do
1274 clear_config([Pleroma.Captcha, :enabled], true)
1275 app = insert(:oauth_app, trusted: true, scopes: ["read", "write", "follow", "push"])
1276
1277 conn =
1278 build_conn()
1279 |> post("/oauth/token", %{
1280 "grant_type" => "client_credentials",
1281 "client_id" => app.client_id,
1282 "client_secret" => app.client_secret
1283 })
1284
1285 assert %{"access_token" => token, "token_type" => "Bearer"} = json_response(conn, 200)
1286
1287 response =
1288 build_conn()
1289 |> Plug.Conn.put_req_header("authorization", "Bearer " <> token)
1290 |> put_req_header("content-type", "multipart/form-data")
1291 |> post("/api/v1/accounts", %{
1292 nickname: "nickanme",
1293 agreement: true,
1294 email: "email@example.com",
1295 fullname: "Lain",
1296 username: "Lain",
1297 password: "some_password",
1298 confirm: "some_password"
1299 })
1300 |> json_response_and_validate_schema(200)
1301
1302 assert %{
1303 "access_token" => access_token,
1304 "created_at" => _,
1305 "scope" => "read write follow push",
1306 "token_type" => "Bearer"
1307 } = response
1308
1309 response =
1310 build_conn()
1311 |> Plug.Conn.put_req_header("authorization", "Bearer " <> access_token)
1312 |> get("/api/v1/accounts/verify_credentials")
1313 |> json_response_and_validate_schema(200)
1314
1315 assert %{
1316 "acct" => "Lain",
1317 "bot" => false,
1318 "display_name" => "Lain",
1319 "follow_requests_count" => 0,
1320 "followers_count" => 0,
1321 "following_count" => 0,
1322 "locked" => false,
1323 "note" => "",
1324 "source" => %{
1325 "fields" => [],
1326 "note" => "",
1327 "pleroma" => %{
1328 "actor_type" => "Person",
1329 "discoverable" => false,
1330 "no_rich_text" => false,
1331 "show_role" => true
1332 },
1333 "privacy" => "public",
1334 "sensitive" => false
1335 },
1336 "statuses_count" => 0,
1337 "username" => "Lain"
1338 } = response
1339 end
1340 end
1341
1342 describe "create account by app / rate limit" do
1343 setup do: clear_config([:rate_limit, :app_account_creation], {10_000, 2})
1344
1345 test "respects rate limit setting", %{conn: conn} do
1346 app_token = insert(:oauth_token, user: nil)
1347
1348 conn =
1349 conn
1350 |> put_req_header("authorization", "Bearer " <> app_token.token)
1351 |> Map.put(:remote_ip, {15, 15, 15, 15})
1352 |> put_req_header("content-type", "multipart/form-data")
1353
1354 for i <- 1..2 do
1355 conn =
1356 conn
1357 |> post("/api/v1/accounts", %{
1358 username: "#{i}lain",
1359 email: "#{i}lain@example.org",
1360 password: "PlzDontHackLain",
1361 agreement: true
1362 })
1363
1364 %{
1365 "access_token" => token,
1366 "created_at" => _created_at,
1367 "scope" => _scope,
1368 "token_type" => "Bearer"
1369 } = json_response_and_validate_schema(conn, 200)
1370
1371 token_from_db = Repo.get_by(Token, token: token)
1372 assert token_from_db
1373 token_from_db = Repo.preload(token_from_db, :user)
1374 assert token_from_db.user
1375 end
1376
1377 conn =
1378 post(conn, "/api/v1/accounts", %{
1379 username: "6lain",
1380 email: "6lain@example.org",
1381 password: "PlzDontHackLain",
1382 agreement: true
1383 })
1384
1385 assert json_response_and_validate_schema(conn, :too_many_requests) == %{
1386 "error" => "Throttled"
1387 }
1388 end
1389 end
1390
1391 describe "create account with enabled captcha" do
1392 setup %{conn: conn} do
1393 app_token = insert(:oauth_token, user: nil)
1394
1395 conn =
1396 conn
1397 |> put_req_header("authorization", "Bearer " <> app_token.token)
1398 |> put_req_header("content-type", "multipart/form-data")
1399
1400 [conn: conn]
1401 end
1402
1403 setup do: clear_config([Pleroma.Captcha, :enabled], true)
1404
1405 test "creates an account and returns 200 if captcha is valid", %{conn: conn} do
1406 %{token: token, answer_data: answer_data} = Pleroma.Captcha.new()
1407
1408 params = %{
1409 username: "lain",
1410 email: "lain@example.org",
1411 password: "PlzDontHackLain",
1412 agreement: true,
1413 captcha_solution: Pleroma.Captcha.Mock.solution(),
1414 captcha_token: token,
1415 captcha_answer_data: answer_data
1416 }
1417
1418 assert %{
1419 "access_token" => access_token,
1420 "created_at" => _,
1421 "scope" => "read",
1422 "token_type" => "Bearer"
1423 } =
1424 conn
1425 |> post("/api/v1/accounts", params)
1426 |> json_response_and_validate_schema(:ok)
1427
1428 assert Token |> Repo.get_by(token: access_token) |> Repo.preload(:user) |> Map.get(:user)
1429 end
1430
1431 test "returns 400 if any captcha field is not provided", %{conn: conn} do
1432 captcha_fields = [:captcha_solution, :captcha_token, :captcha_answer_data]
1433
1434 valid_params = %{
1435 username: "lain",
1436 email: "lain@example.org",
1437 password: "PlzDontHackLain",
1438 agreement: true,
1439 captcha_solution: "xx",
1440 captcha_token: "xx",
1441 captcha_answer_data: "xx"
1442 }
1443
1444 for field <- captcha_fields do
1445 expected = %{
1446 "error" => "{\"captcha\":[\"Invalid CAPTCHA (Missing parameter: #{field})\"]}"
1447 }
1448
1449 assert expected ==
1450 conn
1451 |> post("/api/v1/accounts", Map.delete(valid_params, field))
1452 |> json_response_and_validate_schema(:bad_request)
1453 end
1454 end
1455
1456 test "returns an error if captcha is invalid", %{conn: conn} do
1457 params = %{
1458 username: "lain",
1459 email: "lain@example.org",
1460 password: "PlzDontHackLain",
1461 agreement: true,
1462 captcha_solution: "cofe",
1463 captcha_token: "cofe",
1464 captcha_answer_data: "cofe"
1465 }
1466
1467 assert %{"error" => "{\"captcha\":[\"Invalid answer data\"]}"} ==
1468 conn
1469 |> post("/api/v1/accounts", params)
1470 |> json_response_and_validate_schema(:bad_request)
1471 end
1472 end
1473
1474 describe "GET /api/v1/accounts/:id/lists - account_lists" do
1475 test "returns lists to which the account belongs" do
1476 %{user: user, conn: conn} = oauth_access(["read:lists"])
1477 other_user = insert(:user)
1478 assert {:ok, %Pleroma.List{id: _list_id} = list} = Pleroma.List.create("Test List", user)
1479 {:ok, %{following: _following}} = Pleroma.List.follow(list, other_user)
1480
1481 assert [%{"id" => _list_id, "title" => "Test List"}] =
1482 conn
1483 |> get("/api/v1/accounts/#{other_user.id}/lists")
1484 |> json_response_and_validate_schema(200)
1485 end
1486 end
1487
1488 describe "verify_credentials" do
1489 test "verify_credentials" do
1490 %{user: user, conn: conn} = oauth_access(["read:accounts"])
1491
1492 [notification | _] =
1493 insert_list(7, :notification, user: user, activity: insert(:note_activity))
1494
1495 Pleroma.Notification.set_read_up_to(user, notification.id)
1496 conn = get(conn, "/api/v1/accounts/verify_credentials")
1497
1498 response = json_response_and_validate_schema(conn, 200)
1499
1500 assert %{"id" => id, "source" => %{"privacy" => "public"}} = response
1501 assert response["pleroma"]["chat_token"]
1502 assert response["pleroma"]["unread_notifications_count"] == 6
1503 assert id == to_string(user.id)
1504 end
1505
1506 test "verify_credentials default scope unlisted" do
1507 user = insert(:user, default_scope: "unlisted")
1508 %{conn: conn} = oauth_access(["read:accounts"], user: user)
1509
1510 conn = get(conn, "/api/v1/accounts/verify_credentials")
1511
1512 assert %{"id" => id, "source" => %{"privacy" => "unlisted"}} =
1513 json_response_and_validate_schema(conn, 200)
1514
1515 assert id == to_string(user.id)
1516 end
1517
1518 test "locked accounts" do
1519 user = insert(:user, default_scope: "private")
1520 %{conn: conn} = oauth_access(["read:accounts"], user: user)
1521
1522 conn = get(conn, "/api/v1/accounts/verify_credentials")
1523
1524 assert %{"id" => id, "source" => %{"privacy" => "private"}} =
1525 json_response_and_validate_schema(conn, 200)
1526
1527 assert id == to_string(user.id)
1528 end
1529 end
1530
1531 describe "user relationships" do
1532 setup do: oauth_access(["read:follows"])
1533
1534 test "returns the relationships for the current user", %{user: user, conn: conn} do
1535 %{id: other_user_id} = other_user = insert(:user)
1536 {:ok, _user, _other_user} = User.follow(user, other_user)
1537
1538 assert [%{"id" => ^other_user_id}] =
1539 conn
1540 |> get("/api/v1/accounts/relationships?id=#{other_user.id}")
1541 |> json_response_and_validate_schema(200)
1542
1543 assert [%{"id" => ^other_user_id}] =
1544 conn
1545 |> get("/api/v1/accounts/relationships?id[]=#{other_user.id}")
1546 |> json_response_and_validate_schema(200)
1547 end
1548
1549 test "returns an empty list on a bad request", %{conn: conn} do
1550 conn = get(conn, "/api/v1/accounts/relationships", %{})
1551
1552 assert [] = json_response_and_validate_schema(conn, 200)
1553 end
1554 end
1555
1556 test "getting a list of mutes" do
1557 %{user: user, conn: conn} = oauth_access(["read:mutes"])
1558 %{id: id1} = other_user1 = insert(:user)
1559 %{id: id2} = other_user2 = insert(:user)
1560 %{id: id3} = other_user3 = insert(:user)
1561
1562 {:ok, _user_relationships} = User.mute(user, other_user1)
1563 {:ok, _user_relationships} = User.mute(user, other_user2)
1564 {:ok, _user_relationships} = User.mute(user, other_user3)
1565
1566 result =
1567 conn
1568 |> assign(:user, user)
1569 |> get("/api/v1/mutes")
1570 |> json_response_and_validate_schema(200)
1571
1572 assert [id1, id2, id3] == Enum.map(result, & &1["id"])
1573
1574 result =
1575 conn
1576 |> assign(:user, user)
1577 |> get("/api/v1/mutes?limit=1")
1578 |> json_response_and_validate_schema(200)
1579
1580 assert [%{"id" => ^id1}] = result
1581
1582 result =
1583 conn
1584 |> assign(:user, user)
1585 |> get("/api/v1/mutes?since_id=#{id1}")
1586 |> json_response_and_validate_schema(200)
1587
1588 assert [%{"id" => ^id2}, %{"id" => ^id3}] = result
1589
1590 result =
1591 conn
1592 |> assign(:user, user)
1593 |> get("/api/v1/mutes?since_id=#{id1}&max_id=#{id3}")
1594 |> json_response_and_validate_schema(200)
1595
1596 assert [%{"id" => ^id2}] = result
1597
1598 result =
1599 conn
1600 |> assign(:user, user)
1601 |> get("/api/v1/mutes?since_id=#{id1}&limit=1")
1602 |> json_response_and_validate_schema(200)
1603
1604 assert [%{"id" => ^id2}] = result
1605 end
1606
1607 test "getting a list of blocks" do
1608 %{user: user, conn: conn} = oauth_access(["read:blocks"])
1609 %{id: id1} = other_user1 = insert(:user)
1610 %{id: id2} = other_user2 = insert(:user)
1611 %{id: id3} = other_user3 = insert(:user)
1612
1613 {:ok, _user_relationship} = User.block(user, other_user1)
1614 {:ok, _user_relationship} = User.block(user, other_user3)
1615 {:ok, _user_relationship} = User.block(user, other_user2)
1616
1617 result =
1618 conn
1619 |> assign(:user, user)
1620 |> get("/api/v1/blocks")
1621 |> json_response_and_validate_schema(200)
1622
1623 assert [id1, id2, id3] == Enum.map(result, & &1["id"])
1624
1625 result =
1626 conn
1627 |> assign(:user, user)
1628 |> get("/api/v1/blocks?limit=1")
1629 |> json_response_and_validate_schema(200)
1630
1631 assert [%{"id" => ^id1}] = result
1632
1633 result =
1634 conn
1635 |> assign(:user, user)
1636 |> get("/api/v1/blocks?since_id=#{id1}")
1637 |> json_response_and_validate_schema(200)
1638
1639 assert [%{"id" => ^id2}, %{"id" => ^id3}] = result
1640
1641 result =
1642 conn
1643 |> assign(:user, user)
1644 |> get("/api/v1/blocks?since_id=#{id1}&max_id=#{id3}")
1645 |> json_response_and_validate_schema(200)
1646
1647 assert [%{"id" => ^id2}] = result
1648
1649 result =
1650 conn
1651 |> assign(:user, user)
1652 |> get("/api/v1/blocks?since_id=#{id1}&limit=1")
1653 |> json_response_and_validate_schema(200)
1654
1655 assert [%{"id" => ^id2}] = result
1656 end
1657 end