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