1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
5 defmodule Pleroma.Web.TwitterAPI.ControllerTest do
6 use Pleroma.Web.ConnCase
7 alias Pleroma.Web.TwitterAPI.Representers.ActivityRepresenter
8 alias Pleroma.Builders.{ActivityBuilder, UserBuilder}
9 alias Pleroma.{Repo, Activity, User, Object, Notification}
10 alias Pleroma.Web.ActivityPub.ActivityPub
11 alias Pleroma.Web.TwitterAPI.UserView
12 alias Pleroma.Web.TwitterAPI.NotificationView
13 alias Pleroma.Web.CommonAPI
14 alias Pleroma.Web.TwitterAPI.TwitterAPI
18 import Pleroma.Factory
20 @banner "data:image/gif;base64,R0lGODlhEAAQAMQAAORHHOVSKudfOulrSOp3WOyDZu6QdvCchPGolfO0o/XBs/fNwfjZ0frl3/zy7////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkAABAALAAAAAAQABAAAAVVICSOZGlCQAosJ6mu7fiyZeKqNKToQGDsM8hBADgUXoGAiqhSvp5QAnQKGIgUhwFUYLCVDFCrKUE1lBavAViFIDlTImbKC5Gm2hB0SlBCBMQiB0UjIQA7"
22 describe "POST /api/account/update_profile_banner" do
23 test "it updates the banner", %{conn: conn} do
27 |> assign(:user, user)
28 |> post(authenticated_twitter_api__path(conn, :update_banner), %{"banner" => @banner})
31 user = refresh_record(user)
32 assert user.info.banner["type"] == "Image"
36 describe "POST /api/qvitter/update_background_image" do
37 test "it updates the background", %{conn: conn} do
41 |> assign(:user, user)
42 |> post(authenticated_twitter_api__path(conn, :update_background), %{"img" => @banner})
45 user = refresh_record(user)
46 assert user.info.background["type"] == "Image"
50 describe "POST /api/account/verify_credentials" do
53 test "without valid credentials", %{conn: conn} do
54 conn = post(conn, "/api/account/verify_credentials.json")
55 assert json_response(conn, 403) == %{"error" => "Invalid credentials."}
58 test "with credentials", %{conn: conn, user: user} do
61 |> with_credentials(user.nickname, "test")
62 |> post("/api/account/verify_credentials.json")
65 assert response == UserView.render("show.json", %{user: user, token: response["token"]})
69 describe "POST /statuses/update.json" do
72 test "without valid credentials", %{conn: conn} do
73 conn = post(conn, "/api/statuses/update.json")
74 assert json_response(conn, 403) == %{"error" => "Invalid credentials."}
77 test "with credentials", %{conn: conn, user: user} do
78 conn_with_creds = conn |> with_credentials(user.nickname, "test")
79 request_path = "/api/statuses/update.json"
82 "request" => request_path,
83 "error" => "Client must provide a 'status' parameter with a value."
90 assert json_response(conn, 400) == error_response
94 |> post(request_path, %{status: ""})
96 assert json_response(conn, 400) == error_response
100 |> post(request_path, %{status: " "})
102 assert json_response(conn, 400) == error_response
104 # we post with visibility private in order to avoid triggering relay
107 |> post(request_path, %{status: "Nice meme.", visibility: "private"})
109 assert json_response(conn, 200) ==
110 ActivityRepresenter.to_map(Repo.one(Activity), %{user: user})
114 describe "GET /statuses/public_timeline.json" do
117 test "returns statuses", %{conn: conn} do
119 activities = ActivityBuilder.insert_list(30, %{}, %{user: user})
120 ActivityBuilder.insert_list(10, %{}, %{user: user})
121 since_id = List.last(activities).id
125 |> get("/api/statuses/public_timeline.json", %{since_id: since_id})
127 response = json_response(conn, 200)
129 assert length(response) == 10
132 test "returns 403 to unauthenticated request when the instance is not public", %{conn: conn} do
134 Application.get_env(:pleroma, :instance)
135 |> Keyword.put(:public, false)
137 Application.put_env(:pleroma, :instance, instance)
140 |> get("/api/statuses/public_timeline.json")
141 |> json_response(403)
144 Application.get_env(:pleroma, :instance)
145 |> Keyword.put(:public, true)
147 Application.put_env(:pleroma, :instance, instance)
150 test "returns 200 to authenticated request when the instance is not public",
151 %{conn: conn, user: user} do
153 Application.get_env(:pleroma, :instance)
154 |> Keyword.put(:public, false)
156 Application.put_env(:pleroma, :instance, instance)
159 |> with_credentials(user.nickname, "test")
160 |> get("/api/statuses/public_timeline.json")
161 |> json_response(200)
164 Application.get_env(:pleroma, :instance)
165 |> Keyword.put(:public, true)
167 Application.put_env(:pleroma, :instance, instance)
170 test "returns 200 to unauthenticated request when the instance is public", %{conn: conn} do
172 |> get("/api/statuses/public_timeline.json")
173 |> json_response(200)
176 test "returns 200 to authenticated request when the instance is public",
177 %{conn: conn, user: user} do
179 |> with_credentials(user.nickname, "test")
180 |> get("/api/statuses/public_timeline.json")
181 |> json_response(200)
185 describe "GET /statuses/public_and_external_timeline.json" do
188 test "returns 403 to unauthenticated request when the instance is not public", %{conn: conn} do
190 Application.get_env(:pleroma, :instance)
191 |> Keyword.put(:public, false)
193 Application.put_env(:pleroma, :instance, instance)
196 |> get("/api/statuses/public_and_external_timeline.json")
197 |> json_response(403)
200 Application.get_env(:pleroma, :instance)
201 |> Keyword.put(:public, true)
203 Application.put_env(:pleroma, :instance, instance)
206 test "returns 200 to authenticated request when the instance is not public",
207 %{conn: conn, user: user} do
209 Application.get_env(:pleroma, :instance)
210 |> Keyword.put(:public, false)
212 Application.put_env(:pleroma, :instance, instance)
215 |> with_credentials(user.nickname, "test")
216 |> get("/api/statuses/public_and_external_timeline.json")
217 |> json_response(200)
220 Application.get_env(:pleroma, :instance)
221 |> Keyword.put(:public, true)
223 Application.put_env(:pleroma, :instance, instance)
226 test "returns 200 to unauthenticated request when the instance is public", %{conn: conn} do
228 |> get("/api/statuses/public_and_external_timeline.json")
229 |> json_response(200)
232 test "returns 200 to authenticated request when the instance is public",
233 %{conn: conn, user: user} do
235 |> with_credentials(user.nickname, "test")
236 |> get("/api/statuses/public_and_external_timeline.json")
237 |> json_response(200)
241 describe "GET /statuses/show/:id.json" do
242 test "returns one status", %{conn: conn} do
244 {:ok, activity} = CommonAPI.post(user, %{"status" => "Hey!"})
245 actor = Repo.get_by!(User, ap_id: activity.data["actor"])
249 |> get("/api/statuses/show/#{activity.id}.json")
251 response = json_response(conn, 200)
253 assert response == ActivityRepresenter.to_map(activity, %{user: actor})
257 describe "GET /users/show.json" do
258 test "gets user with screen_name", %{conn: conn} do
263 |> get("/api/users/show.json", %{"screen_name" => user.nickname})
265 response = json_response(conn, 200)
267 assert response["id"] == user.id
270 test "gets user with user_id", %{conn: conn} do
275 |> get("/api/users/show.json", %{"user_id" => user.id})
277 response = json_response(conn, 200)
279 assert response["id"] == user.id
282 test "gets a user for a logged in user", %{conn: conn} do
284 logged_in = insert(:user)
286 {:ok, logged_in, user, _activity} = TwitterAPI.follow(logged_in, %{"user_id" => user.id})
290 |> with_credentials(logged_in.nickname, "test")
291 |> get("/api/users/show.json", %{"user_id" => user.id})
293 response = json_response(conn, 200)
295 assert response["following"] == true
299 describe "GET /statusnet/conversation/:id.json" do
300 test "returns the statuses in the conversation", %{conn: conn} do
301 {:ok, _user} = UserBuilder.insert()
302 {:ok, activity} = ActivityBuilder.insert(%{"type" => "Create", "context" => "2hu"})
303 {:ok, _activity_two} = ActivityBuilder.insert(%{"type" => "Create", "context" => "2hu"})
304 {:ok, _activity_three} = ActivityBuilder.insert(%{"type" => "Create", "context" => "3hu"})
308 |> get("/api/statusnet/conversation/#{activity.data["context_id"]}.json")
310 response = json_response(conn, 200)
312 assert length(response) == 2
316 describe "GET /statuses/friends_timeline.json" do
319 test "without valid credentials", %{conn: conn} do
320 conn = get(conn, "/api/statuses/friends_timeline.json")
321 assert json_response(conn, 403) == %{"error" => "Invalid credentials."}
324 test "with credentials", %{conn: conn, user: current_user} do
328 ActivityBuilder.insert_list(30, %{"to" => [User.ap_followers(user)]}, %{user: user})
330 returned_activities =
331 ActivityBuilder.insert_list(10, %{"to" => [User.ap_followers(user)]}, %{user: user})
333 other_user = insert(:user)
334 ActivityBuilder.insert_list(10, %{}, %{user: other_user})
335 since_id = List.last(activities).id
338 Changeset.change(current_user, following: [User.ap_followers(user)])
343 |> with_credentials(current_user.nickname, "test")
344 |> get("/api/statuses/friends_timeline.json", %{since_id: since_id})
346 response = json_response(conn, 200)
348 assert length(response) == 10
351 Enum.map(returned_activities, fn activity ->
352 ActivityRepresenter.to_map(activity, %{
353 user: User.get_cached_by_ap_id(activity.data["actor"]),
360 describe "GET /statuses/dm_timeline.json" do
361 test "it show direct messages", %{conn: conn} do
362 user_one = insert(:user)
363 user_two = insert(:user)
365 {:ok, user_two} = User.follow(user_two, user_one)
368 CommonAPI.post(user_one, %{
369 "status" => "Hi @#{user_two.nickname}!",
370 "visibility" => "direct"
374 CommonAPI.post(user_two, %{
375 "status" => "Hi @#{user_one.nickname}!",
376 "visibility" => "direct"
379 {:ok, _follower_only} =
380 CommonAPI.post(user_one, %{
381 "status" => "Hi @#{user_two.nickname}!",
382 "visibility" => "private"
385 # Only direct should be visible here
388 |> assign(:user, user_two)
389 |> get("/api/statuses/dm_timeline.json")
391 [status, status_two] = json_response(res_conn, 200)
392 assert status["id"] == direct_two.id
393 assert status_two["id"] == direct.id
397 describe "GET /statuses/mentions.json" do
400 test "without valid credentials", %{conn: conn} do
401 conn = get(conn, "/api/statuses/mentions.json")
402 assert json_response(conn, 403) == %{"error" => "Invalid credentials."}
405 test "with credentials", %{conn: conn, user: current_user} do
407 ActivityBuilder.insert(%{"to" => [current_user.ap_id]}, %{user: current_user})
411 |> with_credentials(current_user.nickname, "test")
412 |> get("/api/statuses/mentions.json")
414 response = json_response(conn, 200)
416 assert length(response) == 1
418 assert Enum.at(response, 0) ==
419 ActivityRepresenter.to_map(activity, %{
421 mentioned: [current_user]
426 describe "GET /api/qvitter/statuses/notifications.json" do
429 test "without valid credentials", %{conn: conn} do
430 conn = get(conn, "/api/qvitter/statuses/notifications.json")
431 assert json_response(conn, 403) == %{"error" => "Invalid credentials."}
434 test "with credentials", %{conn: conn, user: current_user} do
435 other_user = insert(:user)
438 ActivityBuilder.insert(%{"to" => [current_user.ap_id]}, %{user: other_user})
442 |> with_credentials(current_user.nickname, "test")
443 |> get("/api/qvitter/statuses/notifications.json")
445 response = json_response(conn, 200)
447 assert length(response) == 1
450 NotificationView.render("notification.json", %{
451 notifications: Notification.for_user(current_user),
457 describe "POST /api/qvitter/statuses/notifications/read" do
460 test "without valid credentials", %{conn: conn} do
461 conn = post(conn, "/api/qvitter/statuses/notifications/read", %{"latest_id" => 1_234_567})
462 assert json_response(conn, 403) == %{"error" => "Invalid credentials."}
465 test "with credentials, without any params", %{conn: conn, user: current_user} do
468 |> with_credentials(current_user.nickname, "test")
469 |> post("/api/qvitter/statuses/notifications/read")
471 assert json_response(conn, 400) == %{
472 "error" => "You need to specify latest_id",
473 "request" => "/api/qvitter/statuses/notifications/read"
477 test "with credentials, with params", %{conn: conn, user: current_user} do
478 other_user = insert(:user)
481 ActivityBuilder.insert(%{"to" => [current_user.ap_id]}, %{user: other_user})
485 |> with_credentials(current_user.nickname, "test")
486 |> get("/api/qvitter/statuses/notifications.json")
488 [notification] = response = json_response(response_conn, 200)
490 assert length(response) == 1
492 assert notification["is_seen"] == 0
496 |> with_credentials(current_user.nickname, "test")
497 |> post("/api/qvitter/statuses/notifications/read", %{"latest_id" => notification["id"]})
499 [notification] = response = json_response(response_conn, 200)
501 assert length(response) == 1
503 assert notification["is_seen"] == 1
507 describe "GET /statuses/user_timeline.json" do
510 test "without any params", %{conn: conn} do
511 conn = get(conn, "/api/statuses/user_timeline.json")
513 assert json_response(conn, 400) == %{
514 "error" => "You need to specify screen_name or user_id",
515 "request" => "/api/statuses/user_timeline.json"
519 test "with user_id", %{conn: conn} do
521 {:ok, activity} = ActivityBuilder.insert(%{"id" => 1}, %{user: user})
523 conn = get(conn, "/api/statuses/user_timeline.json", %{"user_id" => user.id})
524 response = json_response(conn, 200)
525 assert length(response) == 1
526 assert Enum.at(response, 0) == ActivityRepresenter.to_map(activity, %{user: user})
529 test "with screen_name", %{conn: conn} do
531 {:ok, activity} = ActivityBuilder.insert(%{"id" => 1}, %{user: user})
533 conn = get(conn, "/api/statuses/user_timeline.json", %{"screen_name" => user.nickname})
534 response = json_response(conn, 200)
535 assert length(response) == 1
536 assert Enum.at(response, 0) == ActivityRepresenter.to_map(activity, %{user: user})
539 test "with credentials", %{conn: conn, user: current_user} do
540 {:ok, activity} = ActivityBuilder.insert(%{"id" => 1}, %{user: current_user})
544 |> with_credentials(current_user.nickname, "test")
545 |> get("/api/statuses/user_timeline.json")
547 response = json_response(conn, 200)
549 assert length(response) == 1
550 assert Enum.at(response, 0) == ActivityRepresenter.to_map(activity, %{user: current_user})
553 test "with credentials with user_id", %{conn: conn, user: current_user} do
555 {:ok, activity} = ActivityBuilder.insert(%{"id" => 1}, %{user: user})
559 |> with_credentials(current_user.nickname, "test")
560 |> get("/api/statuses/user_timeline.json", %{"user_id" => user.id})
562 response = json_response(conn, 200)
564 assert length(response) == 1
565 assert Enum.at(response, 0) == ActivityRepresenter.to_map(activity, %{user: user})
568 test "with credentials screen_name", %{conn: conn, user: current_user} do
570 {:ok, activity} = ActivityBuilder.insert(%{"id" => 1}, %{user: user})
574 |> with_credentials(current_user.nickname, "test")
575 |> get("/api/statuses/user_timeline.json", %{"screen_name" => user.nickname})
577 response = json_response(conn, 200)
579 assert length(response) == 1
580 assert Enum.at(response, 0) == ActivityRepresenter.to_map(activity, %{user: user})
583 test "with credentials with user_id, excluding RTs", %{conn: conn, user: current_user} do
585 {:ok, activity} = ActivityBuilder.insert(%{"id" => 1, "type" => "Create"}, %{user: user})
586 {:ok, _} = ActivityBuilder.insert(%{"id" => 2, "type" => "Announce"}, %{user: user})
590 |> with_credentials(current_user.nickname, "test")
591 |> get("/api/statuses/user_timeline.json", %{
592 "user_id" => user.id,
593 "include_rts" => "false"
596 response = json_response(conn, 200)
598 assert length(response) == 1
599 assert Enum.at(response, 0) == ActivityRepresenter.to_map(activity, %{user: user})
603 |> get("/api/statuses/user_timeline.json", %{"user_id" => user.id, "include_rts" => "0"})
605 response = json_response(conn, 200)
607 assert length(response) == 1
608 assert Enum.at(response, 0) == ActivityRepresenter.to_map(activity, %{user: user})
612 describe "POST /friendships/create.json" do
615 test "without valid credentials", %{conn: conn} do
616 conn = post(conn, "/api/friendships/create.json")
617 assert json_response(conn, 403) == %{"error" => "Invalid credentials."}
620 test "with credentials", %{conn: conn, user: current_user} do
621 followed = insert(:user)
625 |> with_credentials(current_user.nickname, "test")
626 |> post("/api/friendships/create.json", %{user_id: followed.id})
628 current_user = Repo.get(User, current_user.id)
629 assert User.ap_followers(followed) in current_user.following
631 assert json_response(conn, 200) ==
632 UserView.render("show.json", %{user: followed, for: current_user})
636 describe "POST /friendships/destroy.json" do
639 test "without valid credentials", %{conn: conn} do
640 conn = post(conn, "/api/friendships/destroy.json")
641 assert json_response(conn, 403) == %{"error" => "Invalid credentials."}
644 test "with credentials", %{conn: conn, user: current_user} do
645 followed = insert(:user)
647 {:ok, current_user} = User.follow(current_user, followed)
648 assert User.ap_followers(followed) in current_user.following
649 ActivityPub.follow(current_user, followed)
653 |> with_credentials(current_user.nickname, "test")
654 |> post("/api/friendships/destroy.json", %{user_id: followed.id})
656 current_user = Repo.get(User, current_user.id)
657 assert current_user.following == [current_user.ap_id]
659 assert json_response(conn, 200) ==
660 UserView.render("show.json", %{user: followed, for: current_user})
664 describe "POST /blocks/create.json" do
667 test "without valid credentials", %{conn: conn} do
668 conn = post(conn, "/api/blocks/create.json")
669 assert json_response(conn, 403) == %{"error" => "Invalid credentials."}
672 test "with credentials", %{conn: conn, user: current_user} do
673 blocked = insert(:user)
677 |> with_credentials(current_user.nickname, "test")
678 |> post("/api/blocks/create.json", %{user_id: blocked.id})
680 current_user = Repo.get(User, current_user.id)
681 assert User.blocks?(current_user, blocked)
683 assert json_response(conn, 200) ==
684 UserView.render("show.json", %{user: blocked, for: current_user})
688 describe "POST /blocks/destroy.json" do
691 test "without valid credentials", %{conn: conn} do
692 conn = post(conn, "/api/blocks/destroy.json")
693 assert json_response(conn, 403) == %{"error" => "Invalid credentials."}
696 test "with credentials", %{conn: conn, user: current_user} do
697 blocked = insert(:user)
699 {:ok, current_user, blocked} = TwitterAPI.block(current_user, %{"user_id" => blocked.id})
700 assert User.blocks?(current_user, blocked)
704 |> with_credentials(current_user.nickname, "test")
705 |> post("/api/blocks/destroy.json", %{user_id: blocked.id})
707 current_user = Repo.get(User, current_user.id)
708 assert current_user.info.blocks == []
710 assert json_response(conn, 200) ==
711 UserView.render("show.json", %{user: blocked, for: current_user})
715 describe "GET /help/test.json" do
716 test "returns \"ok\"", %{conn: conn} do
717 conn = get(conn, "/api/help/test.json")
718 assert json_response(conn, 200) == "ok"
722 describe "POST /api/qvitter/update_avatar.json" do
725 test "without valid credentials", %{conn: conn} do
726 conn = post(conn, "/api/qvitter/update_avatar.json")
727 assert json_response(conn, 403) == %{"error" => "Invalid credentials."}
730 test "with credentials", %{conn: conn, user: current_user} do
731 avatar_image = File.read!("test/fixtures/avatar_data_uri")
735 |> with_credentials(current_user.nickname, "test")
736 |> post("/api/qvitter/update_avatar.json", %{img: avatar_image})
738 current_user = Repo.get(User, current_user.id)
739 assert is_map(current_user.avatar)
741 assert json_response(conn, 200) ==
742 UserView.render("show.json", %{user: current_user, for: current_user})
746 describe "GET /api/qvitter/mutes.json" do
749 test "unimplemented mutes without valid credentials", %{conn: conn} do
750 conn = get(conn, "/api/qvitter/mutes.json")
751 assert json_response(conn, 403) == %{"error" => "Invalid credentials."}
754 test "unimplemented mutes with credentials", %{conn: conn, user: current_user} do
757 |> with_credentials(current_user.nickname, "test")
758 |> get("/api/qvitter/mutes.json")
759 |> json_response(200)
765 describe "POST /api/favorites/create/:id" do
768 test "without valid credentials", %{conn: conn} do
769 note_activity = insert(:note_activity)
770 conn = post(conn, "/api/favorites/create/#{note_activity.id}.json")
771 assert json_response(conn, 403) == %{"error" => "Invalid credentials."}
774 test "with credentials", %{conn: conn, user: current_user} do
775 note_activity = insert(:note_activity)
779 |> with_credentials(current_user.nickname, "test")
780 |> post("/api/favorites/create/#{note_activity.id}.json")
782 assert json_response(conn, 200)
785 test "with credentials, invalid param", %{conn: conn, user: current_user} do
788 |> with_credentials(current_user.nickname, "test")
789 |> post("/api/favorites/create/wrong.json")
791 assert json_response(conn, 400)
794 test "with credentials, invalid activity", %{conn: conn, user: current_user} do
797 |> with_credentials(current_user.nickname, "test")
798 |> post("/api/favorites/create/1.json")
800 assert json_response(conn, 500)
804 describe "POST /api/favorites/destroy/:id" do
807 test "without valid credentials", %{conn: conn} do
808 note_activity = insert(:note_activity)
809 conn = post(conn, "/api/favorites/destroy/#{note_activity.id}.json")
810 assert json_response(conn, 403) == %{"error" => "Invalid credentials."}
813 test "with credentials", %{conn: conn, user: current_user} do
814 note_activity = insert(:note_activity)
815 object = Object.get_by_ap_id(note_activity.data["object"]["id"])
816 ActivityPub.like(current_user, object)
820 |> with_credentials(current_user.nickname, "test")
821 |> post("/api/favorites/destroy/#{note_activity.id}.json")
823 assert json_response(conn, 200)
827 describe "POST /api/statuses/retweet/:id" do
830 test "without valid credentials", %{conn: conn} do
831 note_activity = insert(:note_activity)
832 conn = post(conn, "/api/statuses/retweet/#{note_activity.id}.json")
833 assert json_response(conn, 403) == %{"error" => "Invalid credentials."}
836 test "with credentials", %{conn: conn, user: current_user} do
837 note_activity = insert(:note_activity)
839 request_path = "/api/statuses/retweet/#{note_activity.id}.json"
843 |> with_credentials(current_user.nickname, "test")
844 |> post(request_path)
846 activity = Repo.get(Activity, note_activity.id)
847 activity_user = Repo.get_by(User, ap_id: note_activity.data["actor"])
849 assert json_response(response, 200) ==
850 ActivityRepresenter.to_map(activity, %{user: activity_user, for: current_user})
854 describe "POST /api/statuses/unretweet/:id" do
857 test "without valid credentials", %{conn: conn} do
858 note_activity = insert(:note_activity)
859 conn = post(conn, "/api/statuses/unretweet/#{note_activity.id}.json")
860 assert json_response(conn, 403) == %{"error" => "Invalid credentials."}
863 test "with credentials", %{conn: conn, user: current_user} do
864 note_activity = insert(:note_activity)
866 request_path = "/api/statuses/retweet/#{note_activity.id}.json"
870 |> with_credentials(current_user.nickname, "test")
871 |> post(request_path)
873 request_path = String.replace(request_path, "retweet", "unretweet")
877 |> with_credentials(current_user.nickname, "test")
878 |> post(request_path)
880 activity = Repo.get(Activity, note_activity.id)
881 activity_user = Repo.get_by(User, ap_id: note_activity.data["actor"])
883 assert json_response(response, 200) ==
884 ActivityRepresenter.to_map(activity, %{user: activity_user, for: current_user})
888 describe "POST /api/account/register" do
889 test "it creates a new user", %{conn: conn} do
891 "nickname" => "lain",
892 "email" => "lain@wired.jp",
893 "fullname" => "lain iwakura",
894 "bio" => "close the world.",
895 "password" => "bear",
901 |> post("/api/account/register", data)
903 user = json_response(conn, 200)
905 fetched_user = Repo.get_by(User, nickname: "lain")
906 assert user == UserView.render("show.json", %{user: fetched_user})
909 test "it returns errors on a problem", %{conn: conn} do
911 "email" => "lain@wired.jp",
912 "fullname" => "lain iwakura",
913 "bio" => "close the world.",
914 "password" => "bear",
920 |> post("/api/account/register", data)
922 errors = json_response(conn, 400)
924 assert is_binary(errors["error"])
928 describe "POST /api/account/password_reset, with valid parameters" do
929 setup %{conn: conn} do
931 conn = post(conn, "/api/account/password_reset?email=#{user.email}")
932 %{conn: conn, user: user}
935 test "it returns 204", %{conn: conn} do
936 assert json_response(conn, :no_content)
939 test "it creates a PasswordResetToken record for user", %{user: user} do
940 token_record = Repo.get_by(Pleroma.PasswordResetToken, user_id: user.id)
944 test "it sends an email to user", %{user: user} do
945 token_record = Repo.get_by(Pleroma.PasswordResetToken, user_id: user.id)
947 Swoosh.TestAssertions.assert_email_sent(
948 Pleroma.UserEmail.password_reset_email(user, token_record.token)
953 describe "POST /api/account/password_reset, with invalid parameters" do
956 test "it returns 500 when user is not found", %{conn: conn, user: user} do
957 conn = post(conn, "/api/account/password_reset?email=nonexisting_#{user.email}")
958 assert json_response(conn, :internal_server_error)
961 test "it returns 500 when user is not local", %{conn: conn, user: user} do
962 {:ok, user} = Repo.update(Changeset.change(user, local: false))
963 conn = post(conn, "/api/account/password_reset?email=#{user.email}")
964 assert json_response(conn, :internal_server_error)
968 describe "GET /api/account/confirm_email/:id/:token" do
971 info_change = User.Info.confirmation_changeset(user.info, :unconfirmed)
975 |> Changeset.change()
976 |> Changeset.put_embed(:info, info_change)
979 assert user.info.confirmation_pending
984 test "it redirects to root url", %{conn: conn, user: user} do
985 conn = get(conn, "/api/account/confirm_email/#{user.id}/#{user.info.confirmation_token}")
987 assert 302 == conn.status
990 test "it confirms the user account", %{conn: conn, user: user} do
991 get(conn, "/api/account/confirm_email/#{user.id}/#{user.info.confirmation_token}")
993 user = Repo.get(User, user.id)
995 refute user.info.confirmation_pending
996 refute user.info.confirmation_token
999 test "it returns 500 if user cannot be found by id", %{conn: conn, user: user} do
1000 conn = get(conn, "/api/account/confirm_email/0/#{user.info.confirmation_token}")
1002 assert 500 == conn.status
1005 test "it returns 500 if token is invalid", %{conn: conn, user: user} do
1006 conn = get(conn, "/api/account/confirm_email/#{user.id}/wrong_token")
1008 assert 500 == conn.status
1012 describe "POST /api/account/resend_confirmation_email" do
1014 setting = Pleroma.Config.get([:instance, :account_activation_required])
1017 Pleroma.Config.put([:instance, :account_activation_required], true)
1018 on_exit(fn -> Pleroma.Config.put([:instance, :account_activation_required], setting) end)
1021 user = insert(:user)
1022 info_change = User.Info.confirmation_changeset(user.info, :unconfirmed)
1026 |> Changeset.change()
1027 |> Changeset.put_embed(:info, info_change)
1030 assert user.info.confirmation_pending
1035 test "it returns 204 No Content", %{conn: conn, user: user} do
1037 |> assign(:user, user)
1038 |> post("/api/account/resend_confirmation_email?email=#{user.email}")
1039 |> json_response(:no_content)
1042 test "it sends confirmation email", %{conn: conn, user: user} do
1044 |> assign(:user, user)
1045 |> post("/api/account/resend_confirmation_email?email=#{user.email}")
1047 Swoosh.TestAssertions.assert_email_sent(Pleroma.UserEmail.account_confirmation_email(user))
1051 describe "GET /api/externalprofile/show" do
1052 test "it returns the user", %{conn: conn} do
1053 user = insert(:user)
1054 other_user = insert(:user)
1058 |> assign(:user, user)
1059 |> get("/api/externalprofile/show", %{profileurl: other_user.ap_id})
1061 assert json_response(conn, 200) == UserView.render("show.json", %{user: other_user})
1065 describe "GET /api/statuses/followers" do
1066 test "it returns a user's followers", %{conn: conn} do
1067 user = insert(:user)
1068 follower_one = insert(:user)
1069 follower_two = insert(:user)
1070 _not_follower = insert(:user)
1072 {:ok, follower_one} = User.follow(follower_one, user)
1073 {:ok, follower_two} = User.follow(follower_two, user)
1077 |> assign(:user, user)
1078 |> get("/api/statuses/followers")
1080 expected = UserView.render("index.json", %{users: [follower_one, follower_two], for: user})
1081 result = json_response(conn, 200)
1082 assert Enum.sort(expected) == Enum.sort(result)
1085 test "it returns a given user's followers with user_id", %{conn: conn} do
1086 user = insert(:user)
1087 follower_one = insert(:user)
1088 follower_two = insert(:user)
1089 not_follower = insert(:user)
1091 {:ok, follower_one} = User.follow(follower_one, user)
1092 {:ok, follower_two} = User.follow(follower_two, user)
1096 |> assign(:user, not_follower)
1097 |> get("/api/statuses/followers", %{"user_id" => user.id})
1099 assert MapSet.equal?(
1100 MapSet.new(json_response(conn, 200)),
1102 UserView.render("index.json", %{
1103 users: [follower_one, follower_two],
1110 test "it returns empty for a hidden network", %{conn: conn} do
1111 user = insert(:user, %{info: %{hide_network: true}})
1112 follower_one = insert(:user)
1113 follower_two = insert(:user)
1114 not_follower = insert(:user)
1116 {:ok, _follower_one} = User.follow(follower_one, user)
1117 {:ok, _follower_two} = User.follow(follower_two, user)
1121 |> assign(:user, not_follower)
1122 |> get("/api/statuses/followers", %{"user_id" => user.id})
1123 |> json_response(200)
1125 assert [] == response
1128 test "it returns the followers for a hidden network if requested by the user themselves", %{
1131 user = insert(:user, %{info: %{hide_network: true}})
1132 follower_one = insert(:user)
1133 follower_two = insert(:user)
1134 _not_follower = insert(:user)
1136 {:ok, _follower_one} = User.follow(follower_one, user)
1137 {:ok, _follower_two} = User.follow(follower_two, user)
1141 |> assign(:user, user)
1142 |> get("/api/statuses/followers", %{"user_id" => user.id})
1144 refute [] == json_response(conn, 200)
1148 describe "GET /api/statuses/blocks" do
1149 test "it returns the list of users blocked by requester", %{conn: conn} do
1150 user = insert(:user)
1151 other_user = insert(:user)
1153 {:ok, user} = User.block(user, other_user)
1157 |> assign(:user, user)
1158 |> get("/api/statuses/blocks")
1160 expected = UserView.render("index.json", %{users: [other_user], for: user})
1161 result = json_response(conn, 200)
1162 assert Enum.sort(expected) == Enum.sort(result)
1166 describe "GET /api/statuses/friends" do
1167 test "it returns the logged in user's friends", %{conn: conn} do
1168 user = insert(:user)
1169 followed_one = insert(:user)
1170 followed_two = insert(:user)
1171 _not_followed = insert(:user)
1173 {:ok, user} = User.follow(user, followed_one)
1174 {:ok, user} = User.follow(user, followed_two)
1178 |> assign(:user, user)
1179 |> get("/api/statuses/friends")
1181 expected = UserView.render("index.json", %{users: [followed_one, followed_two], for: user})
1182 result = json_response(conn, 200)
1183 assert Enum.sort(expected) == Enum.sort(result)
1186 test "it returns a given user's friends with user_id", %{conn: conn} do
1187 user = insert(:user)
1188 followed_one = insert(:user)
1189 followed_two = insert(:user)
1190 _not_followed = insert(:user)
1192 {:ok, user} = User.follow(user, followed_one)
1193 {:ok, user} = User.follow(user, followed_two)
1197 |> assign(:user, user)
1198 |> get("/api/statuses/friends", %{"user_id" => user.id})
1200 assert MapSet.equal?(
1201 MapSet.new(json_response(conn, 200)),
1203 UserView.render("index.json", %{users: [followed_one, followed_two], for: user})
1208 test "it returns empty for a hidden network", %{conn: conn} do
1209 user = insert(:user, %{info: %{hide_network: true}})
1210 followed_one = insert(:user)
1211 followed_two = insert(:user)
1212 not_followed = insert(:user)
1214 {:ok, user} = User.follow(user, followed_one)
1215 {:ok, user} = User.follow(user, followed_two)
1219 |> assign(:user, not_followed)
1220 |> get("/api/statuses/friends", %{"user_id" => user.id})
1222 assert [] == json_response(conn, 200)
1225 test "it returns friends for a hidden network if the user themselves request it", %{
1228 user = insert(:user, %{info: %{hide_network: true}})
1229 followed_one = insert(:user)
1230 followed_two = insert(:user)
1231 _not_followed = insert(:user)
1233 {:ok, _user} = User.follow(user, followed_one)
1234 {:ok, _user} = User.follow(user, followed_two)
1238 |> assign(:user, user)
1239 |> get("/api/statuses/friends", %{"user_id" => user.id})
1240 |> json_response(200)
1242 refute [] == response
1245 test "it returns a given user's friends with screen_name", %{conn: conn} do
1246 user = insert(:user)
1247 followed_one = insert(:user)
1248 followed_two = insert(:user)
1249 _not_followed = insert(:user)
1251 {:ok, user} = User.follow(user, followed_one)
1252 {:ok, user} = User.follow(user, followed_two)
1256 |> assign(:user, user)
1257 |> get("/api/statuses/friends", %{"screen_name" => user.nickname})
1259 assert MapSet.equal?(
1260 MapSet.new(json_response(conn, 200)),
1262 UserView.render("index.json", %{users: [followed_one, followed_two], for: user})
1268 describe "GET /friends/ids" do
1269 test "it returns a user's friends", %{conn: conn} do
1270 user = insert(:user)
1271 followed_one = insert(:user)
1272 followed_two = insert(:user)
1273 _not_followed = insert(:user)
1275 {:ok, user} = User.follow(user, followed_one)
1276 {:ok, user} = User.follow(user, followed_two)
1280 |> assign(:user, user)
1281 |> get("/api/friends/ids")
1283 expected = [followed_one.id, followed_two.id]
1285 assert MapSet.equal?(
1286 MapSet.new(Poison.decode!(json_response(conn, 200))),
1287 MapSet.new(expected)
1292 describe "POST /api/account/update_profile.json" do
1293 test "it updates a user's profile", %{conn: conn} do
1294 user = insert(:user)
1295 user2 = insert(:user)
1299 |> assign(:user, user)
1300 |> post("/api/account/update_profile.json", %{
1301 "name" => "new name",
1302 "description" => "hi @#{user2.nickname}"
1305 user = Repo.get!(User, user.id)
1306 assert user.name == "new name"
1309 "hi <span><a data-user='#{user2.id}' class='mention' href='#{user2.ap_id}'>@<span>#{
1311 }</span></a></span>"
1313 assert json_response(conn, 200) == UserView.render("user.json", %{user: user, for: user})
1316 test "it sets and un-sets hide_network", %{conn: conn} do
1317 user = insert(:user)
1320 |> assign(:user, user)
1321 |> post("/api/account/update_profile.json", %{
1322 "hide_network" => "true"
1325 user = Repo.get!(User, user.id)
1326 assert user.info.hide_network == true
1330 |> assign(:user, user)
1331 |> post("/api/account/update_profile.json", %{
1332 "hide_network" => "false"
1335 user = Repo.get!(User, user.id)
1336 assert user.info.hide_network == false
1337 assert json_response(conn, 200) == UserView.render("user.json", %{user: user, for: user})
1340 test "it locks an account", %{conn: conn} do
1341 user = insert(:user)
1345 |> assign(:user, user)
1346 |> post("/api/account/update_profile.json", %{
1350 user = Repo.get!(User, user.id)
1351 assert user.info.locked == true
1353 assert json_response(conn, 200) == UserView.render("user.json", %{user: user, for: user})
1356 test "it unlocks an account", %{conn: conn} do
1357 user = insert(:user)
1361 |> assign(:user, user)
1362 |> post("/api/account/update_profile.json", %{
1366 user = Repo.get!(User, user.id)
1367 assert user.info.locked == false
1369 assert json_response(conn, 200) == UserView.render("user.json", %{user: user, for: user})
1373 defp valid_user(_context) do
1374 user = insert(:user)
1378 defp with_credentials(conn, username, password) do
1379 header_content = "Basic " <> Base.encode64("#{username}:#{password}")
1380 put_req_header(conn, "authorization", header_content)
1383 describe "GET /api/search.json" do
1384 test "it returns search results", %{conn: conn} do
1385 user = insert(:user)
1386 user_two = insert(:user, %{nickname: "shp@shitposter.club"})
1388 {:ok, activity} = CommonAPI.post(user, %{"status" => "This is about 2hu"})
1389 {:ok, _} = CommonAPI.post(user_two, %{"status" => "This isn't"})
1393 |> get("/api/search.json", %{"q" => "2hu", "page" => "1", "rpp" => "1"})
1395 assert [status] = json_response(conn, 200)
1396 assert status["id"] == activity.id
1400 describe "GET /api/statusnet/tags/timeline/:tag.json" do
1401 test "it returns the tags timeline", %{conn: conn} do
1402 user = insert(:user)
1403 user_two = insert(:user, %{nickname: "shp@shitposter.club"})
1405 {:ok, activity} = CommonAPI.post(user, %{"status" => "This is about #2hu"})
1406 {:ok, _} = CommonAPI.post(user_two, %{"status" => "This isn't"})
1410 |> get("/api/statusnet/tags/timeline/2hu.json")
1412 assert [status] = json_response(conn, 200)
1413 assert status["id"] == activity.id
1417 test "Convert newlines to <br> in bio", %{conn: conn} do
1418 user = insert(:user)
1422 |> assign(:user, user)
1423 |> post("/api/account/update_profile.json", %{
1424 "description" => "Hello,\r\nWorld! I\n am a test."
1427 user = Repo.get!(User, user.id)
1428 assert user.bio == "Hello,<br>World! I<br> am a test."
1431 describe "POST /api/pleroma/change_password" do
1434 test "without credentials", %{conn: conn} do
1435 conn = post(conn, "/api/pleroma/change_password")
1436 assert json_response(conn, 403) == %{"error" => "Invalid credentials."}
1439 test "with credentials and invalid password", %{conn: conn, user: current_user} do
1442 |> with_credentials(current_user.nickname, "test")
1443 |> post("/api/pleroma/change_password", %{
1445 "new_password" => "newpass",
1446 "new_password_confirmation" => "newpass"
1449 assert json_response(conn, 200) == %{"error" => "Invalid password."}
1452 test "with credentials, valid password and new password and confirmation not matching", %{
1458 |> with_credentials(current_user.nickname, "test")
1459 |> post("/api/pleroma/change_password", %{
1460 "password" => "test",
1461 "new_password" => "newpass",
1462 "new_password_confirmation" => "notnewpass"
1465 assert json_response(conn, 200) == %{
1466 "error" => "New password does not match confirmation."
1470 test "with credentials, valid password and invalid new password", %{
1476 |> with_credentials(current_user.nickname, "test")
1477 |> post("/api/pleroma/change_password", %{
1478 "password" => "test",
1479 "new_password" => "",
1480 "new_password_confirmation" => ""
1483 assert json_response(conn, 200) == %{
1484 "error" => "New password can't be blank."
1488 test "with credentials, valid password and matching new password and confirmation", %{
1494 |> with_credentials(current_user.nickname, "test")
1495 |> post("/api/pleroma/change_password", %{
1496 "password" => "test",
1497 "new_password" => "newpass",
1498 "new_password_confirmation" => "newpass"
1501 assert json_response(conn, 200) == %{"status" => "success"}
1502 fetched_user = Repo.get(User, current_user.id)
1503 assert Pbkdf2.checkpw("newpass", fetched_user.password_hash) == true
1507 describe "POST /api/pleroma/delete_account" do
1510 test "without credentials", %{conn: conn} do
1511 conn = post(conn, "/api/pleroma/delete_account")
1512 assert json_response(conn, 403) == %{"error" => "Invalid credentials."}
1515 test "with credentials and invalid password", %{conn: conn, user: current_user} do
1518 |> with_credentials(current_user.nickname, "test")
1519 |> post("/api/pleroma/delete_account", %{"password" => "hi"})
1521 assert json_response(conn, 200) == %{"error" => "Invalid password."}
1524 test "with credentials and valid password", %{conn: conn, user: current_user} do
1527 |> with_credentials(current_user.nickname, "test")
1528 |> post("/api/pleroma/delete_account", %{"password" => "test"})
1530 assert json_response(conn, 200) == %{"status" => "success"}
1531 # Wait a second for the started task to end
1536 describe "GET /api/pleroma/friend_requests" do
1537 test "it lists friend requests" do
1538 user = insert(:user)
1539 other_user = insert(:user)
1541 {:ok, _activity} = ActivityPub.follow(other_user, user)
1543 user = Repo.get(User, user.id)
1544 other_user = Repo.get(User, other_user.id)
1546 assert User.following?(other_user, user) == false
1550 |> assign(:user, user)
1551 |> get("/api/pleroma/friend_requests")
1553 assert [relationship] = json_response(conn, 200)
1554 assert other_user.id == relationship["id"]
1558 describe "POST /api/pleroma/friendships/approve" do
1559 test "it approves a friend request" do
1560 user = insert(:user)
1561 other_user = insert(:user)
1563 {:ok, _activity} = ActivityPub.follow(other_user, user)
1565 user = Repo.get(User, user.id)
1566 other_user = Repo.get(User, other_user.id)
1568 assert User.following?(other_user, user) == false
1572 |> assign(:user, user)
1573 |> post("/api/pleroma/friendships/approve", %{"user_id" => to_string(other_user.id)})
1575 assert relationship = json_response(conn, 200)
1576 assert other_user.id == relationship["id"]
1577 assert relationship["follows_you"] == true
1581 describe "POST /api/pleroma/friendships/deny" do
1582 test "it denies a friend request" do
1583 user = insert(:user)
1584 other_user = insert(:user)
1586 {:ok, _activity} = ActivityPub.follow(other_user, user)
1588 user = Repo.get(User, user.id)
1589 other_user = Repo.get(User, other_user.id)
1591 assert User.following?(other_user, user) == false
1595 |> assign(:user, user)
1596 |> post("/api/pleroma/friendships/deny", %{"user_id" => to_string(other_user.id)})
1598 assert relationship = json_response(conn, 200)
1599 assert other_user.id == relationship["id"]
1600 assert relationship["follows_you"] == false
1604 describe "GET /api/pleroma/search_user" do
1605 test "it returns users, ordered by similarity", %{conn: conn} do
1606 user = insert(:user, %{name: "eal"})
1607 user_two = insert(:user, %{name: "ean"})
1608 user_three = insert(:user, %{name: "ebn"})
1612 |> get(twitter_api_search__path(conn, :search_user), query: "eal")
1613 |> json_response(200)
1615 assert length(resp) == 3
1616 assert [user.id, user_two.id, user_three.id] == Enum.map(resp, fn %{"id" => id} -> id end)
1620 describe "POST /api/media/upload" do
1622 Pleroma.DataCase.ensure_local_uploader(context)
1625 test "it performs the upload and sets `data[actor]` with AP id of uploader user", %{
1628 user = insert(:user)
1630 upload_filename = "test/fixtures/image_tmp.jpg"
1631 File.cp!("test/fixtures/image.jpg", upload_filename)
1633 file = %Plug.Upload{
1634 content_type: "image/jpg",
1635 path: Path.absname(upload_filename),
1636 filename: "image.jpg"
1641 |> assign(:user, user)
1642 |> put_req_header("content-type", "application/octet-stream")
1643 |> post("/api/media/upload", %{
1646 |> json_response(:ok)
1648 assert response["media_id"]
1649 object = Repo.get(Object, response["media_id"])
1651 assert object.data["actor"] == User.ap_id(user)
1655 describe "POST /api/media/metadata/create" do
1657 object = insert(:note)
1658 user = User.get_by_ap_id(object.data["actor"])
1659 %{object: object, user: user}
1662 test "it returns :forbidden status on attempt to modify someone else's upload", %{
1666 initial_description = object.data["name"]
1667 another_user = insert(:user)
1670 |> assign(:user, another_user)
1671 |> post("/api/media/metadata/create", %{"media_id" => object.id})
1672 |> json_response(:forbidden)
1674 object = Repo.get(Object, object.id)
1675 assert object.data["name"] == initial_description
1678 test "it updates `data[name]` of referenced Object with provided value", %{
1683 description = "Informative description of the image. Initial value: #{object.data["name"]}}"
1686 |> assign(:user, user)
1687 |> post("/api/media/metadata/create", %{
1688 "media_id" => object.id,
1689 "alt_text" => %{"text" => description}
1691 |> json_response(:no_content)
1693 object = Repo.get(Object, object.id)
1694 assert object.data["name"] == description