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