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