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