9ac4ff9297c01375cbb9dd13eb67ec62af1edf6a
[akkoma] / test / web / twitter_api / twitter_api_controller_test.exs
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
5 defmodule Pleroma.Web.TwitterAPI.ControllerTest do
6 use Pleroma.Web.ConnCase
7 alias Comeonin.Pbkdf2
8 alias Ecto.Changeset
9 alias Pleroma.Activity
10 alias Pleroma.Builders.ActivityBuilder
11 alias Pleroma.Builders.UserBuilder
12 alias Pleroma.Notification
13 alias Pleroma.Object
14 alias Pleroma.Repo
15 alias Pleroma.Tests.ObanHelpers
16 alias Pleroma.User
17 alias Pleroma.Web.ActivityPub.ActivityPub
18 alias Pleroma.Web.CommonAPI
19 alias Pleroma.Web.OAuth.Token
20 alias Pleroma.Web.TwitterAPI.ActivityView
21 alias Pleroma.Web.TwitterAPI.Controller
22 alias Pleroma.Web.TwitterAPI.NotificationView
23 alias Pleroma.Web.TwitterAPI.TwitterAPI
24 alias Pleroma.Web.TwitterAPI.UserView
25
26 import Mock
27 import Pleroma.Factory
28 import Swoosh.TestAssertions
29
30 @banner "data:image/gif;base64,R0lGODlhEAAQAMQAAORHHOVSKudfOulrSOp3WOyDZu6QdvCchPGolfO0o/XBs/fNwfjZ0frl3/zy7////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkAABAALAAAAAAQABAAAAVVICSOZGlCQAosJ6mu7fiyZeKqNKToQGDsM8hBADgUXoGAiqhSvp5QAnQKGIgUhwFUYLCVDFCrKUE1lBavAViFIDlTImbKC5Gm2hB0SlBCBMQiB0UjIQA7"
31
32 describe "POST /api/account/update_profile_banner" do
33 test "it updates the banner", %{conn: conn} do
34 user = insert(:user)
35
36 conn
37 |> assign(:user, user)
38 |> post(authenticated_twitter_api__path(conn, :update_banner), %{"banner" => @banner})
39 |> json_response(200)
40
41 user = refresh_record(user)
42 assert user.info.banner["type"] == "Image"
43 end
44
45 test "profile banner can be reset", %{conn: conn} do
46 user = insert(:user)
47
48 conn
49 |> assign(:user, user)
50 |> post(authenticated_twitter_api__path(conn, :update_banner), %{"banner" => ""})
51 |> json_response(200)
52
53 user = refresh_record(user)
54 assert user.info.banner == %{}
55 end
56 end
57
58 describe "POST /api/qvitter/update_background_image" do
59 test "it updates the background", %{conn: conn} do
60 user = insert(:user)
61
62 conn
63 |> assign(:user, user)
64 |> post(authenticated_twitter_api__path(conn, :update_background), %{"img" => @banner})
65 |> json_response(200)
66
67 user = refresh_record(user)
68 assert user.info.background["type"] == "Image"
69 end
70
71 test "background can be reset", %{conn: conn} do
72 user = insert(:user)
73
74 conn
75 |> assign(:user, user)
76 |> post(authenticated_twitter_api__path(conn, :update_background), %{"img" => ""})
77 |> json_response(200)
78
79 user = refresh_record(user)
80 assert user.info.background == %{}
81 end
82 end
83
84 describe "POST /api/account/verify_credentials" do
85 setup [:valid_user]
86
87 test "without valid credentials", %{conn: conn} do
88 conn = post(conn, "/api/account/verify_credentials.json")
89 assert json_response(conn, 403) == %{"error" => "Invalid credentials."}
90 end
91
92 test "with credentials", %{conn: conn, user: user} do
93 response =
94 conn
95 |> with_credentials(user.nickname, "test")
96 |> post("/api/account/verify_credentials.json")
97 |> json_response(200)
98
99 assert response ==
100 UserView.render("show.json", %{user: user, token: response["token"], for: user})
101 end
102 end
103
104 describe "POST /statuses/update.json" do
105 setup [:valid_user]
106
107 test "without valid credentials", %{conn: conn} do
108 conn = post(conn, "/api/statuses/update.json")
109 assert json_response(conn, 403) == %{"error" => "Invalid credentials."}
110 end
111
112 test "with credentials", %{conn: conn, user: user} do
113 conn_with_creds = conn |> with_credentials(user.nickname, "test")
114 request_path = "/api/statuses/update.json"
115
116 error_response = %{
117 "request" => request_path,
118 "error" => "Client must provide a 'status' parameter with a value."
119 }
120
121 conn =
122 conn_with_creds
123 |> post(request_path)
124
125 assert json_response(conn, 400) == error_response
126
127 conn =
128 conn_with_creds
129 |> post(request_path, %{status: ""})
130
131 assert json_response(conn, 400) == error_response
132
133 conn =
134 conn_with_creds
135 |> post(request_path, %{status: " "})
136
137 assert json_response(conn, 400) == error_response
138
139 # we post with visibility private in order to avoid triggering relay
140 conn =
141 conn_with_creds
142 |> post(request_path, %{status: "Nice meme.", visibility: "private"})
143
144 assert json_response(conn, 200) ==
145 ActivityView.render("activity.json", %{
146 activity: Repo.one(Activity),
147 user: user,
148 for: user
149 })
150 end
151 end
152
153 describe "GET /statuses/public_timeline.json" do
154 setup [:valid_user]
155
156 test "returns statuses", %{conn: conn} do
157 user = insert(:user)
158 activities = ActivityBuilder.insert_list(30, %{}, %{user: user})
159 ActivityBuilder.insert_list(10, %{}, %{user: user})
160 since_id = List.last(activities).id
161
162 conn =
163 conn
164 |> get("/api/statuses/public_timeline.json", %{since_id: since_id})
165
166 response = json_response(conn, 200)
167
168 assert length(response) == 10
169 end
170
171 test "returns 403 to unauthenticated request when the instance is not public", %{conn: conn} do
172 Pleroma.Config.put([:instance, :public], false)
173
174 conn
175 |> get("/api/statuses/public_timeline.json")
176 |> json_response(403)
177
178 Pleroma.Config.put([:instance, :public], true)
179 end
180
181 test "returns 200 to authenticated request when the instance is not public",
182 %{conn: conn, user: user} do
183 Pleroma.Config.put([:instance, :public], false)
184
185 conn
186 |> with_credentials(user.nickname, "test")
187 |> get("/api/statuses/public_timeline.json")
188 |> json_response(200)
189
190 Pleroma.Config.put([:instance, :public], true)
191 end
192
193 test "returns 200 to unauthenticated request when the instance is public", %{conn: conn} do
194 conn
195 |> get("/api/statuses/public_timeline.json")
196 |> json_response(200)
197 end
198
199 test "returns 200 to authenticated request when the instance is public",
200 %{conn: conn, user: user} do
201 conn
202 |> with_credentials(user.nickname, "test")
203 |> get("/api/statuses/public_timeline.json")
204 |> json_response(200)
205 end
206
207 test_with_mock "treats user as unauthenticated if `assigns[:token]` is present but lacks `read` permission",
208 Controller,
209 [:passthrough],
210 [] do
211 token = insert(:oauth_token, scopes: ["write"])
212
213 build_conn()
214 |> put_req_header("authorization", "Bearer #{token.token}")
215 |> get("/api/statuses/public_timeline.json")
216 |> json_response(200)
217
218 assert called(Controller.public_timeline(%{assigns: %{user: nil}}, :_))
219 end
220 end
221
222 describe "GET /statuses/public_and_external_timeline.json" do
223 setup [:valid_user]
224
225 test "returns 403 to unauthenticated request when the instance is not public", %{conn: conn} do
226 Pleroma.Config.put([:instance, :public], false)
227
228 conn
229 |> get("/api/statuses/public_and_external_timeline.json")
230 |> json_response(403)
231
232 Pleroma.Config.put([:instance, :public], true)
233 end
234
235 test "returns 200 to authenticated request when the instance is not public",
236 %{conn: conn, user: user} do
237 Pleroma.Config.put([:instance, :public], false)
238
239 conn
240 |> with_credentials(user.nickname, "test")
241 |> get("/api/statuses/public_and_external_timeline.json")
242 |> json_response(200)
243
244 Pleroma.Config.put([:instance, :public], true)
245 end
246
247 test "returns 200 to unauthenticated request when the instance is public", %{conn: conn} do
248 conn
249 |> get("/api/statuses/public_and_external_timeline.json")
250 |> json_response(200)
251 end
252
253 test "returns 200 to authenticated request when the instance is public",
254 %{conn: conn, user: user} do
255 conn
256 |> with_credentials(user.nickname, "test")
257 |> get("/api/statuses/public_and_external_timeline.json")
258 |> json_response(200)
259 end
260 end
261
262 describe "GET /statuses/show/:id.json" do
263 test "returns one status", %{conn: conn} do
264 user = insert(:user)
265 {:ok, activity} = CommonAPI.post(user, %{"status" => "Hey!"})
266 actor = User.get_cached_by_ap_id(activity.data["actor"])
267
268 conn =
269 conn
270 |> get("/api/statuses/show/#{activity.id}.json")
271
272 response = json_response(conn, 200)
273
274 assert response == ActivityView.render("activity.json", %{activity: activity, user: actor})
275 end
276 end
277
278 describe "GET /users/show.json" do
279 test "gets user with screen_name", %{conn: conn} do
280 user = insert(:user)
281
282 conn =
283 conn
284 |> get("/api/users/show.json", %{"screen_name" => user.nickname})
285
286 response = json_response(conn, 200)
287
288 assert response["id"] == user.id
289 end
290
291 test "gets user with user_id", %{conn: conn} do
292 user = insert(:user)
293
294 conn =
295 conn
296 |> get("/api/users/show.json", %{"user_id" => user.id})
297
298 response = json_response(conn, 200)
299
300 assert response["id"] == user.id
301 end
302
303 test "gets a user for a logged in user", %{conn: conn} do
304 user = insert(:user)
305 logged_in = insert(:user)
306
307 {:ok, logged_in, user, _activity} = TwitterAPI.follow(logged_in, %{"user_id" => user.id})
308
309 conn =
310 conn
311 |> with_credentials(logged_in.nickname, "test")
312 |> get("/api/users/show.json", %{"user_id" => user.id})
313
314 response = json_response(conn, 200)
315
316 assert response["following"] == true
317 end
318 end
319
320 describe "GET /statusnet/conversation/:id.json" do
321 test "returns the statuses in the conversation", %{conn: conn} do
322 {:ok, _user} = UserBuilder.insert()
323 {:ok, activity} = ActivityBuilder.insert(%{"type" => "Create", "context" => "2hu"})
324 {:ok, _activity_two} = ActivityBuilder.insert(%{"type" => "Create", "context" => "2hu"})
325 {:ok, _activity_three} = ActivityBuilder.insert(%{"type" => "Create", "context" => "3hu"})
326
327 conn =
328 conn
329 |> get("/api/statusnet/conversation/#{activity.data["context_id"]}.json")
330
331 response = json_response(conn, 200)
332
333 assert length(response) == 2
334 end
335 end
336
337 describe "GET /statuses/friends_timeline.json" do
338 setup [:valid_user]
339
340 test "without valid credentials", %{conn: conn} do
341 conn = get(conn, "/api/statuses/friends_timeline.json")
342 assert json_response(conn, 403) == %{"error" => "Invalid credentials."}
343 end
344
345 test "with credentials", %{conn: conn, user: current_user} do
346 user = insert(:user)
347
348 activities =
349 ActivityBuilder.insert_list(30, %{"to" => [User.ap_followers(user)]}, %{user: user})
350
351 returned_activities =
352 ActivityBuilder.insert_list(10, %{"to" => [User.ap_followers(user)]}, %{user: user})
353
354 other_user = insert(:user)
355 ActivityBuilder.insert_list(10, %{}, %{user: other_user})
356 since_id = List.last(activities).id
357
358 current_user =
359 Changeset.change(current_user, following: [User.ap_followers(user)])
360 |> Repo.update!()
361
362 conn =
363 conn
364 |> with_credentials(current_user.nickname, "test")
365 |> get("/api/statuses/friends_timeline.json", %{since_id: since_id})
366
367 response = json_response(conn, 200)
368
369 assert length(response) == 10
370
371 assert response ==
372 Enum.map(returned_activities, fn activity ->
373 ActivityView.render("activity.json", %{
374 activity: activity,
375 user: User.get_cached_by_ap_id(activity.data["actor"]),
376 for: current_user
377 })
378 end)
379 end
380 end
381
382 describe "GET /statuses/dm_timeline.json" do
383 test "it show direct messages", %{conn: conn} do
384 user_one = insert(:user)
385 user_two = insert(:user)
386
387 {:ok, user_two} = User.follow(user_two, user_one)
388
389 {:ok, direct} =
390 CommonAPI.post(user_one, %{
391 "status" => "Hi @#{user_two.nickname}!",
392 "visibility" => "direct"
393 })
394
395 {:ok, direct_two} =
396 CommonAPI.post(user_two, %{
397 "status" => "Hi @#{user_one.nickname}!",
398 "visibility" => "direct"
399 })
400
401 {:ok, _follower_only} =
402 CommonAPI.post(user_one, %{
403 "status" => "Hi @#{user_two.nickname}!",
404 "visibility" => "private"
405 })
406
407 # Only direct should be visible here
408 res_conn =
409 conn
410 |> assign(:user, user_two)
411 |> get("/api/statuses/dm_timeline.json")
412
413 [status, status_two] = json_response(res_conn, 200)
414 assert status["id"] == direct_two.id
415 assert status_two["id"] == direct.id
416 end
417
418 test "doesn't include DMs from blocked users", %{conn: conn} do
419 blocker = insert(:user)
420 blocked = insert(:user)
421 user = insert(:user)
422 {:ok, blocker} = User.block(blocker, blocked)
423
424 {:ok, _blocked_direct} =
425 CommonAPI.post(blocked, %{
426 "status" => "Hi @#{blocker.nickname}!",
427 "visibility" => "direct"
428 })
429
430 {:ok, direct} =
431 CommonAPI.post(user, %{
432 "status" => "Hi @#{blocker.nickname}!",
433 "visibility" => "direct"
434 })
435
436 res_conn =
437 conn
438 |> assign(:user, blocker)
439 |> get("/api/statuses/dm_timeline.json")
440
441 [status] = json_response(res_conn, 200)
442 assert status["id"] == direct.id
443 end
444 end
445
446 describe "GET /statuses/mentions.json" do
447 setup [:valid_user]
448
449 test "without valid credentials", %{conn: conn} do
450 conn = get(conn, "/api/statuses/mentions.json")
451 assert json_response(conn, 403) == %{"error" => "Invalid credentials."}
452 end
453
454 test "with credentials", %{conn: conn, user: current_user} do
455 {:ok, activity} =
456 CommonAPI.post(current_user, %{
457 "status" => "why is tenshi eating a corndog so cute?",
458 "visibility" => "public"
459 })
460
461 conn =
462 conn
463 |> with_credentials(current_user.nickname, "test")
464 |> get("/api/statuses/mentions.json")
465
466 response = json_response(conn, 200)
467
468 assert length(response) == 1
469
470 assert Enum.at(response, 0) ==
471 ActivityView.render("activity.json", %{
472 user: current_user,
473 for: current_user,
474 activity: activity
475 })
476 end
477
478 test "does not show DMs in mentions timeline", %{conn: conn, user: current_user} do
479 {:ok, _activity} =
480 CommonAPI.post(current_user, %{
481 "status" => "Have you guys ever seen how cute tenshi eating a corndog is?",
482 "visibility" => "direct"
483 })
484
485 conn =
486 conn
487 |> with_credentials(current_user.nickname, "test")
488 |> get("/api/statuses/mentions.json")
489
490 response = json_response(conn, 200)
491
492 assert Enum.empty?(response)
493 end
494 end
495
496 describe "GET /api/qvitter/statuses/notifications.json" do
497 setup [:valid_user]
498
499 test "without valid credentials", %{conn: conn} do
500 conn = get(conn, "/api/qvitter/statuses/notifications.json")
501 assert json_response(conn, 403) == %{"error" => "Invalid credentials."}
502 end
503
504 test "with credentials", %{conn: conn, user: current_user} do
505 other_user = insert(:user)
506
507 {:ok, _activity} =
508 ActivityBuilder.insert(%{"to" => [current_user.ap_id]}, %{user: other_user})
509
510 conn =
511 conn
512 |> with_credentials(current_user.nickname, "test")
513 |> get("/api/qvitter/statuses/notifications.json")
514
515 response = json_response(conn, 200)
516
517 assert length(response) == 1
518
519 assert response ==
520 NotificationView.render("notification.json", %{
521 notifications: Notification.for_user(current_user),
522 for: current_user
523 })
524 end
525
526 test "muted user", %{conn: conn, user: current_user} do
527 other_user = insert(:user)
528
529 {:ok, current_user} = User.mute(current_user, other_user)
530
531 {:ok, _activity} =
532 ActivityBuilder.insert(%{"to" => [current_user.ap_id]}, %{user: other_user})
533
534 conn =
535 conn
536 |> with_credentials(current_user.nickname, "test")
537 |> get("/api/qvitter/statuses/notifications.json")
538
539 assert json_response(conn, 200) == []
540 end
541
542 test "muted user with with_muted parameter", %{conn: conn, user: current_user} do
543 other_user = insert(:user)
544
545 {:ok, current_user} = User.mute(current_user, other_user)
546
547 {:ok, _activity} =
548 ActivityBuilder.insert(%{"to" => [current_user.ap_id]}, %{user: other_user})
549
550 conn =
551 conn
552 |> with_credentials(current_user.nickname, "test")
553 |> get("/api/qvitter/statuses/notifications.json", %{"with_muted" => "true"})
554
555 assert length(json_response(conn, 200)) == 1
556 end
557 end
558
559 describe "POST /api/qvitter/statuses/notifications/read" do
560 setup [:valid_user]
561
562 test "without valid credentials", %{conn: conn} do
563 conn = post(conn, "/api/qvitter/statuses/notifications/read", %{"latest_id" => 1_234_567})
564 assert json_response(conn, 403) == %{"error" => "Invalid credentials."}
565 end
566
567 test "with credentials, without any params", %{conn: conn, user: current_user} do
568 conn =
569 conn
570 |> with_credentials(current_user.nickname, "test")
571 |> post("/api/qvitter/statuses/notifications/read")
572
573 assert json_response(conn, 400) == %{
574 "error" => "You need to specify latest_id",
575 "request" => "/api/qvitter/statuses/notifications/read"
576 }
577 end
578
579 test "with credentials, with params", %{conn: conn, user: current_user} do
580 other_user = insert(:user)
581
582 {:ok, _activity} =
583 ActivityBuilder.insert(%{"to" => [current_user.ap_id]}, %{user: other_user})
584
585 response_conn =
586 conn
587 |> with_credentials(current_user.nickname, "test")
588 |> get("/api/qvitter/statuses/notifications.json")
589
590 [notification] = response = json_response(response_conn, 200)
591
592 assert length(response) == 1
593
594 assert notification["is_seen"] == 0
595
596 response_conn =
597 conn
598 |> with_credentials(current_user.nickname, "test")
599 |> post("/api/qvitter/statuses/notifications/read", %{"latest_id" => notification["id"]})
600
601 [notification] = response = json_response(response_conn, 200)
602
603 assert length(response) == 1
604
605 assert notification["is_seen"] == 1
606 end
607 end
608
609 describe "GET /statuses/user_timeline.json" do
610 setup [:valid_user]
611
612 test "without any params", %{conn: conn} do
613 conn = get(conn, "/api/statuses/user_timeline.json")
614
615 assert json_response(conn, 400) == %{
616 "error" => "You need to specify screen_name or user_id",
617 "request" => "/api/statuses/user_timeline.json"
618 }
619 end
620
621 test "with user_id", %{conn: conn} do
622 user = insert(:user)
623 {:ok, activity} = ActivityBuilder.insert(%{"id" => 1}, %{user: user})
624
625 conn = get(conn, "/api/statuses/user_timeline.json", %{"user_id" => user.id})
626 response = json_response(conn, 200)
627 assert length(response) == 1
628
629 assert Enum.at(response, 0) ==
630 ActivityView.render("activity.json", %{user: user, activity: activity})
631 end
632
633 test "with screen_name", %{conn: conn} do
634 user = insert(:user)
635 {:ok, activity} = ActivityBuilder.insert(%{"id" => 1}, %{user: user})
636
637 conn = get(conn, "/api/statuses/user_timeline.json", %{"screen_name" => user.nickname})
638 response = json_response(conn, 200)
639 assert length(response) == 1
640
641 assert Enum.at(response, 0) ==
642 ActivityView.render("activity.json", %{user: user, activity: activity})
643 end
644
645 test "with credentials", %{conn: conn, user: current_user} do
646 {:ok, activity} = ActivityBuilder.insert(%{"id" => 1}, %{user: current_user})
647
648 conn =
649 conn
650 |> with_credentials(current_user.nickname, "test")
651 |> get("/api/statuses/user_timeline.json")
652
653 response = json_response(conn, 200)
654
655 assert length(response) == 1
656
657 assert Enum.at(response, 0) ==
658 ActivityView.render("activity.json", %{
659 user: current_user,
660 for: current_user,
661 activity: activity
662 })
663 end
664
665 test "with credentials with user_id", %{conn: conn, user: current_user} do
666 user = insert(:user)
667 {:ok, activity} = ActivityBuilder.insert(%{"id" => 1}, %{user: user})
668
669 conn =
670 conn
671 |> with_credentials(current_user.nickname, "test")
672 |> get("/api/statuses/user_timeline.json", %{"user_id" => user.id})
673
674 response = json_response(conn, 200)
675
676 assert length(response) == 1
677
678 assert Enum.at(response, 0) ==
679 ActivityView.render("activity.json", %{user: user, activity: activity})
680 end
681
682 test "with credentials screen_name", %{conn: conn, user: current_user} do
683 user = insert(:user)
684 {:ok, activity} = ActivityBuilder.insert(%{"id" => 1}, %{user: user})
685
686 conn =
687 conn
688 |> with_credentials(current_user.nickname, "test")
689 |> get("/api/statuses/user_timeline.json", %{"screen_name" => user.nickname})
690
691 response = json_response(conn, 200)
692
693 assert length(response) == 1
694
695 assert Enum.at(response, 0) ==
696 ActivityView.render("activity.json", %{user: user, activity: activity})
697 end
698
699 test "with credentials with user_id, excluding RTs", %{conn: conn, user: current_user} do
700 user = insert(:user)
701 {:ok, activity} = ActivityBuilder.insert(%{"id" => 1, "type" => "Create"}, %{user: user})
702 {:ok, _} = ActivityBuilder.insert(%{"id" => 2, "type" => "Announce"}, %{user: user})
703
704 conn =
705 conn
706 |> with_credentials(current_user.nickname, "test")
707 |> get("/api/statuses/user_timeline.json", %{
708 "user_id" => user.id,
709 "include_rts" => "false"
710 })
711
712 response = json_response(conn, 200)
713
714 assert length(response) == 1
715
716 assert Enum.at(response, 0) ==
717 ActivityView.render("activity.json", %{user: user, activity: activity})
718
719 conn =
720 conn
721 |> get("/api/statuses/user_timeline.json", %{"user_id" => user.id, "include_rts" => "0"})
722
723 response = json_response(conn, 200)
724
725 assert length(response) == 1
726
727 assert Enum.at(response, 0) ==
728 ActivityView.render("activity.json", %{user: user, activity: activity})
729 end
730 end
731
732 describe "POST /friendships/create.json" do
733 setup [:valid_user]
734
735 test "without valid credentials", %{conn: conn} do
736 conn = post(conn, "/api/friendships/create.json")
737 assert json_response(conn, 403) == %{"error" => "Invalid credentials."}
738 end
739
740 test "with credentials", %{conn: conn, user: current_user} do
741 followed = insert(:user)
742
743 conn =
744 conn
745 |> with_credentials(current_user.nickname, "test")
746 |> post("/api/friendships/create.json", %{user_id: followed.id})
747
748 current_user = User.get_cached_by_id(current_user.id)
749 assert User.ap_followers(followed) in current_user.following
750
751 assert json_response(conn, 200) ==
752 UserView.render("show.json", %{user: followed, for: current_user})
753 end
754
755 test "for restricted account", %{conn: conn, user: current_user} do
756 followed = insert(:user, info: %User.Info{locked: true})
757
758 conn =
759 conn
760 |> with_credentials(current_user.nickname, "test")
761 |> post("/api/friendships/create.json", %{user_id: followed.id})
762
763 current_user = User.get_cached_by_id(current_user.id)
764 followed = User.get_cached_by_id(followed.id)
765
766 refute User.ap_followers(followed) in current_user.following
767
768 assert json_response(conn, 200) ==
769 UserView.render("show.json", %{user: followed, for: current_user})
770 end
771 end
772
773 describe "POST /friendships/destroy.json" do
774 setup [:valid_user]
775
776 test "without valid credentials", %{conn: conn} do
777 conn = post(conn, "/api/friendships/destroy.json")
778 assert json_response(conn, 403) == %{"error" => "Invalid credentials."}
779 end
780
781 test "with credentials", %{conn: conn, user: current_user} do
782 followed = insert(:user)
783
784 {:ok, current_user} = User.follow(current_user, followed)
785 assert User.ap_followers(followed) in current_user.following
786 ActivityPub.follow(current_user, followed)
787
788 conn =
789 conn
790 |> with_credentials(current_user.nickname, "test")
791 |> post("/api/friendships/destroy.json", %{user_id: followed.id})
792
793 current_user = User.get_cached_by_id(current_user.id)
794 assert current_user.following == [current_user.ap_id]
795
796 assert json_response(conn, 200) ==
797 UserView.render("show.json", %{user: followed, for: current_user})
798 end
799 end
800
801 describe "POST /blocks/create.json" do
802 setup [:valid_user]
803
804 test "without valid credentials", %{conn: conn} do
805 conn = post(conn, "/api/blocks/create.json")
806 assert json_response(conn, 403) == %{"error" => "Invalid credentials."}
807 end
808
809 test "with credentials", %{conn: conn, user: current_user} do
810 blocked = insert(:user)
811
812 conn =
813 conn
814 |> with_credentials(current_user.nickname, "test")
815 |> post("/api/blocks/create.json", %{user_id: blocked.id})
816
817 current_user = User.get_cached_by_id(current_user.id)
818 assert User.blocks?(current_user, blocked)
819
820 assert json_response(conn, 200) ==
821 UserView.render("show.json", %{user: blocked, for: current_user})
822 end
823 end
824
825 describe "POST /blocks/destroy.json" do
826 setup [:valid_user]
827
828 test "without valid credentials", %{conn: conn} do
829 conn = post(conn, "/api/blocks/destroy.json")
830 assert json_response(conn, 403) == %{"error" => "Invalid credentials."}
831 end
832
833 test "with credentials", %{conn: conn, user: current_user} do
834 blocked = insert(:user)
835
836 {:ok, current_user, blocked} = TwitterAPI.block(current_user, %{"user_id" => blocked.id})
837 assert User.blocks?(current_user, blocked)
838
839 conn =
840 conn
841 |> with_credentials(current_user.nickname, "test")
842 |> post("/api/blocks/destroy.json", %{user_id: blocked.id})
843
844 current_user = User.get_cached_by_id(current_user.id)
845 assert current_user.info.blocks == []
846
847 assert json_response(conn, 200) ==
848 UserView.render("show.json", %{user: blocked, for: current_user})
849 end
850 end
851
852 describe "GET /help/test.json" do
853 test "returns \"ok\"", %{conn: conn} do
854 conn = get(conn, "/api/help/test.json")
855 assert json_response(conn, 200) == "ok"
856 end
857 end
858
859 describe "POST /api/qvitter/update_avatar.json" do
860 setup [:valid_user]
861
862 test "without valid credentials", %{conn: conn} do
863 conn = post(conn, "/api/qvitter/update_avatar.json")
864 assert json_response(conn, 403) == %{"error" => "Invalid credentials."}
865 end
866
867 test "with credentials", %{conn: conn, user: current_user} do
868 avatar_image = File.read!("test/fixtures/avatar_data_uri")
869
870 conn =
871 conn
872 |> with_credentials(current_user.nickname, "test")
873 |> post("/api/qvitter/update_avatar.json", %{img: avatar_image})
874
875 current_user = User.get_cached_by_id(current_user.id)
876 assert is_map(current_user.avatar)
877
878 assert json_response(conn, 200) ==
879 UserView.render("show.json", %{user: current_user, for: current_user})
880 end
881
882 test "user avatar can be reset", %{conn: conn, user: current_user} do
883 conn =
884 conn
885 |> with_credentials(current_user.nickname, "test")
886 |> post("/api/qvitter/update_avatar.json", %{img: ""})
887
888 current_user = User.get_cached_by_id(current_user.id)
889 assert current_user.avatar == nil
890
891 assert json_response(conn, 200) ==
892 UserView.render("show.json", %{user: current_user, for: current_user})
893 end
894 end
895
896 describe "GET /api/qvitter/mutes.json" do
897 setup [:valid_user]
898
899 test "unimplemented mutes without valid credentials", %{conn: conn} do
900 conn = get(conn, "/api/qvitter/mutes.json")
901 assert json_response(conn, 403) == %{"error" => "Invalid credentials."}
902 end
903
904 test "unimplemented mutes with credentials", %{conn: conn, user: current_user} do
905 response =
906 conn
907 |> with_credentials(current_user.nickname, "test")
908 |> get("/api/qvitter/mutes.json")
909 |> json_response(200)
910
911 assert [] = response
912 end
913 end
914
915 describe "POST /api/favorites/create/:id" do
916 setup [:valid_user]
917
918 test "without valid credentials", %{conn: conn} do
919 note_activity = insert(:note_activity)
920 conn = post(conn, "/api/favorites/create/#{note_activity.id}.json")
921 assert json_response(conn, 403) == %{"error" => "Invalid credentials."}
922 end
923
924 test "with credentials", %{conn: conn, user: current_user} do
925 note_activity = insert(:note_activity)
926
927 conn =
928 conn
929 |> with_credentials(current_user.nickname, "test")
930 |> post("/api/favorites/create/#{note_activity.id}.json")
931
932 assert json_response(conn, 200)
933 end
934
935 test "with credentials, invalid param", %{conn: conn, user: current_user} do
936 conn =
937 conn
938 |> with_credentials(current_user.nickname, "test")
939 |> post("/api/favorites/create/wrong.json")
940
941 assert json_response(conn, 400)
942 end
943
944 test "with credentials, invalid activity", %{conn: conn, user: current_user} do
945 conn =
946 conn
947 |> with_credentials(current_user.nickname, "test")
948 |> post("/api/favorites/create/1.json")
949
950 assert json_response(conn, 400)
951 end
952 end
953
954 describe "POST /api/favorites/destroy/:id" do
955 setup [:valid_user]
956
957 test "without valid credentials", %{conn: conn} do
958 note_activity = insert(:note_activity)
959 conn = post(conn, "/api/favorites/destroy/#{note_activity.id}.json")
960 assert json_response(conn, 403) == %{"error" => "Invalid credentials."}
961 end
962
963 test "with credentials", %{conn: conn, user: current_user} do
964 note_activity = insert(:note_activity)
965 object = Object.normalize(note_activity)
966 ActivityPub.like(current_user, object)
967
968 conn =
969 conn
970 |> with_credentials(current_user.nickname, "test")
971 |> post("/api/favorites/destroy/#{note_activity.id}.json")
972
973 assert json_response(conn, 200)
974 end
975 end
976
977 describe "POST /api/statuses/retweet/:id" do
978 setup [:valid_user]
979
980 test "without valid credentials", %{conn: conn} do
981 note_activity = insert(:note_activity)
982 conn = post(conn, "/api/statuses/retweet/#{note_activity.id}.json")
983 assert json_response(conn, 403) == %{"error" => "Invalid credentials."}
984 end
985
986 test "with credentials", %{conn: conn, user: current_user} do
987 note_activity = insert(:note_activity)
988
989 request_path = "/api/statuses/retweet/#{note_activity.id}.json"
990
991 response =
992 conn
993 |> with_credentials(current_user.nickname, "test")
994 |> post(request_path)
995
996 activity = Activity.get_by_id(note_activity.id)
997 activity_user = User.get_cached_by_ap_id(note_activity.data["actor"])
998
999 assert json_response(response, 200) ==
1000 ActivityView.render("activity.json", %{
1001 user: activity_user,
1002 for: current_user,
1003 activity: activity
1004 })
1005 end
1006 end
1007
1008 describe "POST /api/statuses/unretweet/:id" do
1009 setup [:valid_user]
1010
1011 test "without valid credentials", %{conn: conn} do
1012 note_activity = insert(:note_activity)
1013 conn = post(conn, "/api/statuses/unretweet/#{note_activity.id}.json")
1014 assert json_response(conn, 403) == %{"error" => "Invalid credentials."}
1015 end
1016
1017 test "with credentials", %{conn: conn, user: current_user} do
1018 note_activity = insert(:note_activity)
1019
1020 request_path = "/api/statuses/retweet/#{note_activity.id}.json"
1021
1022 _response =
1023 conn
1024 |> with_credentials(current_user.nickname, "test")
1025 |> post(request_path)
1026
1027 request_path = String.replace(request_path, "retweet", "unretweet")
1028
1029 response =
1030 conn
1031 |> with_credentials(current_user.nickname, "test")
1032 |> post(request_path)
1033
1034 activity = Activity.get_by_id(note_activity.id)
1035 activity_user = User.get_cached_by_ap_id(note_activity.data["actor"])
1036
1037 assert json_response(response, 200) ==
1038 ActivityView.render("activity.json", %{
1039 user: activity_user,
1040 for: current_user,
1041 activity: activity
1042 })
1043 end
1044 end
1045
1046 describe "POST /api/account/register" do
1047 test "it creates a new user", %{conn: conn} do
1048 data = %{
1049 "nickname" => "lain",
1050 "email" => "lain@wired.jp",
1051 "fullname" => "lain iwakura",
1052 "bio" => "close the world.",
1053 "password" => "bear",
1054 "confirm" => "bear"
1055 }
1056
1057 conn =
1058 conn
1059 |> post("/api/account/register", data)
1060
1061 user = json_response(conn, 200)
1062
1063 fetched_user = User.get_cached_by_nickname("lain")
1064 assert user == UserView.render("show.json", %{user: fetched_user})
1065 end
1066
1067 test "it returns errors on a problem", %{conn: conn} do
1068 data = %{
1069 "email" => "lain@wired.jp",
1070 "fullname" => "lain iwakura",
1071 "bio" => "close the world.",
1072 "password" => "bear",
1073 "confirm" => "bear"
1074 }
1075
1076 conn =
1077 conn
1078 |> post("/api/account/register", data)
1079
1080 errors = json_response(conn, 400)
1081
1082 assert is_binary(errors["error"])
1083 end
1084 end
1085
1086 describe "POST /api/account/password_reset, with valid parameters" do
1087 setup %{conn: conn} do
1088 user = insert(:user)
1089 conn = post(conn, "/api/account/password_reset?email=#{user.email}")
1090 %{conn: conn, user: user}
1091 end
1092
1093 test "it returns 204", %{conn: conn} do
1094 assert json_response(conn, :no_content)
1095 end
1096
1097 test "it creates a PasswordResetToken record for user", %{user: user} do
1098 token_record = Repo.get_by(Pleroma.PasswordResetToken, user_id: user.id)
1099 assert token_record
1100 end
1101
1102 test "it sends an email to user", %{user: user} do
1103 ObanHelpers.perform_all()
1104 token_record = Repo.get_by(Pleroma.PasswordResetToken, user_id: user.id)
1105
1106 email = Pleroma.Emails.UserEmail.password_reset_email(user, token_record.token)
1107 notify_email = Pleroma.Config.get([:instance, :notify_email])
1108 instance_name = Pleroma.Config.get([:instance, :name])
1109
1110 assert_email_sent(
1111 from: {instance_name, notify_email},
1112 to: {user.name, user.email},
1113 html_body: email.html_body
1114 )
1115 end
1116 end
1117
1118 describe "POST /api/account/password_reset, with invalid parameters" do
1119 setup [:valid_user]
1120
1121 test "it returns 404 when user is not found", %{conn: conn, user: user} do
1122 conn = post(conn, "/api/account/password_reset?email=nonexisting_#{user.email}")
1123 assert conn.status == 404
1124 assert conn.resp_body == ""
1125 end
1126
1127 test "it returns 400 when user is not local", %{conn: conn, user: user} do
1128 {:ok, user} = Repo.update(Changeset.change(user, local: false))
1129 conn = post(conn, "/api/account/password_reset?email=#{user.email}")
1130 assert conn.status == 400
1131 assert conn.resp_body == ""
1132 end
1133 end
1134
1135 describe "GET /api/account/confirm_email/:id/:token" do
1136 setup do
1137 user = insert(:user)
1138 info_change = User.Info.confirmation_changeset(user.info, need_confirmation: true)
1139
1140 {:ok, user} =
1141 user
1142 |> Changeset.change()
1143 |> Changeset.put_embed(:info, info_change)
1144 |> Repo.update()
1145
1146 assert user.info.confirmation_pending
1147
1148 [user: user]
1149 end
1150
1151 test "it redirects to root url", %{conn: conn, user: user} do
1152 conn = get(conn, "/api/account/confirm_email/#{user.id}/#{user.info.confirmation_token}")
1153
1154 assert 302 == conn.status
1155 end
1156
1157 test "it confirms the user account", %{conn: conn, user: user} do
1158 get(conn, "/api/account/confirm_email/#{user.id}/#{user.info.confirmation_token}")
1159
1160 user = User.get_cached_by_id(user.id)
1161
1162 refute user.info.confirmation_pending
1163 refute user.info.confirmation_token
1164 end
1165
1166 test "it returns 500 if user cannot be found by id", %{conn: conn, user: user} do
1167 conn = get(conn, "/api/account/confirm_email/0/#{user.info.confirmation_token}")
1168
1169 assert 500 == conn.status
1170 end
1171
1172 test "it returns 500 if token is invalid", %{conn: conn, user: user} do
1173 conn = get(conn, "/api/account/confirm_email/#{user.id}/wrong_token")
1174
1175 assert 500 == conn.status
1176 end
1177 end
1178
1179 describe "POST /api/account/resend_confirmation_email" do
1180 setup do
1181 setting = Pleroma.Config.get([:instance, :account_activation_required])
1182
1183 unless setting do
1184 Pleroma.Config.put([:instance, :account_activation_required], true)
1185 on_exit(fn -> Pleroma.Config.put([:instance, :account_activation_required], setting) end)
1186 end
1187
1188 user = insert(:user)
1189 info_change = User.Info.confirmation_changeset(user.info, need_confirmation: true)
1190
1191 {:ok, user} =
1192 user
1193 |> Changeset.change()
1194 |> Changeset.put_embed(:info, info_change)
1195 |> Repo.update()
1196
1197 assert user.info.confirmation_pending
1198
1199 [user: user]
1200 end
1201
1202 test "it returns 204 No Content", %{conn: conn, user: user} do
1203 conn
1204 |> assign(:user, user)
1205 |> post("/api/account/resend_confirmation_email?email=#{user.email}")
1206 |> json_response(:no_content)
1207 end
1208
1209 test "it sends confirmation email", %{conn: conn, user: user} do
1210 conn
1211 |> assign(:user, user)
1212 |> post("/api/account/resend_confirmation_email?email=#{user.email}")
1213
1214 ObanHelpers.perform_all()
1215
1216 email = Pleroma.Emails.UserEmail.account_confirmation_email(user)
1217 notify_email = Pleroma.Config.get([:instance, :notify_email])
1218 instance_name = Pleroma.Config.get([:instance, :name])
1219
1220 assert_email_sent(
1221 from: {instance_name, notify_email},
1222 to: {user.name, user.email},
1223 html_body: email.html_body
1224 )
1225 end
1226 end
1227
1228 describe "GET /api/externalprofile/show" do
1229 test "it returns the user", %{conn: conn} do
1230 user = insert(:user)
1231 other_user = insert(:user)
1232
1233 conn =
1234 conn
1235 |> assign(:user, user)
1236 |> get("/api/externalprofile/show", %{profileurl: other_user.ap_id})
1237
1238 assert json_response(conn, 200) == UserView.render("show.json", %{user: other_user})
1239 end
1240 end
1241
1242 describe "GET /api/statuses/followers" do
1243 test "it returns a user's followers", %{conn: conn} do
1244 user = insert(:user)
1245 follower_one = insert(:user)
1246 follower_two = insert(:user)
1247 _not_follower = insert(:user)
1248
1249 {:ok, follower_one} = User.follow(follower_one, user)
1250 {:ok, follower_two} = User.follow(follower_two, user)
1251
1252 conn =
1253 conn
1254 |> assign(:user, user)
1255 |> get("/api/statuses/followers")
1256
1257 expected = UserView.render("index.json", %{users: [follower_one, follower_two], for: user})
1258 result = json_response(conn, 200)
1259 assert Enum.sort(expected) == Enum.sort(result)
1260 end
1261
1262 test "it returns 20 followers per page", %{conn: conn} do
1263 user = insert(:user)
1264 followers = insert_list(21, :user)
1265
1266 Enum.each(followers, fn follower ->
1267 User.follow(follower, user)
1268 end)
1269
1270 res_conn =
1271 conn
1272 |> assign(:user, user)
1273 |> get("/api/statuses/followers")
1274
1275 result = json_response(res_conn, 200)
1276 assert length(result) == 20
1277
1278 res_conn =
1279 conn
1280 |> assign(:user, user)
1281 |> get("/api/statuses/followers?page=2")
1282
1283 result = json_response(res_conn, 200)
1284 assert length(result) == 1
1285 end
1286
1287 test "it returns a given user's followers with user_id", %{conn: conn} do
1288 user = insert(:user)
1289 follower_one = insert(:user)
1290 follower_two = insert(:user)
1291 not_follower = insert(:user)
1292
1293 {:ok, follower_one} = User.follow(follower_one, user)
1294 {:ok, follower_two} = User.follow(follower_two, user)
1295
1296 conn =
1297 conn
1298 |> assign(:user, not_follower)
1299 |> get("/api/statuses/followers", %{"user_id" => user.id})
1300
1301 assert MapSet.equal?(
1302 MapSet.new(json_response(conn, 200)),
1303 MapSet.new(
1304 UserView.render("index.json", %{
1305 users: [follower_one, follower_two],
1306 for: not_follower
1307 })
1308 )
1309 )
1310 end
1311
1312 test "it returns empty when hide_followers is set to true", %{conn: conn} do
1313 user = insert(:user, %{info: %{hide_followers: true}})
1314 follower_one = insert(:user)
1315 follower_two = insert(:user)
1316 not_follower = insert(:user)
1317
1318 {:ok, _follower_one} = User.follow(follower_one, user)
1319 {:ok, _follower_two} = User.follow(follower_two, user)
1320
1321 response =
1322 conn
1323 |> assign(:user, not_follower)
1324 |> get("/api/statuses/followers", %{"user_id" => user.id})
1325 |> json_response(200)
1326
1327 assert [] == response
1328 end
1329
1330 test "it returns the followers when hide_followers is set to true if requested by the user themselves",
1331 %{
1332 conn: conn
1333 } do
1334 user = insert(:user, %{info: %{hide_followers: true}})
1335 follower_one = insert(:user)
1336 follower_two = insert(:user)
1337 _not_follower = insert(:user)
1338
1339 {:ok, _follower_one} = User.follow(follower_one, user)
1340 {:ok, _follower_two} = User.follow(follower_two, user)
1341
1342 conn =
1343 conn
1344 |> assign(:user, user)
1345 |> get("/api/statuses/followers", %{"user_id" => user.id})
1346
1347 refute [] == json_response(conn, 200)
1348 end
1349 end
1350
1351 describe "GET /api/statuses/blocks" do
1352 test "it returns the list of users blocked by requester", %{conn: conn} do
1353 user = insert(:user)
1354 other_user = insert(:user)
1355
1356 {:ok, user} = User.block(user, other_user)
1357
1358 conn =
1359 conn
1360 |> assign(:user, user)
1361 |> get("/api/statuses/blocks")
1362
1363 expected = UserView.render("index.json", %{users: [other_user], for: user})
1364 result = json_response(conn, 200)
1365 assert Enum.sort(expected) == Enum.sort(result)
1366 end
1367 end
1368
1369 describe "GET /api/statuses/friends" do
1370 test "it returns the logged in user's friends", %{conn: conn} do
1371 user = insert(:user)
1372 followed_one = insert(:user)
1373 followed_two = insert(:user)
1374 _not_followed = insert(:user)
1375
1376 {:ok, user} = User.follow(user, followed_one)
1377 {:ok, user} = User.follow(user, followed_two)
1378
1379 conn =
1380 conn
1381 |> assign(:user, user)
1382 |> get("/api/statuses/friends")
1383
1384 expected = UserView.render("index.json", %{users: [followed_one, followed_two], for: user})
1385 result = json_response(conn, 200)
1386 assert Enum.sort(expected) == Enum.sort(result)
1387 end
1388
1389 test "it returns 20 friends per page, except if 'export' is set to true", %{conn: conn} do
1390 user = insert(:user)
1391 followeds = insert_list(21, :user)
1392
1393 {:ok, user} =
1394 Enum.reduce(followeds, {:ok, user}, fn followed, {:ok, user} ->
1395 User.follow(user, followed)
1396 end)
1397
1398 res_conn =
1399 conn
1400 |> assign(:user, user)
1401 |> get("/api/statuses/friends")
1402
1403 result = json_response(res_conn, 200)
1404 assert length(result) == 20
1405
1406 res_conn =
1407 conn
1408 |> assign(:user, user)
1409 |> get("/api/statuses/friends", %{page: 2})
1410
1411 result = json_response(res_conn, 200)
1412 assert length(result) == 1
1413
1414 res_conn =
1415 conn
1416 |> assign(:user, user)
1417 |> get("/api/statuses/friends", %{all: true})
1418
1419 result = json_response(res_conn, 200)
1420 assert length(result) == 21
1421 end
1422
1423 test "it returns a given user's friends with user_id", %{conn: conn} do
1424 user = insert(:user)
1425 followed_one = insert(:user)
1426 followed_two = insert(:user)
1427 _not_followed = insert(:user)
1428
1429 {:ok, user} = User.follow(user, followed_one)
1430 {:ok, user} = User.follow(user, followed_two)
1431
1432 conn =
1433 conn
1434 |> assign(:user, user)
1435 |> get("/api/statuses/friends", %{"user_id" => user.id})
1436
1437 assert MapSet.equal?(
1438 MapSet.new(json_response(conn, 200)),
1439 MapSet.new(
1440 UserView.render("index.json", %{users: [followed_one, followed_two], for: user})
1441 )
1442 )
1443 end
1444
1445 test "it returns empty when hide_follows is set to true", %{conn: conn} do
1446 user = insert(:user, %{info: %{hide_follows: true}})
1447 followed_one = insert(:user)
1448 followed_two = insert(:user)
1449 not_followed = insert(:user)
1450
1451 {:ok, user} = User.follow(user, followed_one)
1452 {:ok, user} = User.follow(user, followed_two)
1453
1454 conn =
1455 conn
1456 |> assign(:user, not_followed)
1457 |> get("/api/statuses/friends", %{"user_id" => user.id})
1458
1459 assert [] == json_response(conn, 200)
1460 end
1461
1462 test "it returns friends when hide_follows is set to true if the user themselves request it",
1463 %{
1464 conn: conn
1465 } do
1466 user = insert(:user, %{info: %{hide_follows: true}})
1467 followed_one = insert(:user)
1468 followed_two = insert(:user)
1469 _not_followed = insert(:user)
1470
1471 {:ok, _user} = User.follow(user, followed_one)
1472 {:ok, _user} = User.follow(user, followed_two)
1473
1474 response =
1475 conn
1476 |> assign(:user, user)
1477 |> get("/api/statuses/friends", %{"user_id" => user.id})
1478 |> json_response(200)
1479
1480 refute [] == response
1481 end
1482
1483 test "it returns a given user's friends with screen_name", %{conn: conn} do
1484 user = insert(:user)
1485 followed_one = insert(:user)
1486 followed_two = insert(:user)
1487 _not_followed = insert(:user)
1488
1489 {:ok, user} = User.follow(user, followed_one)
1490 {:ok, user} = User.follow(user, followed_two)
1491
1492 conn =
1493 conn
1494 |> assign(:user, user)
1495 |> get("/api/statuses/friends", %{"screen_name" => user.nickname})
1496
1497 assert MapSet.equal?(
1498 MapSet.new(json_response(conn, 200)),
1499 MapSet.new(
1500 UserView.render("index.json", %{users: [followed_one, followed_two], for: user})
1501 )
1502 )
1503 end
1504 end
1505
1506 describe "GET /friends/ids" do
1507 test "it returns a user's friends", %{conn: conn} do
1508 user = insert(:user)
1509 followed_one = insert(:user)
1510 followed_two = insert(:user)
1511 _not_followed = insert(:user)
1512
1513 {:ok, user} = User.follow(user, followed_one)
1514 {:ok, user} = User.follow(user, followed_two)
1515
1516 conn =
1517 conn
1518 |> assign(:user, user)
1519 |> get("/api/friends/ids")
1520
1521 expected = [followed_one.id, followed_two.id]
1522
1523 assert MapSet.equal?(
1524 MapSet.new(Poison.decode!(json_response(conn, 200))),
1525 MapSet.new(expected)
1526 )
1527 end
1528 end
1529
1530 describe "POST /api/account/update_profile.json" do
1531 test "it updates a user's profile", %{conn: conn} do
1532 user = insert(:user)
1533 user2 = insert(:user)
1534
1535 conn =
1536 conn
1537 |> assign(:user, user)
1538 |> post("/api/account/update_profile.json", %{
1539 "name" => "new name",
1540 "description" => "hi @#{user2.nickname}"
1541 })
1542
1543 user = Repo.get!(User, user.id)
1544 assert user.name == "new name"
1545
1546 assert user.bio ==
1547 "hi <span class='h-card'><a data-user='#{user2.id}' class='u-url mention' href='#{
1548 user2.ap_id
1549 }'>@<span>#{user2.nickname}</span></a></span>"
1550
1551 assert json_response(conn, 200) == UserView.render("user.json", %{user: user, for: user})
1552 end
1553
1554 test "it sets and un-sets hide_follows", %{conn: conn} do
1555 user = insert(:user)
1556
1557 conn
1558 |> assign(:user, user)
1559 |> post("/api/account/update_profile.json", %{
1560 "hide_follows" => "true"
1561 })
1562
1563 user = Repo.get!(User, user.id)
1564 assert user.info.hide_follows == true
1565
1566 conn =
1567 conn
1568 |> assign(:user, user)
1569 |> post("/api/account/update_profile.json", %{
1570 "hide_follows" => "false"
1571 })
1572
1573 user = refresh_record(user)
1574 assert user.info.hide_follows == false
1575 assert json_response(conn, 200) == UserView.render("user.json", %{user: user, for: user})
1576 end
1577
1578 test "it sets and un-sets hide_followers", %{conn: conn} do
1579 user = insert(:user)
1580
1581 conn
1582 |> assign(:user, user)
1583 |> post("/api/account/update_profile.json", %{
1584 "hide_followers" => "true"
1585 })
1586
1587 user = Repo.get!(User, user.id)
1588 assert user.info.hide_followers == true
1589
1590 conn =
1591 conn
1592 |> assign(:user, user)
1593 |> post("/api/account/update_profile.json", %{
1594 "hide_followers" => "false"
1595 })
1596
1597 user = Repo.get!(User, user.id)
1598 assert user.info.hide_followers == false
1599 assert json_response(conn, 200) == UserView.render("user.json", %{user: user, for: user})
1600 end
1601
1602 test "it sets and un-sets show_role", %{conn: conn} do
1603 user = insert(:user)
1604
1605 conn
1606 |> assign(:user, user)
1607 |> post("/api/account/update_profile.json", %{
1608 "show_role" => "true"
1609 })
1610
1611 user = Repo.get!(User, user.id)
1612 assert user.info.show_role == true
1613
1614 conn =
1615 conn
1616 |> assign(:user, user)
1617 |> post("/api/account/update_profile.json", %{
1618 "show_role" => "false"
1619 })
1620
1621 user = Repo.get!(User, user.id)
1622 assert user.info.show_role == false
1623 assert json_response(conn, 200) == UserView.render("user.json", %{user: user, for: user})
1624 end
1625
1626 test "it sets and un-sets skip_thread_containment", %{conn: conn} do
1627 user = insert(:user)
1628
1629 response =
1630 conn
1631 |> assign(:user, user)
1632 |> post("/api/account/update_profile.json", %{"skip_thread_containment" => "true"})
1633 |> json_response(200)
1634
1635 assert response["pleroma"]["skip_thread_containment"] == true
1636 user = refresh_record(user)
1637 assert user.info.skip_thread_containment
1638
1639 response =
1640 conn
1641 |> assign(:user, user)
1642 |> post("/api/account/update_profile.json", %{"skip_thread_containment" => "false"})
1643 |> json_response(200)
1644
1645 assert response["pleroma"]["skip_thread_containment"] == false
1646 refute refresh_record(user).info.skip_thread_containment
1647 end
1648
1649 test "it locks an account", %{conn: conn} do
1650 user = insert(:user)
1651
1652 conn =
1653 conn
1654 |> assign(:user, user)
1655 |> post("/api/account/update_profile.json", %{
1656 "locked" => "true"
1657 })
1658
1659 user = Repo.get!(User, user.id)
1660 assert user.info.locked == true
1661
1662 assert json_response(conn, 200) == UserView.render("user.json", %{user: user, for: user})
1663 end
1664
1665 test "it unlocks an account", %{conn: conn} do
1666 user = insert(:user)
1667
1668 conn =
1669 conn
1670 |> assign(:user, user)
1671 |> post("/api/account/update_profile.json", %{
1672 "locked" => "false"
1673 })
1674
1675 user = Repo.get!(User, user.id)
1676 assert user.info.locked == false
1677
1678 assert json_response(conn, 200) == UserView.render("user.json", %{user: user, for: user})
1679 end
1680
1681 # Broken before the change to class="emoji" and non-<img/> in the DB
1682 @tag :skip
1683 test "it formats emojos", %{conn: conn} do
1684 user = insert(:user)
1685
1686 conn =
1687 conn
1688 |> assign(:user, user)
1689 |> post("/api/account/update_profile.json", %{
1690 "bio" => "I love our :moominmamma:​"
1691 })
1692
1693 assert response = json_response(conn, 200)
1694
1695 assert %{
1696 "description" => "I love our :moominmamma:",
1697 "description_html" =>
1698 ~s{I love our <img class="emoji" alt="moominmamma" title="moominmamma" src="} <>
1699 _
1700 } = response
1701
1702 conn =
1703 conn
1704 |> get("/api/users/show.json?user_id=#{user.nickname}")
1705
1706 assert response == json_response(conn, 200)
1707 end
1708 end
1709
1710 defp valid_user(_context) do
1711 user = insert(:user)
1712 [user: user]
1713 end
1714
1715 defp with_credentials(conn, username, password) do
1716 header_content = "Basic " <> Base.encode64("#{username}:#{password}")
1717 put_req_header(conn, "authorization", header_content)
1718 end
1719
1720 describe "GET /api/search.json" do
1721 test "it returns search results", %{conn: conn} do
1722 user = insert(:user)
1723 user_two = insert(:user, %{nickname: "shp@shitposter.club"})
1724
1725 {:ok, activity} = CommonAPI.post(user, %{"status" => "This is about 2hu"})
1726 {:ok, _} = CommonAPI.post(user_two, %{"status" => "This isn't"})
1727
1728 conn =
1729 conn
1730 |> get("/api/search.json", %{"q" => "2hu", "page" => "1", "rpp" => "1"})
1731
1732 assert [status] = json_response(conn, 200)
1733 assert status["id"] == activity.id
1734 end
1735 end
1736
1737 describe "GET /api/statusnet/tags/timeline/:tag.json" do
1738 test "it returns the tags timeline", %{conn: conn} do
1739 user = insert(:user)
1740 user_two = insert(:user, %{nickname: "shp@shitposter.club"})
1741
1742 {:ok, activity} = CommonAPI.post(user, %{"status" => "This is about #2hu"})
1743 {:ok, _} = CommonAPI.post(user_two, %{"status" => "This isn't"})
1744
1745 conn =
1746 conn
1747 |> get("/api/statusnet/tags/timeline/2hu.json")
1748
1749 assert [status] = json_response(conn, 200)
1750 assert status["id"] == activity.id
1751 end
1752 end
1753
1754 test "Convert newlines to <br> in bio", %{conn: conn} do
1755 user = insert(:user)
1756
1757 _conn =
1758 conn
1759 |> assign(:user, user)
1760 |> post("/api/account/update_profile.json", %{
1761 "description" => "Hello,\r\nWorld! I\n am a test."
1762 })
1763
1764 user = Repo.get!(User, user.id)
1765 assert user.bio == "Hello,<br>World! I<br> am a test."
1766 end
1767
1768 describe "POST /api/pleroma/change_password" do
1769 setup [:valid_user]
1770
1771 test "without credentials", %{conn: conn} do
1772 conn = post(conn, "/api/pleroma/change_password")
1773 assert json_response(conn, 403) == %{"error" => "Invalid credentials."}
1774 end
1775
1776 test "with credentials and invalid password", %{conn: conn, user: current_user} do
1777 conn =
1778 conn
1779 |> with_credentials(current_user.nickname, "test")
1780 |> post("/api/pleroma/change_password", %{
1781 "password" => "hi",
1782 "new_password" => "newpass",
1783 "new_password_confirmation" => "newpass"
1784 })
1785
1786 assert json_response(conn, 200) == %{"error" => "Invalid password."}
1787 end
1788
1789 test "with credentials, valid password and new password and confirmation not matching", %{
1790 conn: conn,
1791 user: current_user
1792 } do
1793 conn =
1794 conn
1795 |> with_credentials(current_user.nickname, "test")
1796 |> post("/api/pleroma/change_password", %{
1797 "password" => "test",
1798 "new_password" => "newpass",
1799 "new_password_confirmation" => "notnewpass"
1800 })
1801
1802 assert json_response(conn, 200) == %{
1803 "error" => "New password does not match confirmation."
1804 }
1805 end
1806
1807 test "with credentials, valid password and invalid new password", %{
1808 conn: conn,
1809 user: current_user
1810 } do
1811 conn =
1812 conn
1813 |> with_credentials(current_user.nickname, "test")
1814 |> post("/api/pleroma/change_password", %{
1815 "password" => "test",
1816 "new_password" => "",
1817 "new_password_confirmation" => ""
1818 })
1819
1820 assert json_response(conn, 200) == %{
1821 "error" => "New password can't be blank."
1822 }
1823 end
1824
1825 test "with credentials, valid password and matching new password and confirmation", %{
1826 conn: conn,
1827 user: current_user
1828 } do
1829 conn =
1830 conn
1831 |> with_credentials(current_user.nickname, "test")
1832 |> post("/api/pleroma/change_password", %{
1833 "password" => "test",
1834 "new_password" => "newpass",
1835 "new_password_confirmation" => "newpass"
1836 })
1837
1838 assert json_response(conn, 200) == %{"status" => "success"}
1839 fetched_user = User.get_cached_by_id(current_user.id)
1840 assert Pbkdf2.checkpw("newpass", fetched_user.password_hash) == true
1841 end
1842 end
1843
1844 describe "POST /api/pleroma/delete_account" do
1845 setup [:valid_user]
1846
1847 test "without credentials", %{conn: conn} do
1848 conn = post(conn, "/api/pleroma/delete_account")
1849 assert json_response(conn, 403) == %{"error" => "Invalid credentials."}
1850 end
1851
1852 test "with credentials and invalid password", %{conn: conn, user: current_user} do
1853 conn =
1854 conn
1855 |> with_credentials(current_user.nickname, "test")
1856 |> post("/api/pleroma/delete_account", %{"password" => "hi"})
1857
1858 assert json_response(conn, 200) == %{"error" => "Invalid password."}
1859 end
1860
1861 test "with credentials and valid password", %{conn: conn, user: current_user} do
1862 conn =
1863 conn
1864 |> with_credentials(current_user.nickname, "test")
1865 |> post("/api/pleroma/delete_account", %{"password" => "test"})
1866
1867 assert json_response(conn, 200) == %{"status" => "success"}
1868 # Wait a second for the started task to end
1869 :timer.sleep(1000)
1870 end
1871 end
1872
1873 describe "GET /api/pleroma/friend_requests" do
1874 test "it lists friend requests" do
1875 user = insert(:user)
1876 other_user = insert(:user)
1877
1878 {:ok, _activity} = ActivityPub.follow(other_user, user)
1879
1880 user = User.get_cached_by_id(user.id)
1881 other_user = User.get_cached_by_id(other_user.id)
1882
1883 assert User.following?(other_user, user) == false
1884
1885 conn =
1886 build_conn()
1887 |> assign(:user, user)
1888 |> get("/api/pleroma/friend_requests")
1889
1890 assert [relationship] = json_response(conn, 200)
1891 assert other_user.id == relationship["id"]
1892 end
1893
1894 test "requires 'read' permission", %{conn: conn} do
1895 token1 = insert(:oauth_token, scopes: ["write"])
1896 token2 = insert(:oauth_token, scopes: ["read"])
1897
1898 for token <- [token1, token2] do
1899 conn =
1900 conn
1901 |> put_req_header("authorization", "Bearer #{token.token}")
1902 |> get("/api/pleroma/friend_requests")
1903
1904 if token == token1 do
1905 assert %{"error" => "Insufficient permissions: read."} == json_response(conn, 403)
1906 else
1907 assert json_response(conn, 200)
1908 end
1909 end
1910 end
1911 end
1912
1913 describe "POST /api/pleroma/friendships/approve" do
1914 test "it approves a friend request" do
1915 user = insert(:user)
1916 other_user = insert(:user)
1917
1918 {:ok, _activity} = ActivityPub.follow(other_user, user)
1919
1920 user = User.get_cached_by_id(user.id)
1921 other_user = User.get_cached_by_id(other_user.id)
1922
1923 assert User.following?(other_user, user) == false
1924
1925 conn =
1926 build_conn()
1927 |> assign(:user, user)
1928 |> post("/api/pleroma/friendships/approve", %{"user_id" => other_user.id})
1929
1930 assert relationship = json_response(conn, 200)
1931 assert other_user.id == relationship["id"]
1932 assert relationship["follows_you"] == true
1933 end
1934 end
1935
1936 describe "POST /api/pleroma/friendships/deny" do
1937 test "it denies a friend request" do
1938 user = insert(:user)
1939 other_user = insert(:user)
1940
1941 {:ok, _activity} = ActivityPub.follow(other_user, user)
1942
1943 user = User.get_cached_by_id(user.id)
1944 other_user = User.get_cached_by_id(other_user.id)
1945
1946 assert User.following?(other_user, user) == false
1947
1948 conn =
1949 build_conn()
1950 |> assign(:user, user)
1951 |> post("/api/pleroma/friendships/deny", %{"user_id" => other_user.id})
1952
1953 assert relationship = json_response(conn, 200)
1954 assert other_user.id == relationship["id"]
1955 assert relationship["follows_you"] == false
1956 end
1957 end
1958
1959 describe "GET /api/pleroma/search_user" do
1960 test "it returns users, ordered by similarity", %{conn: conn} do
1961 user = insert(:user, %{name: "eal"})
1962 user_two = insert(:user, %{name: "eal me"})
1963 _user_three = insert(:user, %{name: "zzz"})
1964
1965 resp =
1966 conn
1967 |> get(twitter_api_search__path(conn, :search_user), query: "eal me")
1968 |> json_response(200)
1969
1970 assert length(resp) == 2
1971 assert [user_two.id, user.id] == Enum.map(resp, fn %{"id" => id} -> id end)
1972 end
1973 end
1974
1975 describe "POST /api/media/upload" do
1976 setup context do
1977 Pleroma.DataCase.ensure_local_uploader(context)
1978 end
1979
1980 test "it performs the upload and sets `data[actor]` with AP id of uploader user", %{
1981 conn: conn
1982 } do
1983 user = insert(:user)
1984
1985 upload_filename = "test/fixtures/image_tmp.jpg"
1986 File.cp!("test/fixtures/image.jpg", upload_filename)
1987
1988 file = %Plug.Upload{
1989 content_type: "image/jpg",
1990 path: Path.absname(upload_filename),
1991 filename: "image.jpg"
1992 }
1993
1994 response =
1995 conn
1996 |> assign(:user, user)
1997 |> put_req_header("content-type", "application/octet-stream")
1998 |> post("/api/media/upload", %{
1999 "media" => file
2000 })
2001 |> json_response(:ok)
2002
2003 assert response["media_id"]
2004 object = Repo.get(Object, response["media_id"])
2005 assert object
2006 assert object.data["actor"] == User.ap_id(user)
2007 end
2008 end
2009
2010 describe "POST /api/media/metadata/create" do
2011 setup do
2012 object = insert(:note)
2013 user = User.get_cached_by_ap_id(object.data["actor"])
2014 %{object: object, user: user}
2015 end
2016
2017 test "it returns :forbidden status on attempt to modify someone else's upload", %{
2018 conn: conn,
2019 object: object
2020 } do
2021 initial_description = object.data["name"]
2022 another_user = insert(:user)
2023
2024 conn
2025 |> assign(:user, another_user)
2026 |> post("/api/media/metadata/create", %{"media_id" => object.id})
2027 |> json_response(:forbidden)
2028
2029 object = Repo.get(Object, object.id)
2030 assert object.data["name"] == initial_description
2031 end
2032
2033 test "it updates `data[name]` of referenced Object with provided value", %{
2034 conn: conn,
2035 object: object,
2036 user: user
2037 } do
2038 description = "Informative description of the image. Initial value: #{object.data["name"]}}"
2039
2040 conn
2041 |> assign(:user, user)
2042 |> post("/api/media/metadata/create", %{
2043 "media_id" => object.id,
2044 "alt_text" => %{"text" => description}
2045 })
2046 |> json_response(:no_content)
2047
2048 object = Repo.get(Object, object.id)
2049 assert object.data["name"] == description
2050 end
2051 end
2052
2053 describe "POST /api/statuses/user_timeline.json?user_id=:user_id&pinned=true" do
2054 test "it returns a list of pinned statuses", %{conn: conn} do
2055 Pleroma.Config.put([:instance, :max_pinned_statuses], 1)
2056
2057 user = insert(:user, %{name: "egor"})
2058 {:ok, %{id: activity_id}} = CommonAPI.post(user, %{"status" => "HI!!!"})
2059 {:ok, _} = CommonAPI.pin(activity_id, user)
2060
2061 resp =
2062 conn
2063 |> get("/api/statuses/user_timeline.json", %{user_id: user.id, pinned: true})
2064 |> json_response(200)
2065
2066 assert length(resp) == 1
2067 assert [%{"id" => ^activity_id, "pinned" => true}] = resp
2068 end
2069 end
2070
2071 describe "POST /api/statuses/pin/:id" do
2072 setup do
2073 Pleroma.Config.put([:instance, :max_pinned_statuses], 1)
2074 [user: insert(:user)]
2075 end
2076
2077 test "without valid credentials", %{conn: conn} do
2078 note_activity = insert(:note_activity)
2079 conn = post(conn, "/api/statuses/pin/#{note_activity.id}.json")
2080 assert json_response(conn, 403) == %{"error" => "Invalid credentials."}
2081 end
2082
2083 test "with credentials", %{conn: conn, user: user} do
2084 {:ok, activity} = CommonAPI.post(user, %{"status" => "test!"})
2085
2086 request_path = "/api/statuses/pin/#{activity.id}.json"
2087
2088 response =
2089 conn
2090 |> with_credentials(user.nickname, "test")
2091 |> post(request_path)
2092
2093 user = refresh_record(user)
2094
2095 assert json_response(response, 200) ==
2096 ActivityView.render("activity.json", %{user: user, for: user, activity: activity})
2097 end
2098 end
2099
2100 describe "POST /api/statuses/unpin/:id" do
2101 setup do
2102 Pleroma.Config.put([:instance, :max_pinned_statuses], 1)
2103 [user: insert(:user)]
2104 end
2105
2106 test "without valid credentials", %{conn: conn} do
2107 note_activity = insert(:note_activity)
2108 conn = post(conn, "/api/statuses/unpin/#{note_activity.id}.json")
2109 assert json_response(conn, 403) == %{"error" => "Invalid credentials."}
2110 end
2111
2112 test "with credentials", %{conn: conn, user: user} do
2113 {:ok, activity} = CommonAPI.post(user, %{"status" => "test!"})
2114 {:ok, activity} = CommonAPI.pin(activity.id, user)
2115
2116 request_path = "/api/statuses/unpin/#{activity.id}.json"
2117
2118 response =
2119 conn
2120 |> with_credentials(user.nickname, "test")
2121 |> post(request_path)
2122
2123 user = refresh_record(user)
2124
2125 assert json_response(response, 200) ==
2126 ActivityView.render("activity.json", %{user: user, for: user, activity: activity})
2127 end
2128 end
2129
2130 describe "GET /api/oauth_tokens" do
2131 setup do
2132 token = insert(:oauth_token) |> Repo.preload(:user)
2133
2134 %{token: token}
2135 end
2136
2137 test "renders list", %{token: token} do
2138 response =
2139 build_conn()
2140 |> assign(:user, token.user)
2141 |> get("/api/oauth_tokens")
2142
2143 keys =
2144 json_response(response, 200)
2145 |> hd()
2146 |> Map.keys()
2147
2148 assert keys -- ["id", "app_name", "valid_until"] == []
2149 end
2150
2151 test "revoke token", %{token: token} do
2152 response =
2153 build_conn()
2154 |> assign(:user, token.user)
2155 |> delete("/api/oauth_tokens/#{token.id}")
2156
2157 tokens = Token.get_user_tokens(token.user)
2158
2159 assert tokens == []
2160 assert response.status == 201
2161 end
2162 end
2163 end