Add test for following with subscription
[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 with subscription and unsubscribing when notify is nil" do
926 %{conn: conn} = oauth_access(["follow"])
927 followed = insert(:user)
928
929 ret_conn =
930 conn
931 |> put_req_header("content-type", "application/json")
932 |> post("/api/v1/accounts/#{followed.id}/follow", %{notify: true})
933
934 assert %{"id" => _id, "subscribing" => true} =
935 json_response_and_validate_schema(ret_conn, 200)
936
937 ret_conn =
938 conn
939 |> put_req_header("content-type", "application/json")
940 |> post("/api/v1/accounts/#{followed.id}/follow")
941
942 assert %{"id" => _id, "subscribing" => false} =
943 json_response_and_validate_schema(ret_conn, 200)
944 end
945
946 test "following / unfollowing errors", %{user: user, conn: conn} do
947 # self follow
948 conn_res = post(conn, "/api/v1/accounts/#{user.id}/follow")
949
950 assert %{"error" => "Can not follow yourself"} =
951 json_response_and_validate_schema(conn_res, 400)
952
953 # self unfollow
954 user = User.get_cached_by_id(user.id)
955 conn_res = post(conn, "/api/v1/accounts/#{user.id}/unfollow")
956
957 assert %{"error" => "Can not unfollow yourself"} =
958 json_response_and_validate_schema(conn_res, 400)
959
960 # self follow via uri
961 user = User.get_cached_by_id(user.id)
962
963 assert %{"error" => "Can not follow yourself"} =
964 conn
965 |> put_req_header("content-type", "multipart/form-data")
966 |> post("/api/v1/follows", %{"uri" => user.nickname})
967 |> json_response_and_validate_schema(400)
968
969 # follow non existing user
970 conn_res = post(conn, "/api/v1/accounts/doesntexist/follow")
971 assert %{"error" => "Record not found"} = json_response_and_validate_schema(conn_res, 404)
972
973 # follow non existing user via uri
974 conn_res =
975 conn
976 |> put_req_header("content-type", "multipart/form-data")
977 |> post("/api/v1/follows", %{"uri" => "doesntexist"})
978
979 assert %{"error" => "Record not found"} = json_response_and_validate_schema(conn_res, 404)
980
981 # unfollow non existing user
982 conn_res = post(conn, "/api/v1/accounts/doesntexist/unfollow")
983 assert %{"error" => "Record not found"} = json_response_and_validate_schema(conn_res, 404)
984 end
985 end
986
987 describe "mute/unmute" do
988 setup do: oauth_access(["write:mutes"])
989
990 test "with notifications", %{conn: conn} do
991 other_user = insert(:user)
992
993 assert %{"id" => _id, "muting" => true, "muting_notifications" => true} =
994 conn
995 |> post("/api/v1/accounts/#{other_user.id}/mute")
996 |> json_response_and_validate_schema(200)
997
998 conn = post(conn, "/api/v1/accounts/#{other_user.id}/unmute")
999
1000 assert %{"id" => _id, "muting" => false, "muting_notifications" => false} =
1001 json_response_and_validate_schema(conn, 200)
1002 end
1003
1004 test "without notifications", %{conn: conn} do
1005 other_user = insert(:user)
1006
1007 ret_conn =
1008 conn
1009 |> put_req_header("content-type", "multipart/form-data")
1010 |> post("/api/v1/accounts/#{other_user.id}/mute", %{"notifications" => "false"})
1011
1012 assert %{"id" => _id, "muting" => true, "muting_notifications" => false} =
1013 json_response_and_validate_schema(ret_conn, 200)
1014
1015 conn = post(conn, "/api/v1/accounts/#{other_user.id}/unmute")
1016
1017 assert %{"id" => _id, "muting" => false, "muting_notifications" => false} =
1018 json_response_and_validate_schema(conn, 200)
1019 end
1020 end
1021
1022 describe "pinned statuses" do
1023 setup do
1024 user = insert(:user)
1025 {:ok, activity} = CommonAPI.post(user, %{status: "HI!!!"})
1026 %{conn: conn} = oauth_access(["read:statuses"], user: user)
1027
1028 [conn: conn, user: user, activity: activity]
1029 end
1030
1031 test "returns pinned statuses", %{conn: conn, user: user, activity: %{id: activity_id}} do
1032 {:ok, _} = CommonAPI.pin(activity_id, user)
1033
1034 assert [%{"id" => ^activity_id, "pinned" => true}] =
1035 conn
1036 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
1037 |> json_response_and_validate_schema(200)
1038 end
1039 end
1040
1041 test "blocking / unblocking a user" do
1042 %{conn: conn} = oauth_access(["follow"])
1043 other_user = insert(:user)
1044
1045 ret_conn = post(conn, "/api/v1/accounts/#{other_user.id}/block")
1046
1047 assert %{"id" => _id, "blocking" => true} = json_response_and_validate_schema(ret_conn, 200)
1048
1049 conn = post(conn, "/api/v1/accounts/#{other_user.id}/unblock")
1050
1051 assert %{"id" => _id, "blocking" => false} = json_response_and_validate_schema(conn, 200)
1052 end
1053
1054 describe "create account by app" do
1055 setup do
1056 valid_params = %{
1057 username: "lain",
1058 email: "lain@example.org",
1059 password: "PlzDontHackLain",
1060 agreement: true
1061 }
1062
1063 [valid_params: valid_params]
1064 end
1065
1066 test "registers and logs in without :account_activation_required / :account_approval_required",
1067 %{conn: conn} do
1068 clear_config([:instance, :account_activation_required], false)
1069 clear_config([:instance, :account_approval_required], false)
1070
1071 conn =
1072 conn
1073 |> put_req_header("content-type", "application/json")
1074 |> post("/api/v1/apps", %{
1075 client_name: "client_name",
1076 redirect_uris: "urn:ietf:wg:oauth:2.0:oob",
1077 scopes: "read, write, follow"
1078 })
1079
1080 assert %{
1081 "client_id" => client_id,
1082 "client_secret" => client_secret,
1083 "id" => _,
1084 "name" => "client_name",
1085 "redirect_uri" => "urn:ietf:wg:oauth:2.0:oob",
1086 "vapid_key" => _,
1087 "website" => nil
1088 } = json_response_and_validate_schema(conn, 200)
1089
1090 conn =
1091 post(conn, "/oauth/token", %{
1092 grant_type: "client_credentials",
1093 client_id: client_id,
1094 client_secret: client_secret
1095 })
1096
1097 assert %{"access_token" => token, "refresh_token" => refresh, "scope" => scope} =
1098 json_response(conn, 200)
1099
1100 assert token
1101 token_from_db = Repo.get_by(Token, token: token)
1102 assert token_from_db
1103 assert refresh
1104 assert scope == "read write follow"
1105
1106 clear_config([User, :email_blacklist], ["example.org"])
1107
1108 params = %{
1109 username: "lain",
1110 email: "lain@example.org",
1111 password: "PlzDontHackLain",
1112 bio: "Test Bio",
1113 agreement: true
1114 }
1115
1116 conn =
1117 build_conn()
1118 |> put_req_header("content-type", "multipart/form-data")
1119 |> put_req_header("authorization", "Bearer " <> token)
1120 |> post("/api/v1/accounts", params)
1121
1122 assert %{"error" => "{\"email\":[\"Invalid email\"]}"} =
1123 json_response_and_validate_schema(conn, 400)
1124
1125 clear_config([User, :email_blacklist], [])
1126
1127 conn =
1128 build_conn()
1129 |> put_req_header("content-type", "multipart/form-data")
1130 |> put_req_header("authorization", "Bearer " <> token)
1131 |> post("/api/v1/accounts", params)
1132
1133 %{
1134 "access_token" => token,
1135 "created_at" => _created_at,
1136 "scope" => ^scope,
1137 "token_type" => "Bearer"
1138 } = json_response_and_validate_schema(conn, 200)
1139
1140 token_from_db = Repo.get_by(Token, token: token)
1141 assert token_from_db
1142 user = Repo.preload(token_from_db, :user).user
1143
1144 assert user
1145 assert user.is_confirmed
1146 assert user.is_approved
1147 end
1148
1149 test "registers but does not log in with :account_activation_required", %{conn: conn} do
1150 clear_config([:instance, :account_activation_required], true)
1151 clear_config([:instance, :account_approval_required], false)
1152
1153 conn =
1154 conn
1155 |> put_req_header("content-type", "application/json")
1156 |> post("/api/v1/apps", %{
1157 client_name: "client_name",
1158 redirect_uris: "urn:ietf:wg:oauth:2.0:oob",
1159 scopes: "read, write, follow"
1160 })
1161
1162 assert %{
1163 "client_id" => client_id,
1164 "client_secret" => client_secret,
1165 "id" => _,
1166 "name" => "client_name",
1167 "redirect_uri" => "urn:ietf:wg:oauth:2.0:oob",
1168 "vapid_key" => _,
1169 "website" => nil
1170 } = json_response_and_validate_schema(conn, 200)
1171
1172 conn =
1173 post(conn, "/oauth/token", %{
1174 grant_type: "client_credentials",
1175 client_id: client_id,
1176 client_secret: client_secret
1177 })
1178
1179 assert %{"access_token" => token, "refresh_token" => refresh, "scope" => scope} =
1180 json_response(conn, 200)
1181
1182 assert token
1183 token_from_db = Repo.get_by(Token, token: token)
1184 assert token_from_db
1185 assert refresh
1186 assert scope == "read write follow"
1187
1188 conn =
1189 build_conn()
1190 |> put_req_header("content-type", "multipart/form-data")
1191 |> put_req_header("authorization", "Bearer " <> token)
1192 |> post("/api/v1/accounts", %{
1193 username: "lain",
1194 email: "lain@example.org",
1195 password: "PlzDontHackLain",
1196 bio: "Test Bio",
1197 agreement: true
1198 })
1199
1200 response = json_response_and_validate_schema(conn, 200)
1201 assert %{"identifier" => "missing_confirmed_email"} = response
1202 refute response["access_token"]
1203 refute response["token_type"]
1204
1205 user = Repo.get_by(User, email: "lain@example.org")
1206 refute user.is_confirmed
1207 end
1208
1209 test "registers but does not log in with :account_approval_required", %{conn: conn} do
1210 clear_config([:instance, :account_approval_required], true)
1211 clear_config([:instance, :account_activation_required], false)
1212
1213 conn =
1214 conn
1215 |> put_req_header("content-type", "application/json")
1216 |> post("/api/v1/apps", %{
1217 client_name: "client_name",
1218 redirect_uris: "urn:ietf:wg:oauth:2.0:oob",
1219 scopes: "read, write, follow"
1220 })
1221
1222 assert %{
1223 "client_id" => client_id,
1224 "client_secret" => client_secret,
1225 "id" => _,
1226 "name" => "client_name",
1227 "redirect_uri" => "urn:ietf:wg:oauth:2.0:oob",
1228 "vapid_key" => _,
1229 "website" => nil
1230 } = json_response_and_validate_schema(conn, 200)
1231
1232 conn =
1233 post(conn, "/oauth/token", %{
1234 grant_type: "client_credentials",
1235 client_id: client_id,
1236 client_secret: client_secret
1237 })
1238
1239 assert %{"access_token" => token, "refresh_token" => refresh, "scope" => scope} =
1240 json_response(conn, 200)
1241
1242 assert token
1243 token_from_db = Repo.get_by(Token, token: token)
1244 assert token_from_db
1245 assert refresh
1246 assert scope == "read write follow"
1247
1248 conn =
1249 build_conn()
1250 |> put_req_header("content-type", "multipart/form-data")
1251 |> put_req_header("authorization", "Bearer " <> token)
1252 |> post("/api/v1/accounts", %{
1253 username: "lain",
1254 email: "lain@example.org",
1255 password: "PlzDontHackLain",
1256 bio: "Test Bio",
1257 agreement: true,
1258 reason: "I'm a cool dude, bro"
1259 })
1260
1261 response = json_response_and_validate_schema(conn, 200)
1262 assert %{"identifier" => "awaiting_approval"} = response
1263 refute response["access_token"]
1264 refute response["token_type"]
1265
1266 user = Repo.get_by(User, email: "lain@example.org")
1267
1268 refute user.is_approved
1269 assert user.registration_reason == "I'm a cool dude, bro"
1270 end
1271
1272 test "returns error when user already registred", %{conn: conn, valid_params: valid_params} do
1273 _user = insert(:user, email: "lain@example.org")
1274 app_token = insert(:oauth_token, user: nil)
1275
1276 res =
1277 conn
1278 |> put_req_header("authorization", "Bearer " <> app_token.token)
1279 |> put_req_header("content-type", "application/json")
1280 |> post("/api/v1/accounts", valid_params)
1281
1282 assert json_response_and_validate_schema(res, 400) == %{
1283 "error" => "{\"email\":[\"has already been taken\"]}"
1284 }
1285 end
1286
1287 test "returns bad_request if missing required params", %{
1288 conn: conn,
1289 valid_params: valid_params
1290 } do
1291 app_token = insert(:oauth_token, user: nil)
1292
1293 conn =
1294 conn
1295 |> put_req_header("authorization", "Bearer " <> app_token.token)
1296 |> put_req_header("content-type", "application/json")
1297
1298 res = post(conn, "/api/v1/accounts", valid_params)
1299 assert json_response_and_validate_schema(res, 200)
1300
1301 [{127, 0, 0, 1}, {127, 0, 0, 2}, {127, 0, 0, 3}, {127, 0, 0, 4}]
1302 |> Stream.zip(Map.delete(valid_params, :email))
1303 |> Enum.each(fn {ip, {attr, _}} ->
1304 res =
1305 conn
1306 |> Map.put(:remote_ip, ip)
1307 |> post("/api/v1/accounts", Map.delete(valid_params, attr))
1308 |> json_response_and_validate_schema(400)
1309
1310 assert res == %{
1311 "error" => "Missing field: #{attr}.",
1312 "errors" => [
1313 %{
1314 "message" => "Missing field: #{attr}",
1315 "source" => %{"pointer" => "/#{attr}"},
1316 "title" => "Invalid value"
1317 }
1318 ]
1319 }
1320 end)
1321 end
1322
1323 test "returns bad_request if missing email params when :account_activation_required is enabled",
1324 %{conn: conn, valid_params: valid_params} do
1325 clear_config([:instance, :account_activation_required], true)
1326
1327 app_token = insert(:oauth_token, user: nil)
1328
1329 conn =
1330 conn
1331 |> put_req_header("authorization", "Bearer " <> app_token.token)
1332 |> put_req_header("content-type", "application/json")
1333
1334 res =
1335 conn
1336 |> Map.put(:remote_ip, {127, 0, 0, 5})
1337 |> post("/api/v1/accounts", Map.delete(valid_params, :email))
1338
1339 assert json_response_and_validate_schema(res, 400) ==
1340 %{"error" => "Missing parameter: email"}
1341
1342 res =
1343 conn
1344 |> Map.put(:remote_ip, {127, 0, 0, 6})
1345 |> post("/api/v1/accounts", Map.put(valid_params, :email, ""))
1346
1347 assert json_response_and_validate_schema(res, 400) == %{
1348 "error" => "{\"email\":[\"can't be blank\"]}"
1349 }
1350 end
1351
1352 test "allow registration without an email", %{conn: conn, valid_params: valid_params} do
1353 app_token = insert(:oauth_token, user: nil)
1354 conn = put_req_header(conn, "authorization", "Bearer " <> app_token.token)
1355
1356 res =
1357 conn
1358 |> put_req_header("content-type", "application/json")
1359 |> Map.put(:remote_ip, {127, 0, 0, 7})
1360 |> post("/api/v1/accounts", Map.delete(valid_params, :email))
1361
1362 assert json_response_and_validate_schema(res, 200)
1363 end
1364
1365 test "allow registration with an empty email", %{conn: conn, valid_params: valid_params} do
1366 app_token = insert(:oauth_token, user: nil)
1367 conn = put_req_header(conn, "authorization", "Bearer " <> app_token.token)
1368
1369 res =
1370 conn
1371 |> put_req_header("content-type", "application/json")
1372 |> Map.put(:remote_ip, {127, 0, 0, 8})
1373 |> post("/api/v1/accounts", Map.put(valid_params, :email, ""))
1374
1375 assert json_response_and_validate_schema(res, 200)
1376 end
1377
1378 test "returns forbidden if token is invalid", %{conn: conn, valid_params: valid_params} do
1379 res =
1380 conn
1381 |> put_req_header("authorization", "Bearer " <> "invalid-token")
1382 |> put_req_header("content-type", "multipart/form-data")
1383 |> post("/api/v1/accounts", valid_params)
1384
1385 assert json_response_and_validate_schema(res, 403) == %{"error" => "Invalid credentials"}
1386 end
1387
1388 test "registration from trusted app" do
1389 clear_config([Pleroma.Captcha, :enabled], true)
1390 app = insert(:oauth_app, trusted: true, scopes: ["read", "write", "follow", "push"])
1391
1392 conn =
1393 build_conn()
1394 |> post("/oauth/token", %{
1395 "grant_type" => "client_credentials",
1396 "client_id" => app.client_id,
1397 "client_secret" => app.client_secret
1398 })
1399
1400 assert %{"access_token" => token, "token_type" => "Bearer"} = json_response(conn, 200)
1401
1402 response =
1403 build_conn()
1404 |> Plug.Conn.put_req_header("authorization", "Bearer " <> token)
1405 |> put_req_header("content-type", "multipart/form-data")
1406 |> post("/api/v1/accounts", %{
1407 nickname: "nickanme",
1408 agreement: true,
1409 email: "email@example.com",
1410 fullname: "Lain",
1411 username: "Lain",
1412 password: "some_password",
1413 confirm: "some_password"
1414 })
1415 |> json_response_and_validate_schema(200)
1416
1417 assert %{
1418 "access_token" => access_token,
1419 "created_at" => _,
1420 "scope" => "read write follow push",
1421 "token_type" => "Bearer"
1422 } = response
1423
1424 response =
1425 build_conn()
1426 |> Plug.Conn.put_req_header("authorization", "Bearer " <> access_token)
1427 |> get("/api/v1/accounts/verify_credentials")
1428 |> json_response_and_validate_schema(200)
1429
1430 assert %{
1431 "acct" => "Lain",
1432 "bot" => false,
1433 "display_name" => "Lain",
1434 "follow_requests_count" => 0,
1435 "followers_count" => 0,
1436 "following_count" => 0,
1437 "locked" => false,
1438 "note" => "",
1439 "source" => %{
1440 "fields" => [],
1441 "note" => "",
1442 "pleroma" => %{
1443 "actor_type" => "Person",
1444 "discoverable" => false,
1445 "no_rich_text" => false,
1446 "show_role" => true
1447 },
1448 "privacy" => "public",
1449 "sensitive" => false
1450 },
1451 "statuses_count" => 0,
1452 "username" => "Lain"
1453 } = response
1454 end
1455 end
1456
1457 describe "create account by app / rate limit" do
1458 setup do: clear_config([:rate_limit, :app_account_creation], {10_000, 2})
1459
1460 test "respects rate limit setting", %{conn: conn} do
1461 app_token = insert(:oauth_token, user: nil)
1462
1463 conn =
1464 conn
1465 |> put_req_header("authorization", "Bearer " <> app_token.token)
1466 |> Map.put(:remote_ip, {15, 15, 15, 15})
1467 |> put_req_header("content-type", "multipart/form-data")
1468
1469 for i <- 1..2 do
1470 conn =
1471 conn
1472 |> post("/api/v1/accounts", %{
1473 username: "#{i}lain",
1474 email: "#{i}lain@example.org",
1475 password: "PlzDontHackLain",
1476 agreement: true
1477 })
1478
1479 %{
1480 "access_token" => token,
1481 "created_at" => _created_at,
1482 "scope" => _scope,
1483 "token_type" => "Bearer"
1484 } = json_response_and_validate_schema(conn, 200)
1485
1486 token_from_db = Repo.get_by(Token, token: token)
1487 assert token_from_db
1488 token_from_db = Repo.preload(token_from_db, :user)
1489 assert token_from_db.user
1490 end
1491
1492 conn =
1493 post(conn, "/api/v1/accounts", %{
1494 username: "6lain",
1495 email: "6lain@example.org",
1496 password: "PlzDontHackLain",
1497 agreement: true
1498 })
1499
1500 assert json_response_and_validate_schema(conn, :too_many_requests) == %{
1501 "error" => "Throttled"
1502 }
1503 end
1504 end
1505
1506 describe "create account with enabled captcha" do
1507 setup %{conn: conn} do
1508 app_token = insert(:oauth_token, user: nil)
1509
1510 conn =
1511 conn
1512 |> put_req_header("authorization", "Bearer " <> app_token.token)
1513 |> put_req_header("content-type", "multipart/form-data")
1514
1515 [conn: conn]
1516 end
1517
1518 setup do: clear_config([Pleroma.Captcha, :enabled], true)
1519
1520 test "creates an account and returns 200 if captcha is valid", %{conn: conn} do
1521 %{token: token, answer_data: answer_data} = Pleroma.Captcha.new()
1522
1523 params = %{
1524 username: "lain",
1525 email: "lain@example.org",
1526 password: "PlzDontHackLain",
1527 agreement: true,
1528 captcha_solution: Pleroma.Captcha.Mock.solution(),
1529 captcha_token: token,
1530 captcha_answer_data: answer_data
1531 }
1532
1533 assert %{
1534 "access_token" => access_token,
1535 "created_at" => _,
1536 "scope" => "read",
1537 "token_type" => "Bearer"
1538 } =
1539 conn
1540 |> post("/api/v1/accounts", params)
1541 |> json_response_and_validate_schema(:ok)
1542
1543 assert Token |> Repo.get_by(token: access_token) |> Repo.preload(:user) |> Map.get(:user)
1544 end
1545
1546 test "returns 400 if any captcha field is not provided", %{conn: conn} do
1547 captcha_fields = [:captcha_solution, :captcha_token, :captcha_answer_data]
1548
1549 valid_params = %{
1550 username: "lain",
1551 email: "lain@example.org",
1552 password: "PlzDontHackLain",
1553 agreement: true,
1554 captcha_solution: "xx",
1555 captcha_token: "xx",
1556 captcha_answer_data: "xx"
1557 }
1558
1559 for field <- captcha_fields do
1560 expected = %{
1561 "error" => "{\"captcha\":[\"Invalid CAPTCHA (Missing parameter: #{field})\"]}"
1562 }
1563
1564 assert expected ==
1565 conn
1566 |> post("/api/v1/accounts", Map.delete(valid_params, field))
1567 |> json_response_and_validate_schema(:bad_request)
1568 end
1569 end
1570
1571 test "returns an error if captcha is invalid", %{conn: conn} do
1572 params = %{
1573 username: "lain",
1574 email: "lain@example.org",
1575 password: "PlzDontHackLain",
1576 agreement: true,
1577 captcha_solution: "cofe",
1578 captcha_token: "cofe",
1579 captcha_answer_data: "cofe"
1580 }
1581
1582 assert %{"error" => "{\"captcha\":[\"Invalid answer data\"]}"} ==
1583 conn
1584 |> post("/api/v1/accounts", params)
1585 |> json_response_and_validate_schema(:bad_request)
1586 end
1587 end
1588
1589 describe "GET /api/v1/accounts/:id/lists - account_lists" do
1590 test "returns lists to which the account belongs" do
1591 %{user: user, conn: conn} = oauth_access(["read:lists"])
1592 other_user = insert(:user)
1593 assert {:ok, %Pleroma.List{id: _list_id} = list} = Pleroma.List.create("Test List", user)
1594 {:ok, %{following: _following}} = Pleroma.List.follow(list, other_user)
1595
1596 assert [%{"id" => _list_id, "title" => "Test List"}] =
1597 conn
1598 |> get("/api/v1/accounts/#{other_user.id}/lists")
1599 |> json_response_and_validate_schema(200)
1600 end
1601 end
1602
1603 describe "verify_credentials" do
1604 test "verify_credentials" do
1605 %{user: user, conn: conn} = oauth_access(["read:accounts"])
1606
1607 [notification | _] =
1608 insert_list(7, :notification, user: user, activity: insert(:note_activity))
1609
1610 Pleroma.Notification.set_read_up_to(user, notification.id)
1611 conn = get(conn, "/api/v1/accounts/verify_credentials")
1612
1613 response = json_response_and_validate_schema(conn, 200)
1614
1615 assert %{"id" => id, "source" => %{"privacy" => "public"}} = response
1616 assert response["pleroma"]["chat_token"]
1617 assert response["pleroma"]["unread_notifications_count"] == 6
1618 assert id == to_string(user.id)
1619 end
1620
1621 test "verify_credentials default scope unlisted" do
1622 user = insert(:user, default_scope: "unlisted")
1623 %{conn: conn} = oauth_access(["read:accounts"], user: user)
1624
1625 conn = get(conn, "/api/v1/accounts/verify_credentials")
1626
1627 assert %{"id" => id, "source" => %{"privacy" => "unlisted"}} =
1628 json_response_and_validate_schema(conn, 200)
1629
1630 assert id == to_string(user.id)
1631 end
1632
1633 test "locked accounts" do
1634 user = insert(:user, default_scope: "private")
1635 %{conn: conn} = oauth_access(["read:accounts"], user: user)
1636
1637 conn = get(conn, "/api/v1/accounts/verify_credentials")
1638
1639 assert %{"id" => id, "source" => %{"privacy" => "private"}} =
1640 json_response_and_validate_schema(conn, 200)
1641
1642 assert id == to_string(user.id)
1643 end
1644 end
1645
1646 describe "user relationships" do
1647 setup do: oauth_access(["read:follows"])
1648
1649 test "returns the relationships for the current user", %{user: user, conn: conn} do
1650 %{id: other_user_id} = other_user = insert(:user)
1651 {:ok, _user, _other_user} = User.follow(user, other_user)
1652
1653 assert [%{"id" => ^other_user_id}] =
1654 conn
1655 |> get("/api/v1/accounts/relationships?id=#{other_user.id}")
1656 |> json_response_and_validate_schema(200)
1657
1658 assert [%{"id" => ^other_user_id}] =
1659 conn
1660 |> get("/api/v1/accounts/relationships?id[]=#{other_user.id}")
1661 |> json_response_and_validate_schema(200)
1662 end
1663
1664 test "returns an empty list on a bad request", %{conn: conn} do
1665 conn = get(conn, "/api/v1/accounts/relationships", %{})
1666
1667 assert [] = json_response_and_validate_schema(conn, 200)
1668 end
1669 end
1670
1671 test "getting a list of mutes" do
1672 %{user: user, conn: conn} = oauth_access(["read:mutes"])
1673 %{id: id1} = other_user1 = insert(:user)
1674 %{id: id2} = other_user2 = insert(:user)
1675 %{id: id3} = other_user3 = insert(:user)
1676
1677 {:ok, _user_relationships} = User.mute(user, other_user1)
1678 {:ok, _user_relationships} = User.mute(user, other_user2)
1679 {:ok, _user_relationships} = User.mute(user, other_user3)
1680
1681 result =
1682 conn
1683 |> get("/api/v1/mutes")
1684 |> json_response_and_validate_schema(200)
1685
1686 assert [id1, id2, id3] == Enum.map(result, & &1["id"])
1687
1688 result =
1689 conn
1690 |> get("/api/v1/mutes?limit=1")
1691 |> json_response_and_validate_schema(200)
1692
1693 assert [%{"id" => ^id1}] = result
1694
1695 result =
1696 conn
1697 |> get("/api/v1/mutes?since_id=#{id1}")
1698 |> json_response_and_validate_schema(200)
1699
1700 assert [%{"id" => ^id2}, %{"id" => ^id3}] = result
1701
1702 result =
1703 conn
1704 |> get("/api/v1/mutes?since_id=#{id1}&max_id=#{id3}")
1705 |> json_response_and_validate_schema(200)
1706
1707 assert [%{"id" => ^id2}] = result
1708
1709 result =
1710 conn
1711 |> get("/api/v1/mutes?since_id=#{id1}&limit=1")
1712 |> json_response_and_validate_schema(200)
1713
1714 assert [%{"id" => ^id2}] = result
1715 end
1716
1717 test "list of mutes with with_relationships parameter" do
1718 %{user: user, conn: conn} = oauth_access(["read:mutes"])
1719 %{id: id1} = other_user1 = insert(:user)
1720 %{id: id2} = other_user2 = insert(:user)
1721 %{id: id3} = other_user3 = insert(:user)
1722
1723 {:ok, _, _} = User.follow(other_user1, user)
1724 {:ok, _, _} = User.follow(other_user2, user)
1725 {:ok, _, _} = User.follow(other_user3, user)
1726
1727 {:ok, _} = User.mute(user, other_user1)
1728 {:ok, _} = User.mute(user, other_user2)
1729 {:ok, _} = User.mute(user, other_user3)
1730
1731 assert [
1732 %{
1733 "id" => ^id1,
1734 "pleroma" => %{"relationship" => %{"muting" => true, "followed_by" => true}}
1735 },
1736 %{
1737 "id" => ^id2,
1738 "pleroma" => %{"relationship" => %{"muting" => true, "followed_by" => true}}
1739 },
1740 %{
1741 "id" => ^id3,
1742 "pleroma" => %{"relationship" => %{"muting" => true, "followed_by" => true}}
1743 }
1744 ] =
1745 conn
1746 |> get("/api/v1/mutes?with_relationships=true")
1747 |> json_response_and_validate_schema(200)
1748 end
1749
1750 test "getting a list of blocks" do
1751 %{user: user, conn: conn} = oauth_access(["read:blocks"])
1752 %{id: id1} = other_user1 = insert(:user)
1753 %{id: id2} = other_user2 = insert(:user)
1754 %{id: id3} = other_user3 = insert(:user)
1755
1756 {:ok, _user_relationship} = User.block(user, other_user1)
1757 {:ok, _user_relationship} = User.block(user, other_user3)
1758 {:ok, _user_relationship} = User.block(user, other_user2)
1759
1760 result =
1761 conn
1762 |> assign(:user, user)
1763 |> get("/api/v1/blocks")
1764 |> json_response_and_validate_schema(200)
1765
1766 assert [id1, id2, id3] == Enum.map(result, & &1["id"])
1767
1768 result =
1769 conn
1770 |> assign(:user, user)
1771 |> get("/api/v1/blocks?limit=1")
1772 |> json_response_and_validate_schema(200)
1773
1774 assert [%{"id" => ^id1}] = result
1775
1776 result =
1777 conn
1778 |> assign(:user, user)
1779 |> get("/api/v1/blocks?since_id=#{id1}")
1780 |> json_response_and_validate_schema(200)
1781
1782 assert [%{"id" => ^id2}, %{"id" => ^id3}] = result
1783
1784 result =
1785 conn
1786 |> assign(:user, user)
1787 |> get("/api/v1/blocks?since_id=#{id1}&max_id=#{id3}")
1788 |> json_response_and_validate_schema(200)
1789
1790 assert [%{"id" => ^id2}] = result
1791
1792 result =
1793 conn
1794 |> assign(:user, user)
1795 |> get("/api/v1/blocks?since_id=#{id1}&limit=1")
1796 |> json_response_and_validate_schema(200)
1797
1798 assert [%{"id" => ^id2}] = result
1799 end
1800 end