1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
5 defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
6 use Pleroma.Web.ConnCase
10 alias Pleroma.Notification
14 alias Pleroma.Web.ActivityPub.ActivityPub
15 alias Pleroma.Web.CommonAPI
16 alias Pleroma.Web.MastodonAPI.FilterView
17 alias Pleroma.Web.OAuth.App
18 alias Pleroma.Web.OStatus
19 alias Pleroma.Web.Push
20 alias Pleroma.Web.TwitterAPI.TwitterAPI
21 import Pleroma.Factory
22 import ExUnit.CaptureLog
26 mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
30 test "the home timeline", %{conn: conn} do
32 following = insert(:user)
34 {:ok, _activity} = TwitterAPI.create_status(following, %{"status" => "test"})
38 |> assign(:user, user)
39 |> get("/api/v1/timelines/home")
41 assert Enum.empty?(json_response(conn, 200))
43 {:ok, user} = User.follow(user, following)
47 |> assign(:user, user)
48 |> get("/api/v1/timelines/home")
50 assert [%{"content" => "test"}] = json_response(conn, 200)
53 test "the public timeline", %{conn: conn} do
54 following = insert(:user)
57 {:ok, _activity} = TwitterAPI.create_status(following, %{"status" => "test"})
60 OStatus.fetch_activity_from_url("https://shitposter.club/notice/2827873")
64 |> get("/api/v1/timelines/public", %{"local" => "False"})
66 assert length(json_response(conn, 200)) == 2
70 |> get("/api/v1/timelines/public", %{"local" => "True"})
72 assert [%{"content" => "test"}] = json_response(conn, 200)
76 |> get("/api/v1/timelines/public", %{"local" => "1"})
78 assert [%{"content" => "test"}] = json_response(conn, 200)
82 test "posting a status", %{conn: conn} do
85 idempotency_key = "Pikachu rocks!"
89 |> assign(:user, user)
90 |> put_req_header("idempotency-key", idempotency_key)
91 |> post("/api/v1/statuses", %{
93 "spoiler_text" => "2hu",
94 "sensitive" => "false"
97 {:ok, ttl} = Cachex.ttl(:idempotency_cache, idempotency_key)
99 assert ttl > :timer.seconds(6 * 60 * 60 - 1)
101 assert %{"content" => "cofe", "id" => id, "spoiler_text" => "2hu", "sensitive" => false} =
102 json_response(conn_one, 200)
104 assert Activity.get_by_id(id)
108 |> assign(:user, user)
109 |> put_req_header("idempotency-key", idempotency_key)
110 |> post("/api/v1/statuses", %{
112 "spoiler_text" => "2hu",
113 "sensitive" => "false"
116 assert %{"id" => second_id} = json_response(conn_two, 200)
118 assert id == second_id
122 |> assign(:user, user)
123 |> post("/api/v1/statuses", %{
125 "spoiler_text" => "2hu",
126 "sensitive" => "false"
129 assert %{"id" => third_id} = json_response(conn_three, 200)
131 refute id == third_id
134 test "posting a sensitive status", %{conn: conn} do
139 |> assign(:user, user)
140 |> post("/api/v1/statuses", %{"status" => "cofe", "sensitive" => true})
142 assert %{"content" => "cofe", "id" => id, "sensitive" => true} = json_response(conn, 200)
143 assert Activity.get_by_id(id)
146 test "posting a fake status", %{conn: conn} do
151 |> assign(:user, user)
152 |> post("/api/v1/statuses", %{
154 "\"Tenshi Eating a Corndog\" is a much discussed concept on /jp/. The significance of it is disputed, so I will focus on one core concept: the symbolism behind it"
157 real_status = json_response(real_conn, 200)
160 assert Object.get_by_ap_id(real_status["uri"])
164 |> Map.put("id", nil)
165 |> Map.put("url", nil)
166 |> Map.put("uri", nil)
167 |> Map.put("created_at", nil)
168 |> Kernel.put_in(["pleroma", "conversation_id"], nil)
172 |> assign(:user, user)
173 |> post("/api/v1/statuses", %{
175 "\"Tenshi Eating a Corndog\" is a much discussed concept on /jp/. The significance of it is disputed, so I will focus on one core concept: the symbolism behind it",
179 fake_status = json_response(fake_conn, 200)
182 refute Object.get_by_ap_id(fake_status["uri"])
186 |> Map.put("id", nil)
187 |> Map.put("url", nil)
188 |> Map.put("uri", nil)
189 |> Map.put("created_at", nil)
190 |> Kernel.put_in(["pleroma", "conversation_id"], nil)
192 assert real_status == fake_status
195 test "posting a status with OGP link preview", %{conn: conn} do
196 Pleroma.Config.put([:rich_media, :enabled], true)
201 |> assign(:user, user)
202 |> post("/api/v1/statuses", %{
203 "status" => "http://example.com/ogp"
206 assert %{"id" => id, "card" => %{"title" => "The Rock"}} = json_response(conn, 200)
207 assert Activity.get_by_id(id)
208 Pleroma.Config.put([:rich_media, :enabled], false)
211 test "posting a direct status", %{conn: conn} do
212 user1 = insert(:user)
213 user2 = insert(:user)
214 content = "direct cofe @#{user2.nickname}"
218 |> assign(:user, user1)
219 |> post("api/v1/statuses", %{"status" => content, "visibility" => "direct"})
221 assert %{"id" => id, "visibility" => "direct"} = json_response(conn, 200)
222 assert activity = Activity.get_by_id(id)
223 assert activity.recipients == [user2.ap_id, user1.ap_id]
224 assert activity.data["to"] == [user2.ap_id]
225 assert activity.data["cc"] == []
228 test "direct timeline", %{conn: conn} do
229 user_one = insert(:user)
230 user_two = insert(:user)
232 {:ok, user_two} = User.follow(user_two, user_one)
235 CommonAPI.post(user_one, %{
236 "status" => "Hi @#{user_two.nickname}!",
237 "visibility" => "direct"
240 {:ok, _follower_only} =
241 CommonAPI.post(user_one, %{
242 "status" => "Hi @#{user_two.nickname}!",
243 "visibility" => "private"
246 # Only direct should be visible here
249 |> assign(:user, user_two)
250 |> get("api/v1/timelines/direct")
252 [status] = json_response(res_conn, 200)
254 assert %{"visibility" => "direct"} = status
255 assert status["url"] != direct.data["id"]
257 # User should be able to see his own direct message
260 |> assign(:user, user_one)
261 |> get("api/v1/timelines/direct")
263 [status] = json_response(res_conn, 200)
265 assert %{"visibility" => "direct"} = status
267 # Both should be visible here
270 |> assign(:user, user_two)
271 |> get("api/v1/timelines/home")
273 [_s1, _s2] = json_response(res_conn, 200)
276 Enum.each(1..20, fn _ ->
278 CommonAPI.post(user_one, %{
279 "status" => "Hi @#{user_two.nickname}!",
280 "visibility" => "direct"
286 |> assign(:user, user_two)
287 |> get("api/v1/timelines/direct")
289 statuses = json_response(res_conn, 200)
290 assert length(statuses) == 20
294 |> assign(:user, user_two)
295 |> get("api/v1/timelines/direct", %{max_id: List.last(statuses)["id"]})
297 [status] = json_response(res_conn, 200)
299 assert status["url"] != direct.data["id"]
302 test "doesn't include DMs from blocked users", %{conn: conn} do
303 blocker = insert(:user)
304 blocked = insert(:user)
306 {:ok, blocker} = User.block(blocker, blocked)
308 {:ok, _blocked_direct} =
309 CommonAPI.post(blocked, %{
310 "status" => "Hi @#{blocker.nickname}!",
311 "visibility" => "direct"
315 CommonAPI.post(user, %{
316 "status" => "Hi @#{blocker.nickname}!",
317 "visibility" => "direct"
322 |> assign(:user, user)
323 |> get("api/v1/timelines/direct")
325 [status] = json_response(res_conn, 200)
326 assert status["id"] == direct.id
329 test "replying to a status", %{conn: conn} do
332 {:ok, replied_to} = TwitterAPI.create_status(user, %{"status" => "cofe"})
336 |> assign(:user, user)
337 |> post("/api/v1/statuses", %{"status" => "xD", "in_reply_to_id" => replied_to.id})
339 assert %{"content" => "xD", "id" => id} = json_response(conn, 200)
341 activity = Activity.get_by_id(id)
343 assert activity.data["context"] == replied_to.data["context"]
344 assert activity.data["object"]["inReplyToStatusId"] == replied_to.id
347 test "posting a status with an invalid in_reply_to_id", %{conn: conn} do
352 |> assign(:user, user)
353 |> post("/api/v1/statuses", %{"status" => "xD", "in_reply_to_id" => ""})
355 assert %{"content" => "xD", "id" => id} = json_response(conn, 200)
357 activity = Activity.get_by_id(id)
362 test "verify_credentials", %{conn: conn} do
367 |> assign(:user, user)
368 |> get("/api/v1/accounts/verify_credentials")
370 assert %{"id" => id, "source" => %{"privacy" => "public"}} = json_response(conn, 200)
371 assert id == to_string(user.id)
374 test "verify_credentials default scope unlisted", %{conn: conn} do
375 user = insert(:user, %{info: %Pleroma.User.Info{default_scope: "unlisted"}})
379 |> assign(:user, user)
380 |> get("/api/v1/accounts/verify_credentials")
382 assert %{"id" => id, "source" => %{"privacy" => "unlisted"}} = json_response(conn, 200)
383 assert id == to_string(user.id)
386 test "apps/verify_credentials", %{conn: conn} do
387 token = insert(:oauth_token)
391 |> assign(:user, token.user)
392 |> assign(:token, token)
393 |> get("/api/v1/apps/verify_credentials")
395 app = Repo.preload(token, :app).app
398 "name" => app.client_name,
399 "website" => app.website,
400 "vapid_key" => Push.vapid_config() |> Keyword.get(:public_key)
403 assert expected == json_response(conn, 200)
406 test "creates an oauth app", %{conn: conn} do
408 app_attrs = build(:oauth_app)
412 |> assign(:user, user)
413 |> post("/api/v1/apps", %{
414 client_name: app_attrs.client_name,
415 redirect_uris: app_attrs.redirect_uris
418 [app] = Repo.all(App)
421 "name" => app.client_name,
422 "website" => app.website,
423 "client_id" => app.client_id,
424 "client_secret" => app.client_secret,
425 "id" => app.id |> to_string(),
426 "redirect_uri" => app.redirect_uris,
427 "vapid_key" => Push.vapid_config() |> Keyword.get(:public_key)
430 assert expected == json_response(conn, 200)
433 test "get a status", %{conn: conn} do
434 activity = insert(:note_activity)
438 |> get("/api/v1/statuses/#{activity.id}")
440 assert %{"id" => id} = json_response(conn, 200)
441 assert id == to_string(activity.id)
444 describe "deleting a status" do
445 test "when you created it", %{conn: conn} do
446 activity = insert(:note_activity)
447 author = User.get_by_ap_id(activity.data["actor"])
451 |> assign(:user, author)
452 |> delete("/api/v1/statuses/#{activity.id}")
454 assert %{} = json_response(conn, 200)
456 refute Activity.get_by_id(activity.id)
459 test "when you didn't create it", %{conn: conn} do
460 activity = insert(:note_activity)
465 |> assign(:user, user)
466 |> delete("/api/v1/statuses/#{activity.id}")
468 assert %{"error" => _} = json_response(conn, 403)
470 assert Activity.get_by_id(activity.id) == activity
473 test "when you're an admin or moderator", %{conn: conn} do
474 activity1 = insert(:note_activity)
475 activity2 = insert(:note_activity)
476 admin = insert(:user, info: %{is_admin: true})
477 moderator = insert(:user, info: %{is_moderator: true})
481 |> assign(:user, admin)
482 |> delete("/api/v1/statuses/#{activity1.id}")
484 assert %{} = json_response(res_conn, 200)
488 |> assign(:user, moderator)
489 |> delete("/api/v1/statuses/#{activity2.id}")
491 assert %{} = json_response(res_conn, 200)
493 refute Activity.get_by_id(activity1.id)
494 refute Activity.get_by_id(activity2.id)
498 describe "filters" do
499 test "creating a filter", %{conn: conn} do
502 filter = %Pleroma.Filter{
509 |> assign(:user, user)
510 |> post("/api/v1/filters", %{"phrase" => filter.phrase, context: filter.context})
512 assert response = json_response(conn, 200)
513 assert response["phrase"] == filter.phrase
514 assert response["context"] == filter.context
515 assert response["id"] != nil
516 assert response["id"] != ""
519 test "fetching a list of filters", %{conn: conn} do
522 query_one = %Pleroma.Filter{
529 query_two = %Pleroma.Filter{
536 {:ok, filter_one} = Pleroma.Filter.create(query_one)
537 {:ok, filter_two} = Pleroma.Filter.create(query_two)
541 |> assign(:user, user)
542 |> get("/api/v1/filters")
543 |> json_response(200)
549 filters: [filter_two, filter_one]
553 test "get a filter", %{conn: conn} do
556 query = %Pleroma.Filter{
563 {:ok, filter} = Pleroma.Filter.create(query)
567 |> assign(:user, user)
568 |> get("/api/v1/filters/#{filter.filter_id}")
570 assert _response = json_response(conn, 200)
573 test "update a filter", %{conn: conn} do
576 query = %Pleroma.Filter{
583 {:ok, _filter} = Pleroma.Filter.create(query)
585 new = %Pleroma.Filter{
592 |> assign(:user, user)
593 |> put("/api/v1/filters/#{query.filter_id}", %{
598 assert response = json_response(conn, 200)
599 assert response["phrase"] == new.phrase
600 assert response["context"] == new.context
603 test "delete a filter", %{conn: conn} do
606 query = %Pleroma.Filter{
613 {:ok, filter} = Pleroma.Filter.create(query)
617 |> assign(:user, user)
618 |> delete("/api/v1/filters/#{filter.filter_id}")
620 assert response = json_response(conn, 200)
621 assert response == %{}
626 test "creating a list", %{conn: conn} do
631 |> assign(:user, user)
632 |> post("/api/v1/lists", %{"title" => "cuties"})
634 assert %{"title" => title} = json_response(conn, 200)
635 assert title == "cuties"
638 test "adding users to a list", %{conn: conn} do
640 other_user = insert(:user)
641 {:ok, list} = Pleroma.List.create("name", user)
645 |> assign(:user, user)
646 |> post("/api/v1/lists/#{list.id}/accounts", %{"account_ids" => [other_user.id]})
648 assert %{} == json_response(conn, 200)
649 %Pleroma.List{following: following} = Pleroma.List.get(list.id, user)
650 assert following == [other_user.follower_address]
653 test "removing users from a list", %{conn: conn} do
655 other_user = insert(:user)
656 third_user = insert(:user)
657 {:ok, list} = Pleroma.List.create("name", user)
658 {:ok, list} = Pleroma.List.follow(list, other_user)
659 {:ok, list} = Pleroma.List.follow(list, third_user)
663 |> assign(:user, user)
664 |> delete("/api/v1/lists/#{list.id}/accounts", %{"account_ids" => [other_user.id]})
666 assert %{} == json_response(conn, 200)
667 %Pleroma.List{following: following} = Pleroma.List.get(list.id, user)
668 assert following == [third_user.follower_address]
671 test "listing users in a list", %{conn: conn} do
673 other_user = insert(:user)
674 {:ok, list} = Pleroma.List.create("name", user)
675 {:ok, list} = Pleroma.List.follow(list, other_user)
679 |> assign(:user, user)
680 |> get("/api/v1/lists/#{list.id}/accounts", %{"account_ids" => [other_user.id]})
682 assert [%{"id" => id}] = json_response(conn, 200)
683 assert id == to_string(other_user.id)
686 test "retrieving a list", %{conn: conn} do
688 {:ok, list} = Pleroma.List.create("name", user)
692 |> assign(:user, user)
693 |> get("/api/v1/lists/#{list.id}")
695 assert %{"id" => id} = json_response(conn, 200)
696 assert id == to_string(list.id)
699 test "renaming a list", %{conn: conn} do
701 {:ok, list} = Pleroma.List.create("name", user)
705 |> assign(:user, user)
706 |> put("/api/v1/lists/#{list.id}", %{"title" => "newname"})
708 assert %{"title" => name} = json_response(conn, 200)
709 assert name == "newname"
712 test "deleting a list", %{conn: conn} do
714 {:ok, list} = Pleroma.List.create("name", user)
718 |> assign(:user, user)
719 |> delete("/api/v1/lists/#{list.id}")
721 assert %{} = json_response(conn, 200)
722 assert is_nil(Repo.get(Pleroma.List, list.id))
725 test "list timeline", %{conn: conn} do
727 other_user = insert(:user)
728 {:ok, _activity_one} = TwitterAPI.create_status(user, %{"status" => "Marisa is cute."})
729 {:ok, activity_two} = TwitterAPI.create_status(other_user, %{"status" => "Marisa is cute."})
730 {:ok, list} = Pleroma.List.create("name", user)
731 {:ok, list} = Pleroma.List.follow(list, other_user)
735 |> assign(:user, user)
736 |> get("/api/v1/timelines/list/#{list.id}")
738 assert [%{"id" => id}] = json_response(conn, 200)
740 assert id == to_string(activity_two.id)
743 test "list timeline does not leak non-public statuses for unfollowed users", %{conn: conn} do
745 other_user = insert(:user)
746 {:ok, activity_one} = TwitterAPI.create_status(other_user, %{"status" => "Marisa is cute."})
748 {:ok, _activity_two} =
749 TwitterAPI.create_status(other_user, %{
750 "status" => "Marisa is cute.",
751 "visibility" => "private"
754 {:ok, list} = Pleroma.List.create("name", user)
755 {:ok, list} = Pleroma.List.follow(list, other_user)
759 |> assign(:user, user)
760 |> get("/api/v1/timelines/list/#{list.id}")
762 assert [%{"id" => id}] = json_response(conn, 200)
764 assert id == to_string(activity_one.id)
768 describe "notifications" do
769 test "list of notifications", %{conn: conn} do
771 other_user = insert(:user)
774 TwitterAPI.create_status(other_user, %{"status" => "hi @#{user.nickname}"})
776 {:ok, [_notification]} = Notification.create_notifications(activity)
780 |> assign(:user, user)
781 |> get("/api/v1/notifications")
784 "hi <span class=\"h-card\"><a data-user=\"#{user.id}\" class=\"u-url mention\" href=\"#{
786 }\">@<span>#{user.nickname}</span></a></span>"
788 assert [%{"status" => %{"content" => response}} | _rest] = json_response(conn, 200)
789 assert response == expected_response
792 test "getting a single notification", %{conn: conn} do
794 other_user = insert(:user)
797 TwitterAPI.create_status(other_user, %{"status" => "hi @#{user.nickname}"})
799 {:ok, [notification]} = Notification.create_notifications(activity)
803 |> assign(:user, user)
804 |> get("/api/v1/notifications/#{notification.id}")
807 "hi <span class=\"h-card\"><a data-user=\"#{user.id}\" class=\"u-url mention\" href=\"#{
809 }\">@<span>#{user.nickname}</span></a></span>"
811 assert %{"status" => %{"content" => response}} = json_response(conn, 200)
812 assert response == expected_response
815 test "dismissing a single notification", %{conn: conn} do
817 other_user = insert(:user)
820 TwitterAPI.create_status(other_user, %{"status" => "hi @#{user.nickname}"})
822 {:ok, [notification]} = Notification.create_notifications(activity)
826 |> assign(:user, user)
827 |> post("/api/v1/notifications/dismiss", %{"id" => notification.id})
829 assert %{} = json_response(conn, 200)
832 test "clearing all notifications", %{conn: conn} do
834 other_user = insert(:user)
837 TwitterAPI.create_status(other_user, %{"status" => "hi @#{user.nickname}"})
839 {:ok, [_notification]} = Notification.create_notifications(activity)
843 |> assign(:user, user)
844 |> post("/api/v1/notifications/clear")
846 assert %{} = json_response(conn, 200)
850 |> assign(:user, user)
851 |> get("/api/v1/notifications")
853 assert all = json_response(conn, 200)
857 test "paginates notifications using min_id, since_id, max_id, and limit", %{conn: conn} do
859 other_user = insert(:user)
861 {:ok, activity1} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
862 {:ok, activity2} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
863 {:ok, activity3} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
864 {:ok, activity4} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
866 notification1_id = Repo.get_by(Notification, activity_id: activity1.id).id |> to_string()
867 notification2_id = Repo.get_by(Notification, activity_id: activity2.id).id |> to_string()
868 notification3_id = Repo.get_by(Notification, activity_id: activity3.id).id |> to_string()
869 notification4_id = Repo.get_by(Notification, activity_id: activity4.id).id |> to_string()
873 |> assign(:user, user)
878 |> get("/api/v1/notifications?limit=2&min_id=#{notification1_id}")
880 result = json_response(conn_res, 200)
881 assert [%{"id" => ^notification3_id}, %{"id" => ^notification2_id}] = result
886 |> get("/api/v1/notifications?limit=2&since_id=#{notification1_id}")
888 result = json_response(conn_res, 200)
889 assert [%{"id" => ^notification4_id}, %{"id" => ^notification3_id}] = result
894 |> get("/api/v1/notifications?limit=2&max_id=#{notification4_id}")
896 result = json_response(conn_res, 200)
897 assert [%{"id" => ^notification3_id}, %{"id" => ^notification2_id}] = result
900 test "filters notifications using exclude_types", %{conn: conn} do
902 other_user = insert(:user)
904 {:ok, mention_activity} = CommonAPI.post(other_user, %{"status" => "hey @#{user.nickname}"})
905 {:ok, create_activity} = CommonAPI.post(user, %{"status" => "hey"})
906 {:ok, favorite_activity, _} = CommonAPI.favorite(create_activity.id, other_user)
907 {:ok, reblog_activity, _} = CommonAPI.repeat(create_activity.id, other_user)
908 {:ok, _, _, follow_activity} = CommonAPI.follow(other_user, user)
910 mention_notification_id =
911 Repo.get_by(Notification, activity_id: mention_activity.id).id |> to_string()
913 favorite_notification_id =
914 Repo.get_by(Notification, activity_id: favorite_activity.id).id |> to_string()
916 reblog_notification_id =
917 Repo.get_by(Notification, activity_id: reblog_activity.id).id |> to_string()
919 follow_notification_id =
920 Repo.get_by(Notification, activity_id: follow_activity.id).id |> to_string()
924 |> assign(:user, user)
927 get(conn, "/api/v1/notifications", %{exclude_types: ["mention", "favourite", "reblog"]})
929 assert [%{"id" => ^follow_notification_id}] = json_response(conn_res, 200)
932 get(conn, "/api/v1/notifications", %{exclude_types: ["favourite", "reblog", "follow"]})
934 assert [%{"id" => ^mention_notification_id}] = json_response(conn_res, 200)
937 get(conn, "/api/v1/notifications", %{exclude_types: ["reblog", "follow", "mention"]})
939 assert [%{"id" => ^favorite_notification_id}] = json_response(conn_res, 200)
942 get(conn, "/api/v1/notifications", %{exclude_types: ["follow", "mention", "favourite"]})
944 assert [%{"id" => ^reblog_notification_id}] = json_response(conn_res, 200)
948 describe "reblogging" do
949 test "reblogs and returns the reblogged status", %{conn: conn} do
950 activity = insert(:note_activity)
955 |> assign(:user, user)
956 |> post("/api/v1/statuses/#{activity.id}/reblog")
958 assert %{"reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 1}} =
959 json_response(conn, 200)
961 assert to_string(activity.id) == id
965 describe "unreblogging" do
966 test "unreblogs and returns the unreblogged status", %{conn: conn} do
967 activity = insert(:note_activity)
970 {:ok, _, _} = CommonAPI.repeat(activity.id, user)
974 |> assign(:user, user)
975 |> post("/api/v1/statuses/#{activity.id}/unreblog")
977 assert %{"id" => id, "reblogged" => false, "reblogs_count" => 0} = json_response(conn, 200)
979 assert to_string(activity.id) == id
983 describe "favoriting" do
984 test "favs a status and returns it", %{conn: conn} do
985 activity = insert(:note_activity)
990 |> assign(:user, user)
991 |> post("/api/v1/statuses/#{activity.id}/favourite")
993 assert %{"id" => id, "favourites_count" => 1, "favourited" => true} =
994 json_response(conn, 200)
996 assert to_string(activity.id) == id
999 test "returns 500 for a wrong id", %{conn: conn} do
1000 user = insert(:user)
1004 |> assign(:user, user)
1005 |> post("/api/v1/statuses/1/favourite")
1006 |> json_response(500)
1008 assert resp == "Something went wrong"
1012 describe "unfavoriting" do
1013 test "unfavorites a status and returns it", %{conn: conn} do
1014 activity = insert(:note_activity)
1015 user = insert(:user)
1017 {:ok, _, _} = CommonAPI.favorite(activity.id, user)
1021 |> assign(:user, user)
1022 |> post("/api/v1/statuses/#{activity.id}/unfavourite")
1024 assert %{"id" => id, "favourites_count" => 0, "favourited" => false} =
1025 json_response(conn, 200)
1027 assert to_string(activity.id) == id
1031 describe "user timelines" do
1032 test "gets a users statuses", %{conn: conn} do
1033 user_one = insert(:user)
1034 user_two = insert(:user)
1035 user_three = insert(:user)
1037 {:ok, user_three} = User.follow(user_three, user_one)
1039 {:ok, activity} = CommonAPI.post(user_one, %{"status" => "HI!!!"})
1041 {:ok, direct_activity} =
1042 CommonAPI.post(user_one, %{
1043 "status" => "Hi, @#{user_two.nickname}.",
1044 "visibility" => "direct"
1047 {:ok, private_activity} =
1048 CommonAPI.post(user_one, %{"status" => "private", "visibility" => "private"})
1052 |> get("/api/v1/accounts/#{user_one.id}/statuses")
1054 assert [%{"id" => id}] = json_response(resp, 200)
1055 assert id == to_string(activity.id)
1059 |> assign(:user, user_two)
1060 |> get("/api/v1/accounts/#{user_one.id}/statuses")
1062 assert [%{"id" => id_one}, %{"id" => id_two}] = json_response(resp, 200)
1063 assert id_one == to_string(direct_activity.id)
1064 assert id_two == to_string(activity.id)
1068 |> assign(:user, user_three)
1069 |> get("/api/v1/accounts/#{user_one.id}/statuses")
1071 assert [%{"id" => id_one}, %{"id" => id_two}] = json_response(resp, 200)
1072 assert id_one == to_string(private_activity.id)
1073 assert id_two == to_string(activity.id)
1076 test "unimplemented pinned statuses feature", %{conn: conn} do
1077 note = insert(:note_activity)
1078 user = User.get_by_ap_id(note.data["actor"])
1082 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
1084 assert json_response(conn, 200) == []
1087 test "gets an users media", %{conn: conn} do
1088 note = insert(:note_activity)
1089 user = User.get_by_ap_id(note.data["actor"])
1091 file = %Plug.Upload{
1092 content_type: "image/jpg",
1093 path: Path.absname("test/fixtures/image.jpg"),
1094 filename: "an_image.jpg"
1098 TwitterAPI.upload(file, user, "json")
1102 TwitterAPI.create_status(user, %{"status" => "cofe", "media_ids" => [media["media_id"]]})
1106 |> get("/api/v1/accounts/#{user.id}/statuses", %{"only_media" => "true"})
1108 assert [%{"id" => id}] = json_response(conn, 200)
1109 assert id == to_string(image_post.id)
1113 |> get("/api/v1/accounts/#{user.id}/statuses", %{"only_media" => "1"})
1115 assert [%{"id" => id}] = json_response(conn, 200)
1116 assert id == to_string(image_post.id)
1119 test "gets a user's statuses without reblogs", %{conn: conn} do
1120 user = insert(:user)
1121 {:ok, post} = CommonAPI.post(user, %{"status" => "HI!!!"})
1122 {:ok, _, _} = CommonAPI.repeat(post.id, user)
1126 |> get("/api/v1/accounts/#{user.id}/statuses", %{"exclude_reblogs" => "true"})
1128 assert [%{"id" => id}] = json_response(conn, 200)
1129 assert id == to_string(post.id)
1133 |> get("/api/v1/accounts/#{user.id}/statuses", %{"exclude_reblogs" => "1"})
1135 assert [%{"id" => id}] = json_response(conn, 200)
1136 assert id == to_string(post.id)
1140 describe "user relationships" do
1141 test "returns the relationships for the current user", %{conn: conn} do
1142 user = insert(:user)
1143 other_user = insert(:user)
1144 {:ok, user} = User.follow(user, other_user)
1148 |> assign(:user, user)
1149 |> get("/api/v1/accounts/relationships", %{"id" => [other_user.id]})
1151 assert [relationship] = json_response(conn, 200)
1153 assert to_string(other_user.id) == relationship["id"]
1157 describe "locked accounts" do
1158 test "/api/v1/follow_requests works" do
1159 user = insert(:user, %{info: %Pleroma.User.Info{locked: true}})
1160 other_user = insert(:user)
1162 {:ok, _activity} = ActivityPub.follow(other_user, user)
1164 user = User.get_by_id(user.id)
1165 other_user = User.get_by_id(other_user.id)
1167 assert User.following?(other_user, user) == false
1171 |> assign(:user, user)
1172 |> get("/api/v1/follow_requests")
1174 assert [relationship] = json_response(conn, 200)
1175 assert to_string(other_user.id) == relationship["id"]
1178 test "/api/v1/follow_requests/:id/authorize works" do
1179 user = insert(:user, %{info: %User.Info{locked: true}})
1180 other_user = insert(:user)
1182 {:ok, _activity} = ActivityPub.follow(other_user, user)
1184 user = User.get_by_id(user.id)
1185 other_user = User.get_by_id(other_user.id)
1187 assert User.following?(other_user, user) == false
1191 |> assign(:user, user)
1192 |> post("/api/v1/follow_requests/#{other_user.id}/authorize")
1194 assert relationship = json_response(conn, 200)
1195 assert to_string(other_user.id) == relationship["id"]
1197 user = User.get_by_id(user.id)
1198 other_user = User.get_by_id(other_user.id)
1200 assert User.following?(other_user, user) == true
1203 test "verify_credentials", %{conn: conn} do
1204 user = insert(:user, %{info: %Pleroma.User.Info{default_scope: "private"}})
1208 |> assign(:user, user)
1209 |> get("/api/v1/accounts/verify_credentials")
1211 assert %{"id" => id, "source" => %{"privacy" => "private"}} = json_response(conn, 200)
1212 assert id == to_string(user.id)
1215 test "/api/v1/follow_requests/:id/reject works" do
1216 user = insert(:user, %{info: %Pleroma.User.Info{locked: true}})
1217 other_user = insert(:user)
1219 {:ok, _activity} = ActivityPub.follow(other_user, user)
1221 user = User.get_by_id(user.id)
1225 |> assign(:user, user)
1226 |> post("/api/v1/follow_requests/#{other_user.id}/reject")
1228 assert relationship = json_response(conn, 200)
1229 assert to_string(other_user.id) == relationship["id"]
1231 user = User.get_by_id(user.id)
1232 other_user = User.get_by_id(other_user.id)
1234 assert User.following?(other_user, user) == false
1238 test "account fetching", %{conn: conn} do
1239 user = insert(:user)
1243 |> get("/api/v1/accounts/#{user.id}")
1245 assert %{"id" => id} = json_response(conn, 200)
1246 assert id == to_string(user.id)
1250 |> get("/api/v1/accounts/-1")
1252 assert %{"error" => "Can't find user"} = json_response(conn, 404)
1255 test "account fetching also works nickname", %{conn: conn} do
1256 user = insert(:user)
1260 |> get("/api/v1/accounts/#{user.nickname}")
1262 assert %{"id" => id} = json_response(conn, 200)
1263 assert id == user.id
1266 test "media upload", %{conn: conn} do
1267 file = %Plug.Upload{
1268 content_type: "image/jpg",
1269 path: Path.absname("test/fixtures/image.jpg"),
1270 filename: "an_image.jpg"
1273 desc = "Description of the image"
1275 user = insert(:user)
1279 |> assign(:user, user)
1280 |> post("/api/v1/media", %{"file" => file, "description" => desc})
1282 assert media = json_response(conn, 200)
1284 assert media["type"] == "image"
1285 assert media["description"] == desc
1288 object = Repo.get(Object, media["id"])
1289 assert object.data["actor"] == User.ap_id(user)
1292 test "hashtag timeline", %{conn: conn} do
1293 following = insert(:user)
1296 {:ok, activity} = TwitterAPI.create_status(following, %{"status" => "test #2hu"})
1298 {:ok, [_activity]} =
1299 OStatus.fetch_activity_from_url("https://shitposter.club/notice/2827873")
1303 |> get("/api/v1/timelines/tag/2hu")
1305 assert [%{"id" => id}] = json_response(nconn, 200)
1307 assert id == to_string(activity.id)
1309 # works for different capitalization too
1312 |> get("/api/v1/timelines/tag/2HU")
1314 assert [%{"id" => id}] = json_response(nconn, 200)
1316 assert id == to_string(activity.id)
1320 test "multi-hashtag timeline", %{conn: conn} do
1321 user = insert(:user)
1323 {:ok, activity_test} = CommonAPI.post(user, %{"status" => "#test"})
1324 {:ok, activity_test1} = CommonAPI.post(user, %{"status" => "#test #test1"})
1325 {:ok, activity_none} = CommonAPI.post(user, %{"status" => "#test #none"})
1329 |> get("/api/v1/timelines/tag/test", %{"any" => ["test1"]})
1331 [status_none, status_test1, status_test] = json_response(any_test, 200)
1333 assert to_string(activity_test.id) == status_test["id"]
1334 assert to_string(activity_test1.id) == status_test1["id"]
1335 assert to_string(activity_none.id) == status_none["id"]
1339 |> get("/api/v1/timelines/tag/test", %{"all" => ["test1"], "none" => ["none"]})
1341 assert [status_test1] == json_response(restricted_test, 200)
1343 all_test = conn |> get("/api/v1/timelines/tag/test", %{"all" => ["none"]})
1345 assert [status_none] == json_response(all_test, 200)
1348 test "getting followers", %{conn: conn} do
1349 user = insert(:user)
1350 other_user = insert(:user)
1351 {:ok, user} = User.follow(user, other_user)
1355 |> get("/api/v1/accounts/#{other_user.id}/followers")
1357 assert [%{"id" => id}] = json_response(conn, 200)
1358 assert id == to_string(user.id)
1361 test "getting followers, hide_followers", %{conn: conn} do
1362 user = insert(:user)
1363 other_user = insert(:user, %{info: %{hide_followers: true}})
1364 {:ok, _user} = User.follow(user, other_user)
1368 |> get("/api/v1/accounts/#{other_user.id}/followers")
1370 assert [] == json_response(conn, 200)
1373 test "getting followers, hide_followers, same user requesting", %{conn: conn} do
1374 user = insert(:user)
1375 other_user = insert(:user, %{info: %{hide_followers: true}})
1376 {:ok, _user} = User.follow(user, other_user)
1380 |> assign(:user, other_user)
1381 |> get("/api/v1/accounts/#{other_user.id}/followers")
1383 refute [] == json_response(conn, 200)
1386 test "getting followers, pagination", %{conn: conn} do
1387 user = insert(:user)
1388 follower1 = insert(:user)
1389 follower2 = insert(:user)
1390 follower3 = insert(:user)
1391 {:ok, _} = User.follow(follower1, user)
1392 {:ok, _} = User.follow(follower2, user)
1393 {:ok, _} = User.follow(follower3, user)
1397 |> assign(:user, user)
1401 |> get("/api/v1/accounts/#{user.id}/followers?since_id=#{follower1.id}")
1403 assert [%{"id" => id3}, %{"id" => id2}] = json_response(res_conn, 200)
1404 assert id3 == follower3.id
1405 assert id2 == follower2.id
1409 |> get("/api/v1/accounts/#{user.id}/followers?max_id=#{follower3.id}")
1411 assert [%{"id" => id2}, %{"id" => id1}] = json_response(res_conn, 200)
1412 assert id2 == follower2.id
1413 assert id1 == follower1.id
1417 |> get("/api/v1/accounts/#{user.id}/followers?limit=1&max_id=#{follower3.id}")
1419 assert [%{"id" => id2}] = json_response(res_conn, 200)
1420 assert id2 == follower2.id
1422 assert [link_header] = get_resp_header(res_conn, "link")
1423 assert link_header =~ ~r/since_id=#{follower2.id}/
1424 assert link_header =~ ~r/max_id=#{follower2.id}/
1427 test "getting following", %{conn: conn} do
1428 user = insert(:user)
1429 other_user = insert(:user)
1430 {:ok, user} = User.follow(user, other_user)
1434 |> get("/api/v1/accounts/#{user.id}/following")
1436 assert [%{"id" => id}] = json_response(conn, 200)
1437 assert id == to_string(other_user.id)
1440 test "getting following, hide_follows", %{conn: conn} do
1441 user = insert(:user, %{info: %{hide_follows: true}})
1442 other_user = insert(:user)
1443 {:ok, user} = User.follow(user, other_user)
1447 |> get("/api/v1/accounts/#{user.id}/following")
1449 assert [] == json_response(conn, 200)
1452 test "getting following, hide_follows, same user requesting", %{conn: conn} do
1453 user = insert(:user, %{info: %{hide_follows: true}})
1454 other_user = insert(:user)
1455 {:ok, user} = User.follow(user, other_user)
1459 |> assign(:user, user)
1460 |> get("/api/v1/accounts/#{user.id}/following")
1462 refute [] == json_response(conn, 200)
1465 test "getting following, pagination", %{conn: conn} do
1466 user = insert(:user)
1467 following1 = insert(:user)
1468 following2 = insert(:user)
1469 following3 = insert(:user)
1470 {:ok, _} = User.follow(user, following1)
1471 {:ok, _} = User.follow(user, following2)
1472 {:ok, _} = User.follow(user, following3)
1476 |> assign(:user, user)
1480 |> get("/api/v1/accounts/#{user.id}/following?since_id=#{following1.id}")
1482 assert [%{"id" => id3}, %{"id" => id2}] = json_response(res_conn, 200)
1483 assert id3 == following3.id
1484 assert id2 == following2.id
1488 |> get("/api/v1/accounts/#{user.id}/following?max_id=#{following3.id}")
1490 assert [%{"id" => id2}, %{"id" => id1}] = json_response(res_conn, 200)
1491 assert id2 == following2.id
1492 assert id1 == following1.id
1496 |> get("/api/v1/accounts/#{user.id}/following?limit=1&max_id=#{following3.id}")
1498 assert [%{"id" => id2}] = json_response(res_conn, 200)
1499 assert id2 == following2.id
1501 assert [link_header] = get_resp_header(res_conn, "link")
1502 assert link_header =~ ~r/since_id=#{following2.id}/
1503 assert link_header =~ ~r/max_id=#{following2.id}/
1506 test "following / unfollowing a user", %{conn: conn} do
1507 user = insert(:user)
1508 other_user = insert(:user)
1512 |> assign(:user, user)
1513 |> post("/api/v1/accounts/#{other_user.id}/follow")
1515 assert %{"id" => _id, "following" => true} = json_response(conn, 200)
1517 user = User.get_by_id(user.id)
1521 |> assign(:user, user)
1522 |> post("/api/v1/accounts/#{other_user.id}/unfollow")
1524 assert %{"id" => _id, "following" => false} = json_response(conn, 200)
1526 user = User.get_by_id(user.id)
1530 |> assign(:user, user)
1531 |> post("/api/v1/follows", %{"uri" => other_user.nickname})
1533 assert %{"id" => id} = json_response(conn, 200)
1534 assert id == to_string(other_user.id)
1537 test "muting / unmuting a user", %{conn: conn} do
1538 user = insert(:user)
1539 other_user = insert(:user)
1543 |> assign(:user, user)
1544 |> post("/api/v1/accounts/#{other_user.id}/mute")
1546 assert %{"id" => _id, "muting" => true} = json_response(conn, 200)
1548 user = User.get_by_id(user.id)
1552 |> assign(:user, user)
1553 |> post("/api/v1/accounts/#{other_user.id}/unmute")
1555 assert %{"id" => _id, "muting" => false} = json_response(conn, 200)
1558 test "getting a list of mutes", %{conn: conn} do
1559 user = insert(:user)
1560 other_user = insert(:user)
1562 {:ok, user} = User.mute(user, other_user)
1566 |> assign(:user, user)
1567 |> get("/api/v1/mutes")
1569 other_user_id = to_string(other_user.id)
1570 assert [%{"id" => ^other_user_id}] = json_response(conn, 200)
1573 test "blocking / unblocking a user", %{conn: conn} do
1574 user = insert(:user)
1575 other_user = insert(:user)
1579 |> assign(:user, user)
1580 |> post("/api/v1/accounts/#{other_user.id}/block")
1582 assert %{"id" => _id, "blocking" => true} = json_response(conn, 200)
1584 user = User.get_by_id(user.id)
1588 |> assign(:user, user)
1589 |> post("/api/v1/accounts/#{other_user.id}/unblock")
1591 assert %{"id" => _id, "blocking" => false} = json_response(conn, 200)
1594 test "getting a list of blocks", %{conn: conn} do
1595 user = insert(:user)
1596 other_user = insert(:user)
1598 {:ok, user} = User.block(user, other_user)
1602 |> assign(:user, user)
1603 |> get("/api/v1/blocks")
1605 other_user_id = to_string(other_user.id)
1606 assert [%{"id" => ^other_user_id}] = json_response(conn, 200)
1609 test "blocking / unblocking a domain", %{conn: conn} do
1610 user = insert(:user)
1611 other_user = insert(:user, %{ap_id: "https://dogwhistle.zone/@pundit"})
1615 |> assign(:user, user)
1616 |> post("/api/v1/domain_blocks", %{"domain" => "dogwhistle.zone"})
1618 assert %{} = json_response(conn, 200)
1619 user = User.get_cached_by_ap_id(user.ap_id)
1620 assert User.blocks?(user, other_user)
1624 |> assign(:user, user)
1625 |> delete("/api/v1/domain_blocks", %{"domain" => "dogwhistle.zone"})
1627 assert %{} = json_response(conn, 200)
1628 user = User.get_cached_by_ap_id(user.ap_id)
1629 refute User.blocks?(user, other_user)
1632 test "getting a list of domain blocks", %{conn: conn} do
1633 user = insert(:user)
1635 {:ok, user} = User.block_domain(user, "bad.site")
1636 {:ok, user} = User.block_domain(user, "even.worse.site")
1640 |> assign(:user, user)
1641 |> get("/api/v1/domain_blocks")
1643 domain_blocks = json_response(conn, 200)
1645 assert "bad.site" in domain_blocks
1646 assert "even.worse.site" in domain_blocks
1649 test "unimplemented follow_requests, blocks, domain blocks" do
1650 user = insert(:user)
1652 ["blocks", "domain_blocks", "follow_requests"]
1653 |> Enum.each(fn endpoint ->
1656 |> assign(:user, user)
1657 |> get("/api/v1/#{endpoint}")
1659 assert [] = json_response(conn, 200)
1663 test "account search", %{conn: conn} do
1664 user = insert(:user)
1665 user_two = insert(:user, %{nickname: "shp@shitposter.club"})
1666 user_three = insert(:user, %{nickname: "shp@heldscal.la", name: "I love 2hu"})
1670 |> assign(:user, user)
1671 |> get("/api/v1/accounts/search", %{"q" => "shp"})
1672 |> json_response(200)
1674 result_ids = for result <- results, do: result["acct"]
1676 assert user_two.nickname in result_ids
1677 assert user_three.nickname in result_ids
1681 |> assign(:user, user)
1682 |> get("/api/v1/accounts/search", %{"q" => "2hu"})
1683 |> json_response(200)
1685 result_ids = for result <- results, do: result["acct"]
1687 assert user_three.nickname in result_ids
1690 test "search", %{conn: conn} do
1691 user = insert(:user)
1692 user_two = insert(:user, %{nickname: "shp@shitposter.club"})
1693 user_three = insert(:user, %{nickname: "shp@heldscal.la", name: "I love 2hu"})
1695 {:ok, activity} = CommonAPI.post(user, %{"status" => "This is about 2hu"})
1698 CommonAPI.post(user, %{
1699 "status" => "This is about 2hu, but private",
1700 "visibility" => "private"
1703 {:ok, _} = CommonAPI.post(user_two, %{"status" => "This isn't"})
1707 |> get("/api/v1/search", %{"q" => "2hu"})
1709 assert results = json_response(conn, 200)
1711 [account | _] = results["accounts"]
1712 assert account["id"] == to_string(user_three.id)
1714 assert results["hashtags"] == []
1716 [status] = results["statuses"]
1717 assert status["id"] == to_string(activity.id)
1720 test "search fetches remote statuses", %{conn: conn} do
1724 |> get("/api/v1/search", %{"q" => "https://shitposter.club/notice/2827873"})
1726 assert results = json_response(conn, 200)
1728 [status] = results["statuses"]
1729 assert status["uri"] == "tag:shitposter.club,2017-05-05:noticeId=2827873:objectType=comment"
1733 test "search doesn't show statuses that it shouldn't", %{conn: conn} do
1735 CommonAPI.post(insert(:user), %{
1736 "status" => "This is about 2hu, but private",
1737 "visibility" => "private"
1743 |> get("/api/v1/search", %{"q" => activity.data["object"]["id"]})
1745 assert results = json_response(conn, 200)
1747 [] = results["statuses"]
1751 test "search fetches remote accounts", %{conn: conn} do
1754 |> get("/api/v1/search", %{"q" => "shp@social.heldscal.la", "resolve" => "true"})
1756 assert results = json_response(conn, 200)
1757 [account] = results["accounts"]
1758 assert account["acct"] == "shp@social.heldscal.la"
1761 test "returns the favorites of a user", %{conn: conn} do
1762 user = insert(:user)
1763 other_user = insert(:user)
1765 {:ok, _} = CommonAPI.post(other_user, %{"status" => "bla"})
1766 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "traps are happy"})
1768 {:ok, _, _} = CommonAPI.favorite(activity.id, user)
1772 |> assign(:user, user)
1773 |> get("/api/v1/favourites")
1775 assert [status] = json_response(first_conn, 200)
1776 assert status["id"] == to_string(activity.id)
1778 assert [{"link", _link_header}] =
1779 Enum.filter(first_conn.resp_headers, fn element -> match?({"link", _}, element) end)
1781 # Honours query params
1782 {:ok, second_activity} =
1783 CommonAPI.post(other_user, %{
1785 "Trees Are Never Sad Look At Them Every Once In Awhile They're Quite Beautiful."
1788 {:ok, _, _} = CommonAPI.favorite(second_activity.id, user)
1790 last_like = status["id"]
1794 |> assign(:user, user)
1795 |> get("/api/v1/favourites?since_id=#{last_like}")
1797 assert [second_status] = json_response(second_conn, 200)
1798 assert second_status["id"] == to_string(second_activity.id)
1802 |> assign(:user, user)
1803 |> get("/api/v1/favourites?limit=0")
1805 assert [] = json_response(third_conn, 200)
1808 describe "updating credentials" do
1809 test "updates the user's bio", %{conn: conn} do
1810 user = insert(:user)
1811 user2 = insert(:user)
1815 |> assign(:user, user)
1816 |> patch("/api/v1/accounts/update_credentials", %{
1817 "note" => "I drink #cofe with @#{user2.nickname}"
1820 assert user = json_response(conn, 200)
1822 assert user["note"] ==
1823 ~s(I drink <a class="hashtag" data-tag="cofe" href="http://localhost:4001/tag/cofe" rel="tag">#cofe</a> with <span class="h-card"><a data-user=") <>
1825 ~s(" class="u-url mention" href=") <>
1826 user2.ap_id <> ~s(">@<span>) <> user2.nickname <> ~s(</span></a></span>)
1829 test "updates the user's locking status", %{conn: conn} do
1830 user = insert(:user)
1834 |> assign(:user, user)
1835 |> patch("/api/v1/accounts/update_credentials", %{locked: "true"})
1837 assert user = json_response(conn, 200)
1838 assert user["locked"] == true
1841 test "updates the user's name", %{conn: conn} do
1842 user = insert(:user)
1846 |> assign(:user, user)
1847 |> patch("/api/v1/accounts/update_credentials", %{"display_name" => "markorepairs"})
1849 assert user = json_response(conn, 200)
1850 assert user["display_name"] == "markorepairs"
1853 test "updates the user's avatar", %{conn: conn} do
1854 user = insert(:user)
1856 new_avatar = %Plug.Upload{
1857 content_type: "image/jpg",
1858 path: Path.absname("test/fixtures/image.jpg"),
1859 filename: "an_image.jpg"
1864 |> assign(:user, user)
1865 |> patch("/api/v1/accounts/update_credentials", %{"avatar" => new_avatar})
1867 assert user_response = json_response(conn, 200)
1868 assert user_response["avatar"] != User.avatar_url(user)
1871 test "updates the user's banner", %{conn: conn} do
1872 user = insert(:user)
1874 new_header = %Plug.Upload{
1875 content_type: "image/jpg",
1876 path: Path.absname("test/fixtures/image.jpg"),
1877 filename: "an_image.jpg"
1882 |> assign(:user, user)
1883 |> patch("/api/v1/accounts/update_credentials", %{"header" => new_header})
1885 assert user_response = json_response(conn, 200)
1886 assert user_response["header"] != User.banner_url(user)
1889 test "requires 'write' permission", %{conn: conn} do
1890 token1 = insert(:oauth_token, scopes: ["read"])
1891 token2 = insert(:oauth_token, scopes: ["write", "follow"])
1893 for token <- [token1, token2] do
1896 |> put_req_header("authorization", "Bearer #{token.token}")
1897 |> patch("/api/v1/accounts/update_credentials", %{})
1899 if token == token1 do
1900 assert %{"error" => "Insufficient permissions: write."} == json_response(conn, 403)
1902 assert json_response(conn, 200)
1908 test "get instance information", %{conn: conn} do
1909 conn = get(conn, "/api/v1/instance")
1910 assert result = json_response(conn, 200)
1912 # Note: not checking for "max_toot_chars" since it's optional
1920 "streaming_api" => _
1925 "registrations" => _
1929 test "get instance stats", %{conn: conn} do
1930 user = insert(:user, %{local: true})
1932 user2 = insert(:user, %{local: true})
1933 {:ok, _user2} = User.deactivate(user2, !user2.info.deactivated)
1935 insert(:user, %{local: false, nickname: "u@peer1.com"})
1936 insert(:user, %{local: false, nickname: "u@peer2.com"})
1938 {:ok, _} = TwitterAPI.create_status(user, %{"status" => "cofe"})
1940 # Stats should count users with missing or nil `info.deactivated` value
1941 user = User.get_by_id(user.id)
1942 info_change = Changeset.change(user.info, %{deactivated: nil})
1946 |> Changeset.change()
1947 |> Changeset.put_embed(:info, info_change)
1948 |> User.update_and_set_cache()
1950 Pleroma.Stats.update_stats()
1952 conn = get(conn, "/api/v1/instance")
1954 assert result = json_response(conn, 200)
1956 stats = result["stats"]
1959 assert stats["user_count"] == 1
1960 assert stats["status_count"] == 1
1961 assert stats["domain_count"] == 2
1964 test "get peers", %{conn: conn} do
1965 insert(:user, %{local: false, nickname: "u@peer1.com"})
1966 insert(:user, %{local: false, nickname: "u@peer2.com"})
1968 Pleroma.Stats.update_stats()
1970 conn = get(conn, "/api/v1/instance/peers")
1972 assert result = json_response(conn, 200)
1974 assert ["peer1.com", "peer2.com"] == Enum.sort(result)
1977 test "put settings", %{conn: conn} do
1978 user = insert(:user)
1982 |> assign(:user, user)
1983 |> put("/api/web/settings", %{"data" => %{"programming" => "socks"}})
1985 assert _result = json_response(conn, 200)
1987 user = User.get_cached_by_ap_id(user.ap_id)
1988 assert user.info.settings == %{"programming" => "socks"}
1991 describe "pinned statuses" do
1993 Pleroma.Config.put([:instance, :max_pinned_statuses], 1)
1995 user = insert(:user)
1996 {:ok, activity} = CommonAPI.post(user, %{"status" => "HI!!!"})
1998 [user: user, activity: activity]
2001 test "returns pinned statuses", %{conn: conn, user: user, activity: activity} do
2002 {:ok, _} = CommonAPI.pin(activity.id, user)
2006 |> assign(:user, user)
2007 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
2008 |> json_response(200)
2010 id_str = to_string(activity.id)
2012 assert [%{"id" => ^id_str, "pinned" => true}] = result
2015 test "pin status", %{conn: conn, user: user, activity: activity} do
2016 id_str = to_string(activity.id)
2018 assert %{"id" => ^id_str, "pinned" => true} =
2020 |> assign(:user, user)
2021 |> post("/api/v1/statuses/#{activity.id}/pin")
2022 |> json_response(200)
2024 assert [%{"id" => ^id_str, "pinned" => true}] =
2026 |> assign(:user, user)
2027 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
2028 |> json_response(200)
2031 test "unpin status", %{conn: conn, user: user, activity: activity} do
2032 {:ok, _} = CommonAPI.pin(activity.id, user)
2034 id_str = to_string(activity.id)
2035 user = refresh_record(user)
2037 assert %{"id" => ^id_str, "pinned" => false} =
2039 |> assign(:user, user)
2040 |> post("/api/v1/statuses/#{activity.id}/unpin")
2041 |> json_response(200)
2045 |> assign(:user, user)
2046 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
2047 |> json_response(200)
2050 test "max pinned statuses", %{conn: conn, user: user, activity: activity_one} do
2051 {:ok, activity_two} = CommonAPI.post(user, %{"status" => "HI!!!"})
2053 id_str_one = to_string(activity_one.id)
2055 assert %{"id" => ^id_str_one, "pinned" => true} =
2057 |> assign(:user, user)
2058 |> post("/api/v1/statuses/#{id_str_one}/pin")
2059 |> json_response(200)
2061 user = refresh_record(user)
2063 assert %{"error" => "You have already pinned the maximum number of statuses"} =
2065 |> assign(:user, user)
2066 |> post("/api/v1/statuses/#{activity_two.id}/pin")
2067 |> json_response(400)
2070 test "Status rich-media Card", %{conn: conn, user: user} do
2071 Pleroma.Config.put([:rich_media, :enabled], true)
2072 {:ok, activity} = CommonAPI.post(user, %{"status" => "http://example.com/ogp"})
2076 |> get("/api/v1/statuses/#{activity.id}/card")
2077 |> json_response(200)
2079 assert response == %{
2080 "image" => "http://ia.media-imdb.com/images/rock.jpg",
2081 "provider_name" => "www.imdb.com",
2082 "provider_url" => "http://www.imdb.com",
2083 "title" => "The Rock",
2085 "url" => "http://www.imdb.com/title/tt0117500/",
2086 "description" => nil,
2089 "image" => "http://ia.media-imdb.com/images/rock.jpg",
2090 "title" => "The Rock",
2091 "type" => "video.movie",
2092 "url" => "http://www.imdb.com/title/tt0117500/"
2097 # works with private posts
2099 CommonAPI.post(user, %{"status" => "http://example.com/ogp", "visibility" => "direct"})
2103 |> assign(:user, user)
2104 |> get("/api/v1/statuses/#{activity.id}/card")
2105 |> json_response(200)
2107 assert response_two == response
2109 Pleroma.Config.put([:rich_media, :enabled], false)
2114 user = insert(:user)
2115 for_user = insert(:user)
2118 CommonAPI.post(user, %{
2119 "status" => "heweoo?"
2123 CommonAPI.post(user, %{
2124 "status" => "heweoo!"
2129 |> assign(:user, for_user)
2130 |> post("/api/v1/statuses/#{activity1.id}/bookmark")
2132 assert json_response(response1, 200)["bookmarked"] == true
2136 |> assign(:user, for_user)
2137 |> post("/api/v1/statuses/#{activity2.id}/bookmark")
2139 assert json_response(response2, 200)["bookmarked"] == true
2143 |> assign(:user, for_user)
2144 |> get("/api/v1/bookmarks")
2146 assert [json_response(response2, 200), json_response(response1, 200)] ==
2147 json_response(bookmarks, 200)
2151 |> assign(:user, for_user)
2152 |> post("/api/v1/statuses/#{activity1.id}/unbookmark")
2154 assert json_response(response1, 200)["bookmarked"] == false
2158 |> assign(:user, for_user)
2159 |> get("/api/v1/bookmarks")
2161 assert [json_response(response2, 200)] == json_response(bookmarks, 200)
2164 describe "conversation muting" do
2166 user = insert(:user)
2167 {:ok, activity} = CommonAPI.post(user, %{"status" => "HIE"})
2169 [user: user, activity: activity]
2172 test "mute conversation", %{conn: conn, user: user, activity: activity} do
2173 id_str = to_string(activity.id)
2175 assert %{"id" => ^id_str, "muted" => true} =
2177 |> assign(:user, user)
2178 |> post("/api/v1/statuses/#{activity.id}/mute")
2179 |> json_response(200)
2182 test "unmute conversation", %{conn: conn, user: user, activity: activity} do
2183 {:ok, _} = CommonAPI.add_mute(user, activity)
2185 id_str = to_string(activity.id)
2186 user = refresh_record(user)
2188 assert %{"id" => ^id_str, "muted" => false} =
2190 |> assign(:user, user)
2191 |> post("/api/v1/statuses/#{activity.id}/unmute")
2192 |> json_response(200)
2196 test "flavours switching (Pleroma Extension)", %{conn: conn} do
2197 user = insert(:user)
2201 |> assign(:user, user)
2202 |> get("/api/v1/pleroma/flavour")
2204 assert "glitch" == json_response(get_old_flavour, 200)
2208 |> assign(:user, user)
2209 |> post("/api/v1/pleroma/flavour/vanilla")
2211 assert "vanilla" == json_response(set_flavour, 200)
2215 |> assign(:user, user)
2216 |> post("/api/v1/pleroma/flavour/vanilla")
2218 assert json_response(set_flavour, 200) == json_response(get_new_flavour, 200)
2221 describe "reports" do
2223 reporter = insert(:user)
2224 target_user = insert(:user)
2226 {:ok, activity} = CommonAPI.post(target_user, %{"status" => "foobar"})
2228 [reporter: reporter, target_user: target_user, activity: activity]
2231 test "submit a basic report", %{conn: conn, reporter: reporter, target_user: target_user} do
2232 assert %{"action_taken" => false, "id" => _} =
2234 |> assign(:user, reporter)
2235 |> post("/api/v1/reports", %{"account_id" => target_user.id})
2236 |> json_response(200)
2239 test "submit a report with statuses and comment", %{
2242 target_user: target_user,
2245 assert %{"action_taken" => false, "id" => _} =
2247 |> assign(:user, reporter)
2248 |> post("/api/v1/reports", %{
2249 "account_id" => target_user.id,
2250 "status_ids" => [activity.id],
2251 "comment" => "bad status!"
2253 |> json_response(200)
2256 test "account_id is required", %{
2261 assert %{"error" => "Valid `account_id` required"} =
2263 |> assign(:user, reporter)
2264 |> post("/api/v1/reports", %{"status_ids" => [activity.id]})
2265 |> json_response(400)
2268 test "comment must be up to the size specified in the config", %{
2271 target_user: target_user
2273 max_size = Pleroma.Config.get([:instance, :max_report_comment_size], 1000)
2274 comment = String.pad_trailing("a", max_size + 1, "a")
2276 error = %{"error" => "Comment must be up to #{max_size} characters"}
2280 |> assign(:user, reporter)
2281 |> post("/api/v1/reports", %{"account_id" => target_user.id, "comment" => comment})
2282 |> json_response(400)
2286 describe "link headers" do
2287 test "preserves parameters in link headers", %{conn: conn} do
2288 user = insert(:user)
2289 other_user = insert(:user)
2292 CommonAPI.post(other_user, %{
2293 "status" => "hi @#{user.nickname}",
2294 "visibility" => "public"
2298 CommonAPI.post(other_user, %{
2299 "status" => "hi @#{user.nickname}",
2300 "visibility" => "public"
2303 notification1 = Repo.get_by(Notification, activity_id: activity1.id)
2304 notification2 = Repo.get_by(Notification, activity_id: activity2.id)
2308 |> assign(:user, user)
2309 |> get("/api/v1/notifications", %{media_only: true})
2311 assert [link_header] = get_resp_header(conn, "link")
2312 assert link_header =~ ~r/media_only=true/
2313 assert link_header =~ ~r/since_id=#{notification2.id}/
2314 assert link_header =~ ~r/max_id=#{notification1.id}/
2318 test "accounts fetches correct account for nicknames beginning with numbers", %{conn: conn} do
2319 # Need to set an old-style integer ID to reproduce the problem
2320 # (these are no longer assigned to new accounts but were preserved
2321 # for existing accounts during the migration to flakeIDs)
2322 user_one = insert(:user, %{id: 1212})
2323 user_two = insert(:user, %{nickname: "#{user_one.id}garbage"})
2327 |> get("/api/v1/accounts/#{user_one.id}")
2331 |> get("/api/v1/accounts/#{user_two.nickname}")
2335 |> get("/api/v1/accounts/#{user_two.id}")
2337 acc_one = json_response(resp_one, 200)
2338 acc_two = json_response(resp_two, 200)
2339 acc_three = json_response(resp_three, 200)
2340 refute acc_one == acc_two
2341 assert acc_two == acc_three
2344 describe "index/2 redirections" do
2345 setup %{conn: conn} do
2349 signing_salt: "cooldude"
2354 |> Plug.Session.call(Plug.Session.init(session_opts))
2357 test_path = "/web/statuses/test"
2358 %{conn: conn, path: test_path}
2361 test "redirects not logged-in users to the login page", %{conn: conn, path: path} do
2362 conn = get(conn, path)
2364 assert conn.status == 302
2365 assert redirected_to(conn) == "/web/login"
2368 test "does not redirect logged in users to the login page", %{conn: conn, path: path} do
2369 token = insert(:oauth_token)
2373 |> assign(:user, token.user)
2374 |> put_session(:oauth_token, token.token)
2377 assert conn.status == 200
2380 test "saves referer path to session", %{conn: conn, path: path} do
2381 conn = get(conn, path)
2382 return_to = Plug.Conn.get_session(conn, :return_to)
2384 assert return_to == path
2387 test "redirects to the saved path after log in", %{conn: conn, path: path} do
2388 app = insert(:oauth_app, client_name: "Mastodon-Local", redirect_uris: ".")
2389 auth = insert(:oauth_authorization, app: app)
2393 |> put_session(:return_to, path)
2394 |> get("/web/login", %{code: auth.token})
2396 assert conn.status == 302
2397 assert redirected_to(conn) == path
2400 test "redirects to the getting-started page when referer is not present", %{conn: conn} do
2401 app = insert(:oauth_app, client_name: "Mastodon-Local", redirect_uris: ".")
2402 auth = insert(:oauth_authorization, app: app)
2404 conn = get(conn, "/web/login", %{code: auth.token})
2406 assert conn.status == 302
2407 assert redirected_to(conn) == "/web/getting-started"