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