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