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
13 alias Pleroma.ScheduledActivity
15 alias Pleroma.Web.ActivityPub.ActivityPub
16 alias Pleroma.Web.CommonAPI
17 alias Pleroma.Web.MastodonAPI.FilterView
18 alias Pleroma.Web.OAuth.App
19 alias Pleroma.Web.OStatus
20 alias Pleroma.Web.Push
21 alias Pleroma.Web.TwitterAPI.TwitterAPI
22 import Pleroma.Factory
23 import ExUnit.CaptureLog
27 mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
31 test "the home timeline", %{conn: conn} do
33 following = insert(:user)
35 {:ok, _activity} = TwitterAPI.create_status(following, %{"status" => "test"})
39 |> assign(:user, user)
40 |> get("/api/v1/timelines/home")
42 assert Enum.empty?(json_response(conn, 200))
44 {:ok, user} = User.follow(user, following)
48 |> assign(:user, user)
49 |> get("/api/v1/timelines/home")
51 assert [%{"content" => "test"}] = json_response(conn, 200)
54 test "the public timeline", %{conn: conn} do
55 following = insert(:user)
58 {:ok, _activity} = TwitterAPI.create_status(following, %{"status" => "test"})
61 OStatus.fetch_activity_from_url("https://shitposter.club/notice/2827873")
65 |> get("/api/v1/timelines/public", %{"local" => "False"})
67 assert length(json_response(conn, 200)) == 2
71 |> get("/api/v1/timelines/public", %{"local" => "True"})
73 assert [%{"content" => "test"}] = json_response(conn, 200)
77 |> get("/api/v1/timelines/public", %{"local" => "1"})
79 assert [%{"content" => "test"}] = json_response(conn, 200)
83 test "posting a status", %{conn: conn} do
86 idempotency_key = "Pikachu rocks!"
90 |> assign(:user, user)
91 |> put_req_header("idempotency-key", idempotency_key)
92 |> post("/api/v1/statuses", %{
94 "spoiler_text" => "2hu",
95 "sensitive" => "false"
98 {:ok, ttl} = Cachex.ttl(:idempotency_cache, idempotency_key)
100 assert ttl > :timer.seconds(6 * 60 * 60 - 1)
102 assert %{"content" => "cofe", "id" => id, "spoiler_text" => "2hu", "sensitive" => false} =
103 json_response(conn_one, 200)
105 assert Activity.get_by_id(id)
109 |> assign(:user, user)
110 |> put_req_header("idempotency-key", idempotency_key)
111 |> post("/api/v1/statuses", %{
113 "spoiler_text" => "2hu",
114 "sensitive" => "false"
117 assert %{"id" => second_id} = json_response(conn_two, 200)
119 assert id == second_id
123 |> assign(:user, user)
124 |> post("/api/v1/statuses", %{
126 "spoiler_text" => "2hu",
127 "sensitive" => "false"
130 assert %{"id" => third_id} = json_response(conn_three, 200)
132 refute id == third_id
135 test "posting a sensitive status", %{conn: conn} do
140 |> assign(:user, user)
141 |> post("/api/v1/statuses", %{"status" => "cofe", "sensitive" => true})
143 assert %{"content" => "cofe", "id" => id, "sensitive" => true} = json_response(conn, 200)
144 assert Activity.get_by_id(id)
147 test "posting a fake status", %{conn: conn} do
152 |> assign(:user, user)
153 |> post("/api/v1/statuses", %{
155 "\"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"
158 real_status = json_response(real_conn, 200)
161 assert Object.get_by_ap_id(real_status["uri"])
165 |> Map.put("id", nil)
166 |> Map.put("url", nil)
167 |> Map.put("uri", nil)
168 |> Map.put("created_at", nil)
169 |> Kernel.put_in(["pleroma", "conversation_id"], nil)
173 |> assign(:user, user)
174 |> post("/api/v1/statuses", %{
176 "\"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",
180 fake_status = json_response(fake_conn, 200)
183 refute Object.get_by_ap_id(fake_status["uri"])
187 |> Map.put("id", nil)
188 |> Map.put("url", nil)
189 |> Map.put("uri", nil)
190 |> Map.put("created_at", nil)
191 |> Kernel.put_in(["pleroma", "conversation_id"], nil)
193 assert real_status == fake_status
196 test "posting a status with OGP link preview", %{conn: conn} do
197 Pleroma.Config.put([:rich_media, :enabled], true)
202 |> assign(:user, user)
203 |> post("/api/v1/statuses", %{
204 "status" => "http://example.com/ogp"
207 assert %{"id" => id, "card" => %{"title" => "The Rock"}} = json_response(conn, 200)
208 assert Activity.get_by_id(id)
209 Pleroma.Config.put([:rich_media, :enabled], false)
212 test "posting a direct status", %{conn: conn} do
213 user1 = insert(:user)
214 user2 = insert(:user)
215 content = "direct cofe @#{user2.nickname}"
219 |> assign(:user, user1)
220 |> post("api/v1/statuses", %{"status" => content, "visibility" => "direct"})
222 assert %{"id" => id, "visibility" => "direct"} = json_response(conn, 200)
223 assert activity = Activity.get_by_id(id)
224 assert activity.recipients == [user2.ap_id, user1.ap_id]
225 assert activity.data["to"] == [user2.ap_id]
226 assert activity.data["cc"] == []
229 test "direct timeline", %{conn: conn} do
230 user_one = insert(:user)
231 user_two = insert(:user)
233 {:ok, user_two} = User.follow(user_two, user_one)
236 CommonAPI.post(user_one, %{
237 "status" => "Hi @#{user_two.nickname}!",
238 "visibility" => "direct"
241 {:ok, _follower_only} =
242 CommonAPI.post(user_one, %{
243 "status" => "Hi @#{user_two.nickname}!",
244 "visibility" => "private"
247 # Only direct should be visible here
250 |> assign(:user, user_two)
251 |> get("api/v1/timelines/direct")
253 [status] = json_response(res_conn, 200)
255 assert %{"visibility" => "direct"} = status
256 assert status["url"] != direct.data["id"]
258 # User should be able to see his own direct message
261 |> assign(:user, user_one)
262 |> get("api/v1/timelines/direct")
264 [status] = json_response(res_conn, 200)
266 assert %{"visibility" => "direct"} = status
268 # Both should be visible here
271 |> assign(:user, user_two)
272 |> get("api/v1/timelines/home")
274 [_s1, _s2] = json_response(res_conn, 200)
277 Enum.each(1..20, fn _ ->
279 CommonAPI.post(user_one, %{
280 "status" => "Hi @#{user_two.nickname}!",
281 "visibility" => "direct"
287 |> assign(:user, user_two)
288 |> get("api/v1/timelines/direct")
290 statuses = json_response(res_conn, 200)
291 assert length(statuses) == 20
295 |> assign(:user, user_two)
296 |> get("api/v1/timelines/direct", %{max_id: List.last(statuses)["id"]})
298 [status] = json_response(res_conn, 200)
300 assert status["url"] != direct.data["id"]
303 test "Conversations", %{conn: conn} do
304 user_one = insert(:user)
305 user_two = insert(:user)
307 {:ok, user_two} = User.follow(user_two, user_one)
310 CommonAPI.post(user_one, %{
311 "status" => "Hi @#{user_two.nickname}!",
312 "visibility" => "direct"
315 {:ok, _follower_only} =
316 CommonAPI.post(user_one, %{
317 "status" => "Hi @#{user_two.nickname}!",
318 "visibility" => "private"
323 |> assign(:user, user_one)
324 |> get("/api/v1/conversations")
326 assert response = json_response(res_conn, 200)
331 "accounts" => res_accounts,
332 "last_status" => res_last_status,
337 assert length(res_accounts) == 2
338 assert is_binary(res_id)
339 assert unread == true
340 assert res_last_status["id"] == direct.id
342 # Apparently undocumented API endpoint
345 |> assign(:user, user_one)
346 |> post("/api/v1/conversations/#{res_id}/read")
348 assert response = json_response(res_conn, 200)
349 assert length(response["accounts"]) == 2
350 assert response["last_status"]["id"] == direct.id
351 assert response["unread"] == false
353 # (vanilla) Mastodon frontend behaviour
356 |> assign(:user, user_one)
357 |> get("/api/v1/statuses/#{res_last_status["id"]}/context")
359 assert %{"ancestors" => [], "descendants" => []} == json_response(res_conn, 200)
362 test "doesn't include DMs from blocked users", %{conn: conn} do
363 blocker = insert(:user)
364 blocked = insert(:user)
366 {:ok, blocker} = User.block(blocker, blocked)
368 {:ok, _blocked_direct} =
369 CommonAPI.post(blocked, %{
370 "status" => "Hi @#{blocker.nickname}!",
371 "visibility" => "direct"
375 CommonAPI.post(user, %{
376 "status" => "Hi @#{blocker.nickname}!",
377 "visibility" => "direct"
382 |> assign(:user, user)
383 |> get("api/v1/timelines/direct")
385 [status] = json_response(res_conn, 200)
386 assert status["id"] == direct.id
389 test "replying to a status", %{conn: conn} do
392 {:ok, replied_to} = TwitterAPI.create_status(user, %{"status" => "cofe"})
396 |> assign(:user, user)
397 |> post("/api/v1/statuses", %{"status" => "xD", "in_reply_to_id" => replied_to.id})
399 assert %{"content" => "xD", "id" => id} = json_response(conn, 200)
401 activity = Activity.get_by_id(id)
403 assert activity.data["context"] == replied_to.data["context"]
404 assert Activity.get_in_reply_to_activity(activity).id == replied_to.id
407 test "posting a status with an invalid in_reply_to_id", %{conn: conn} do
412 |> assign(:user, user)
413 |> post("/api/v1/statuses", %{"status" => "xD", "in_reply_to_id" => ""})
415 assert %{"content" => "xD", "id" => id} = json_response(conn, 200)
417 activity = Activity.get_by_id(id)
422 test "verify_credentials", %{conn: conn} do
427 |> assign(:user, user)
428 |> get("/api/v1/accounts/verify_credentials")
430 assert %{"id" => id, "source" => %{"privacy" => "public"}} = json_response(conn, 200)
431 assert id == to_string(user.id)
434 test "verify_credentials default scope unlisted", %{conn: conn} do
435 user = insert(:user, %{info: %Pleroma.User.Info{default_scope: "unlisted"}})
439 |> assign(:user, user)
440 |> get("/api/v1/accounts/verify_credentials")
442 assert %{"id" => id, "source" => %{"privacy" => "unlisted"}} = json_response(conn, 200)
443 assert id == to_string(user.id)
446 test "apps/verify_credentials", %{conn: conn} do
447 token = insert(:oauth_token)
451 |> assign(:user, token.user)
452 |> assign(:token, token)
453 |> get("/api/v1/apps/verify_credentials")
455 app = Repo.preload(token, :app).app
458 "name" => app.client_name,
459 "website" => app.website,
460 "vapid_key" => Push.vapid_config() |> Keyword.get(:public_key)
463 assert expected == json_response(conn, 200)
466 test "creates an oauth app", %{conn: conn} do
468 app_attrs = build(:oauth_app)
472 |> assign(:user, user)
473 |> post("/api/v1/apps", %{
474 client_name: app_attrs.client_name,
475 redirect_uris: app_attrs.redirect_uris
478 [app] = Repo.all(App)
481 "name" => app.client_name,
482 "website" => app.website,
483 "client_id" => app.client_id,
484 "client_secret" => app.client_secret,
485 "id" => app.id |> to_string(),
486 "redirect_uri" => app.redirect_uris,
487 "vapid_key" => Push.vapid_config() |> Keyword.get(:public_key)
490 assert expected == json_response(conn, 200)
493 test "get a status", %{conn: conn} do
494 activity = insert(:note_activity)
498 |> get("/api/v1/statuses/#{activity.id}")
500 assert %{"id" => id} = json_response(conn, 200)
501 assert id == to_string(activity.id)
504 describe "deleting a status" do
505 test "when you created it", %{conn: conn} do
506 activity = insert(:note_activity)
507 author = User.get_cached_by_ap_id(activity.data["actor"])
511 |> assign(:user, author)
512 |> delete("/api/v1/statuses/#{activity.id}")
514 assert %{} = json_response(conn, 200)
516 refute Activity.get_by_id(activity.id)
519 test "when you didn't create it", %{conn: conn} do
520 activity = insert(:note_activity)
525 |> assign(:user, user)
526 |> delete("/api/v1/statuses/#{activity.id}")
528 assert %{"error" => _} = json_response(conn, 403)
530 assert Activity.get_by_id(activity.id) == activity
533 test "when you're an admin or moderator", %{conn: conn} do
534 activity1 = insert(:note_activity)
535 activity2 = insert(:note_activity)
536 admin = insert(:user, info: %{is_admin: true})
537 moderator = insert(:user, info: %{is_moderator: true})
541 |> assign(:user, admin)
542 |> delete("/api/v1/statuses/#{activity1.id}")
544 assert %{} = json_response(res_conn, 200)
548 |> assign(:user, moderator)
549 |> delete("/api/v1/statuses/#{activity2.id}")
551 assert %{} = json_response(res_conn, 200)
553 refute Activity.get_by_id(activity1.id)
554 refute Activity.get_by_id(activity2.id)
558 describe "filters" do
559 test "creating a filter", %{conn: conn} do
562 filter = %Pleroma.Filter{
569 |> assign(:user, user)
570 |> post("/api/v1/filters", %{"phrase" => filter.phrase, context: filter.context})
572 assert response = json_response(conn, 200)
573 assert response["phrase"] == filter.phrase
574 assert response["context"] == filter.context
575 assert response["id"] != nil
576 assert response["id"] != ""
579 test "fetching a list of filters", %{conn: conn} do
582 query_one = %Pleroma.Filter{
589 query_two = %Pleroma.Filter{
596 {:ok, filter_one} = Pleroma.Filter.create(query_one)
597 {:ok, filter_two} = Pleroma.Filter.create(query_two)
601 |> assign(:user, user)
602 |> get("/api/v1/filters")
603 |> json_response(200)
609 filters: [filter_two, filter_one]
613 test "get a filter", %{conn: conn} do
616 query = %Pleroma.Filter{
623 {:ok, filter} = Pleroma.Filter.create(query)
627 |> assign(:user, user)
628 |> get("/api/v1/filters/#{filter.filter_id}")
630 assert _response = json_response(conn, 200)
633 test "update a filter", %{conn: conn} do
636 query = %Pleroma.Filter{
643 {:ok, _filter} = Pleroma.Filter.create(query)
645 new = %Pleroma.Filter{
652 |> assign(:user, user)
653 |> put("/api/v1/filters/#{query.filter_id}", %{
658 assert response = json_response(conn, 200)
659 assert response["phrase"] == new.phrase
660 assert response["context"] == new.context
663 test "delete a filter", %{conn: conn} do
666 query = %Pleroma.Filter{
673 {:ok, filter} = Pleroma.Filter.create(query)
677 |> assign(:user, user)
678 |> delete("/api/v1/filters/#{filter.filter_id}")
680 assert response = json_response(conn, 200)
681 assert response == %{}
686 test "creating a list", %{conn: conn} do
691 |> assign(:user, user)
692 |> post("/api/v1/lists", %{"title" => "cuties"})
694 assert %{"title" => title} = json_response(conn, 200)
695 assert title == "cuties"
698 test "adding users to a list", %{conn: conn} do
700 other_user = insert(:user)
701 {:ok, list} = Pleroma.List.create("name", user)
705 |> assign(:user, user)
706 |> post("/api/v1/lists/#{list.id}/accounts", %{"account_ids" => [other_user.id]})
708 assert %{} == json_response(conn, 200)
709 %Pleroma.List{following: following} = Pleroma.List.get(list.id, user)
710 assert following == [other_user.follower_address]
713 test "removing users from a list", %{conn: conn} do
715 other_user = insert(:user)
716 third_user = insert(:user)
717 {:ok, list} = Pleroma.List.create("name", user)
718 {:ok, list} = Pleroma.List.follow(list, other_user)
719 {:ok, list} = Pleroma.List.follow(list, third_user)
723 |> assign(:user, user)
724 |> delete("/api/v1/lists/#{list.id}/accounts", %{"account_ids" => [other_user.id]})
726 assert %{} == json_response(conn, 200)
727 %Pleroma.List{following: following} = Pleroma.List.get(list.id, user)
728 assert following == [third_user.follower_address]
731 test "listing users in a list", %{conn: conn} do
733 other_user = insert(:user)
734 {:ok, list} = Pleroma.List.create("name", user)
735 {:ok, list} = Pleroma.List.follow(list, other_user)
739 |> assign(:user, user)
740 |> get("/api/v1/lists/#{list.id}/accounts", %{"account_ids" => [other_user.id]})
742 assert [%{"id" => id}] = json_response(conn, 200)
743 assert id == to_string(other_user.id)
746 test "retrieving a list", %{conn: conn} do
748 {:ok, list} = Pleroma.List.create("name", user)
752 |> assign(:user, user)
753 |> get("/api/v1/lists/#{list.id}")
755 assert %{"id" => id} = json_response(conn, 200)
756 assert id == to_string(list.id)
759 test "renaming a list", %{conn: conn} do
761 {:ok, list} = Pleroma.List.create("name", user)
765 |> assign(:user, user)
766 |> put("/api/v1/lists/#{list.id}", %{"title" => "newname"})
768 assert %{"title" => name} = json_response(conn, 200)
769 assert name == "newname"
772 test "deleting a list", %{conn: conn} do
774 {:ok, list} = Pleroma.List.create("name", user)
778 |> assign(:user, user)
779 |> delete("/api/v1/lists/#{list.id}")
781 assert %{} = json_response(conn, 200)
782 assert is_nil(Repo.get(Pleroma.List, list.id))
785 test "list timeline", %{conn: conn} do
787 other_user = insert(:user)
788 {:ok, _activity_one} = TwitterAPI.create_status(user, %{"status" => "Marisa is cute."})
789 {:ok, activity_two} = TwitterAPI.create_status(other_user, %{"status" => "Marisa is cute."})
790 {:ok, list} = Pleroma.List.create("name", user)
791 {:ok, list} = Pleroma.List.follow(list, other_user)
795 |> assign(:user, user)
796 |> get("/api/v1/timelines/list/#{list.id}")
798 assert [%{"id" => id}] = json_response(conn, 200)
800 assert id == to_string(activity_two.id)
803 test "list timeline does not leak non-public statuses for unfollowed users", %{conn: conn} do
805 other_user = insert(:user)
806 {:ok, activity_one} = TwitterAPI.create_status(other_user, %{"status" => "Marisa is cute."})
808 {:ok, _activity_two} =
809 TwitterAPI.create_status(other_user, %{
810 "status" => "Marisa is cute.",
811 "visibility" => "private"
814 {:ok, list} = Pleroma.List.create("name", user)
815 {:ok, list} = Pleroma.List.follow(list, other_user)
819 |> assign(:user, user)
820 |> get("/api/v1/timelines/list/#{list.id}")
822 assert [%{"id" => id}] = json_response(conn, 200)
824 assert id == to_string(activity_one.id)
828 describe "notifications" do
829 test "list of notifications", %{conn: conn} do
831 other_user = insert(:user)
834 TwitterAPI.create_status(other_user, %{"status" => "hi @#{user.nickname}"})
836 {:ok, [_notification]} = Notification.create_notifications(activity)
840 |> assign(:user, user)
841 |> get("/api/v1/notifications")
844 "hi <span class=\"h-card\"><a data-user=\"#{user.id}\" class=\"u-url mention\" href=\"#{
846 }\">@<span>#{user.nickname}</span></a></span>"
848 assert [%{"status" => %{"content" => response}} | _rest] = json_response(conn, 200)
849 assert response == expected_response
852 test "getting a single notification", %{conn: conn} do
854 other_user = insert(:user)
857 TwitterAPI.create_status(other_user, %{"status" => "hi @#{user.nickname}"})
859 {:ok, [notification]} = Notification.create_notifications(activity)
863 |> assign(:user, user)
864 |> get("/api/v1/notifications/#{notification.id}")
867 "hi <span class=\"h-card\"><a data-user=\"#{user.id}\" class=\"u-url mention\" href=\"#{
869 }\">@<span>#{user.nickname}</span></a></span>"
871 assert %{"status" => %{"content" => response}} = json_response(conn, 200)
872 assert response == expected_response
875 test "dismissing a single notification", %{conn: conn} do
877 other_user = insert(:user)
880 TwitterAPI.create_status(other_user, %{"status" => "hi @#{user.nickname}"})
882 {:ok, [notification]} = Notification.create_notifications(activity)
886 |> assign(:user, user)
887 |> post("/api/v1/notifications/dismiss", %{"id" => notification.id})
889 assert %{} = json_response(conn, 200)
892 test "clearing all notifications", %{conn: conn} do
894 other_user = insert(:user)
897 TwitterAPI.create_status(other_user, %{"status" => "hi @#{user.nickname}"})
899 {:ok, [_notification]} = Notification.create_notifications(activity)
903 |> assign(:user, user)
904 |> post("/api/v1/notifications/clear")
906 assert %{} = json_response(conn, 200)
910 |> assign(:user, user)
911 |> get("/api/v1/notifications")
913 assert all = json_response(conn, 200)
917 test "paginates notifications using min_id, since_id, max_id, and limit", %{conn: conn} do
919 other_user = insert(:user)
921 {:ok, activity1} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
922 {:ok, activity2} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
923 {:ok, activity3} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
924 {:ok, activity4} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
926 notification1_id = Repo.get_by(Notification, activity_id: activity1.id).id |> to_string()
927 notification2_id = Repo.get_by(Notification, activity_id: activity2.id).id |> to_string()
928 notification3_id = Repo.get_by(Notification, activity_id: activity3.id).id |> to_string()
929 notification4_id = Repo.get_by(Notification, activity_id: activity4.id).id |> to_string()
933 |> assign(:user, user)
938 |> get("/api/v1/notifications?limit=2&min_id=#{notification1_id}")
940 result = json_response(conn_res, 200)
941 assert [%{"id" => ^notification3_id}, %{"id" => ^notification2_id}] = result
946 |> get("/api/v1/notifications?limit=2&since_id=#{notification1_id}")
948 result = json_response(conn_res, 200)
949 assert [%{"id" => ^notification4_id}, %{"id" => ^notification3_id}] = result
954 |> get("/api/v1/notifications?limit=2&max_id=#{notification4_id}")
956 result = json_response(conn_res, 200)
957 assert [%{"id" => ^notification3_id}, %{"id" => ^notification2_id}] = result
960 test "filters notifications using exclude_types", %{conn: conn} do
962 other_user = insert(:user)
964 {:ok, mention_activity} = CommonAPI.post(other_user, %{"status" => "hey @#{user.nickname}"})
965 {:ok, create_activity} = CommonAPI.post(user, %{"status" => "hey"})
966 {:ok, favorite_activity, _} = CommonAPI.favorite(create_activity.id, other_user)
967 {:ok, reblog_activity, _} = CommonAPI.repeat(create_activity.id, other_user)
968 {:ok, _, _, follow_activity} = CommonAPI.follow(other_user, user)
970 mention_notification_id =
971 Repo.get_by(Notification, activity_id: mention_activity.id).id |> to_string()
973 favorite_notification_id =
974 Repo.get_by(Notification, activity_id: favorite_activity.id).id |> to_string()
976 reblog_notification_id =
977 Repo.get_by(Notification, activity_id: reblog_activity.id).id |> to_string()
979 follow_notification_id =
980 Repo.get_by(Notification, activity_id: follow_activity.id).id |> to_string()
984 |> assign(:user, user)
987 get(conn, "/api/v1/notifications", %{exclude_types: ["mention", "favourite", "reblog"]})
989 assert [%{"id" => ^follow_notification_id}] = json_response(conn_res, 200)
992 get(conn, "/api/v1/notifications", %{exclude_types: ["favourite", "reblog", "follow"]})
994 assert [%{"id" => ^mention_notification_id}] = json_response(conn_res, 200)
997 get(conn, "/api/v1/notifications", %{exclude_types: ["reblog", "follow", "mention"]})
999 assert [%{"id" => ^favorite_notification_id}] = json_response(conn_res, 200)
1002 get(conn, "/api/v1/notifications", %{exclude_types: ["follow", "mention", "favourite"]})
1004 assert [%{"id" => ^reblog_notification_id}] = json_response(conn_res, 200)
1007 test "destroy multiple", %{conn: conn} do
1008 user = insert(:user)
1009 other_user = insert(:user)
1011 {:ok, activity1} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
1012 {:ok, activity2} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
1013 {:ok, activity3} = CommonAPI.post(user, %{"status" => "hi @#{other_user.nickname}"})
1014 {:ok, activity4} = CommonAPI.post(user, %{"status" => "hi @#{other_user.nickname}"})
1016 notification1_id = Repo.get_by(Notification, activity_id: activity1.id).id |> to_string()
1017 notification2_id = Repo.get_by(Notification, activity_id: activity2.id).id |> to_string()
1018 notification3_id = Repo.get_by(Notification, activity_id: activity3.id).id |> to_string()
1019 notification4_id = Repo.get_by(Notification, activity_id: activity4.id).id |> to_string()
1023 |> assign(:user, user)
1027 |> get("/api/v1/notifications")
1029 result = json_response(conn_res, 200)
1030 assert [%{"id" => ^notification2_id}, %{"id" => ^notification1_id}] = result
1034 |> assign(:user, other_user)
1038 |> get("/api/v1/notifications")
1040 result = json_response(conn_res, 200)
1041 assert [%{"id" => ^notification4_id}, %{"id" => ^notification3_id}] = result
1045 |> delete("/api/v1/notifications/destroy_multiple", %{
1046 "ids" => [notification1_id, notification2_id]
1049 assert json_response(conn_destroy, 200) == %{}
1053 |> get("/api/v1/notifications")
1055 result = json_response(conn_res, 200)
1056 assert [%{"id" => ^notification4_id}, %{"id" => ^notification3_id}] = result
1060 describe "reblogging" do
1061 test "reblogs and returns the reblogged status", %{conn: conn} do
1062 activity = insert(:note_activity)
1063 user = insert(:user)
1067 |> assign(:user, user)
1068 |> post("/api/v1/statuses/#{activity.id}/reblog")
1071 "reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 1},
1073 } = json_response(conn, 200)
1075 assert to_string(activity.id) == id
1078 test "reblogged status for another user", %{conn: conn} do
1079 activity = insert(:note_activity)
1080 user1 = insert(:user)
1081 user2 = insert(:user)
1082 user3 = insert(:user)
1083 CommonAPI.favorite(activity.id, user2)
1084 {:ok, _bookmark} = Pleroma.Bookmark.create(user2.id, activity.id)
1085 {:ok, reblog_activity1, _object} = CommonAPI.repeat(activity.id, user1)
1086 {:ok, _, _object} = CommonAPI.repeat(activity.id, user2)
1090 |> assign(:user, user3)
1091 |> get("/api/v1/statuses/#{reblog_activity1.id}")
1094 "reblog" => %{"id" => id, "reblogged" => false, "reblogs_count" => 2},
1095 "reblogged" => false,
1096 "favourited" => false,
1097 "bookmarked" => false
1098 } = json_response(conn_res, 200)
1102 |> assign(:user, user2)
1103 |> get("/api/v1/statuses/#{reblog_activity1.id}")
1106 "reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 2},
1107 "reblogged" => true,
1108 "favourited" => true,
1109 "bookmarked" => true
1110 } = json_response(conn_res, 200)
1112 assert to_string(activity.id) == id
1116 describe "unreblogging" do
1117 test "unreblogs and returns the unreblogged status", %{conn: conn} do
1118 activity = insert(:note_activity)
1119 user = insert(:user)
1121 {:ok, _, _} = CommonAPI.repeat(activity.id, user)
1125 |> assign(:user, user)
1126 |> post("/api/v1/statuses/#{activity.id}/unreblog")
1128 assert %{"id" => id, "reblogged" => false, "reblogs_count" => 0} = json_response(conn, 200)
1130 assert to_string(activity.id) == id
1134 describe "favoriting" do
1135 test "favs a status and returns it", %{conn: conn} do
1136 activity = insert(:note_activity)
1137 user = insert(:user)
1141 |> assign(:user, user)
1142 |> post("/api/v1/statuses/#{activity.id}/favourite")
1144 assert %{"id" => id, "favourites_count" => 1, "favourited" => true} =
1145 json_response(conn, 200)
1147 assert to_string(activity.id) == id
1150 test "returns 500 for a wrong id", %{conn: conn} do
1151 user = insert(:user)
1155 |> assign(:user, user)
1156 |> post("/api/v1/statuses/1/favourite")
1157 |> json_response(500)
1159 assert resp == "Something went wrong"
1163 describe "unfavoriting" do
1164 test "unfavorites a status and returns it", %{conn: conn} do
1165 activity = insert(:note_activity)
1166 user = insert(:user)
1168 {:ok, _, _} = CommonAPI.favorite(activity.id, user)
1172 |> assign(:user, user)
1173 |> post("/api/v1/statuses/#{activity.id}/unfavourite")
1175 assert %{"id" => id, "favourites_count" => 0, "favourited" => false} =
1176 json_response(conn, 200)
1178 assert to_string(activity.id) == id
1182 describe "user timelines" do
1183 test "gets a users statuses", %{conn: conn} do
1184 user_one = insert(:user)
1185 user_two = insert(:user)
1186 user_three = insert(:user)
1188 {:ok, user_three} = User.follow(user_three, user_one)
1190 {:ok, activity} = CommonAPI.post(user_one, %{"status" => "HI!!!"})
1192 {:ok, direct_activity} =
1193 CommonAPI.post(user_one, %{
1194 "status" => "Hi, @#{user_two.nickname}.",
1195 "visibility" => "direct"
1198 {:ok, private_activity} =
1199 CommonAPI.post(user_one, %{"status" => "private", "visibility" => "private"})
1203 |> get("/api/v1/accounts/#{user_one.id}/statuses")
1205 assert [%{"id" => id}] = json_response(resp, 200)
1206 assert id == to_string(activity.id)
1210 |> assign(:user, user_two)
1211 |> get("/api/v1/accounts/#{user_one.id}/statuses")
1213 assert [%{"id" => id_one}, %{"id" => id_two}] = json_response(resp, 200)
1214 assert id_one == to_string(direct_activity.id)
1215 assert id_two == to_string(activity.id)
1219 |> assign(:user, user_three)
1220 |> get("/api/v1/accounts/#{user_one.id}/statuses")
1222 assert [%{"id" => id_one}, %{"id" => id_two}] = json_response(resp, 200)
1223 assert id_one == to_string(private_activity.id)
1224 assert id_two == to_string(activity.id)
1227 test "unimplemented pinned statuses feature", %{conn: conn} do
1228 note = insert(:note_activity)
1229 user = User.get_cached_by_ap_id(note.data["actor"])
1233 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
1235 assert json_response(conn, 200) == []
1238 test "gets an users media", %{conn: conn} do
1239 note = insert(:note_activity)
1240 user = User.get_cached_by_ap_id(note.data["actor"])
1242 file = %Plug.Upload{
1243 content_type: "image/jpg",
1244 path: Path.absname("test/fixtures/image.jpg"),
1245 filename: "an_image.jpg"
1249 TwitterAPI.upload(file, user, "json")
1253 TwitterAPI.create_status(user, %{"status" => "cofe", "media_ids" => [media["media_id"]]})
1257 |> get("/api/v1/accounts/#{user.id}/statuses", %{"only_media" => "true"})
1259 assert [%{"id" => id}] = json_response(conn, 200)
1260 assert id == to_string(image_post.id)
1264 |> get("/api/v1/accounts/#{user.id}/statuses", %{"only_media" => "1"})
1266 assert [%{"id" => id}] = json_response(conn, 200)
1267 assert id == to_string(image_post.id)
1270 test "gets a user's statuses without reblogs", %{conn: conn} do
1271 user = insert(:user)
1272 {:ok, post} = CommonAPI.post(user, %{"status" => "HI!!!"})
1273 {:ok, _, _} = CommonAPI.repeat(post.id, user)
1277 |> get("/api/v1/accounts/#{user.id}/statuses", %{"exclude_reblogs" => "true"})
1279 assert [%{"id" => id}] = json_response(conn, 200)
1280 assert id == to_string(post.id)
1284 |> get("/api/v1/accounts/#{user.id}/statuses", %{"exclude_reblogs" => "1"})
1286 assert [%{"id" => id}] = json_response(conn, 200)
1287 assert id == to_string(post.id)
1291 describe "user relationships" do
1292 test "returns the relationships for the current user", %{conn: conn} do
1293 user = insert(:user)
1294 other_user = insert(:user)
1295 {:ok, user} = User.follow(user, other_user)
1299 |> assign(:user, user)
1300 |> get("/api/v1/accounts/relationships", %{"id" => [other_user.id]})
1302 assert [relationship] = json_response(conn, 200)
1304 assert to_string(other_user.id) == relationship["id"]
1308 describe "locked accounts" do
1309 test "/api/v1/follow_requests works" do
1310 user = insert(:user, %{info: %Pleroma.User.Info{locked: true}})
1311 other_user = insert(:user)
1313 {:ok, _activity} = ActivityPub.follow(other_user, user)
1315 user = User.get_cached_by_id(user.id)
1316 other_user = User.get_cached_by_id(other_user.id)
1318 assert User.following?(other_user, user) == false
1322 |> assign(:user, user)
1323 |> get("/api/v1/follow_requests")
1325 assert [relationship] = json_response(conn, 200)
1326 assert to_string(other_user.id) == relationship["id"]
1329 test "/api/v1/follow_requests/:id/authorize works" do
1330 user = insert(:user, %{info: %User.Info{locked: true}})
1331 other_user = insert(:user)
1333 {:ok, _activity} = ActivityPub.follow(other_user, user)
1335 user = User.get_cached_by_id(user.id)
1336 other_user = User.get_cached_by_id(other_user.id)
1338 assert User.following?(other_user, user) == false
1342 |> assign(:user, user)
1343 |> post("/api/v1/follow_requests/#{other_user.id}/authorize")
1345 assert relationship = json_response(conn, 200)
1346 assert to_string(other_user.id) == relationship["id"]
1348 user = User.get_cached_by_id(user.id)
1349 other_user = User.get_cached_by_id(other_user.id)
1351 assert User.following?(other_user, user) == true
1354 test "verify_credentials", %{conn: conn} do
1355 user = insert(:user, %{info: %Pleroma.User.Info{default_scope: "private"}})
1359 |> assign(:user, user)
1360 |> get("/api/v1/accounts/verify_credentials")
1362 assert %{"id" => id, "source" => %{"privacy" => "private"}} = json_response(conn, 200)
1363 assert id == to_string(user.id)
1366 test "/api/v1/follow_requests/:id/reject works" do
1367 user = insert(:user, %{info: %Pleroma.User.Info{locked: true}})
1368 other_user = insert(:user)
1370 {:ok, _activity} = ActivityPub.follow(other_user, user)
1372 user = User.get_cached_by_id(user.id)
1376 |> assign(:user, user)
1377 |> post("/api/v1/follow_requests/#{other_user.id}/reject")
1379 assert relationship = json_response(conn, 200)
1380 assert to_string(other_user.id) == relationship["id"]
1382 user = User.get_cached_by_id(user.id)
1383 other_user = User.get_cached_by_id(other_user.id)
1385 assert User.following?(other_user, user) == false
1389 test "account fetching", %{conn: conn} do
1390 user = insert(:user)
1394 |> get("/api/v1/accounts/#{user.id}")
1396 assert %{"id" => id} = json_response(conn, 200)
1397 assert id == to_string(user.id)
1401 |> get("/api/v1/accounts/-1")
1403 assert %{"error" => "Can't find user"} = json_response(conn, 404)
1406 test "account fetching also works nickname", %{conn: conn} do
1407 user = insert(:user)
1411 |> get("/api/v1/accounts/#{user.nickname}")
1413 assert %{"id" => id} = json_response(conn, 200)
1414 assert id == user.id
1417 test "media upload", %{conn: conn} do
1418 file = %Plug.Upload{
1419 content_type: "image/jpg",
1420 path: Path.absname("test/fixtures/image.jpg"),
1421 filename: "an_image.jpg"
1424 desc = "Description of the image"
1426 user = insert(:user)
1430 |> assign(:user, user)
1431 |> post("/api/v1/media", %{"file" => file, "description" => desc})
1433 assert media = json_response(conn, 200)
1435 assert media["type"] == "image"
1436 assert media["description"] == desc
1439 object = Repo.get(Object, media["id"])
1440 assert object.data["actor"] == User.ap_id(user)
1443 test "hashtag timeline", %{conn: conn} do
1444 following = insert(:user)
1447 {:ok, activity} = TwitterAPI.create_status(following, %{"status" => "test #2hu"})
1449 {:ok, [_activity]} =
1450 OStatus.fetch_activity_from_url("https://shitposter.club/notice/2827873")
1454 |> get("/api/v1/timelines/tag/2hu")
1456 assert [%{"id" => id}] = json_response(nconn, 200)
1458 assert id == to_string(activity.id)
1460 # works for different capitalization too
1463 |> get("/api/v1/timelines/tag/2HU")
1465 assert [%{"id" => id}] = json_response(nconn, 200)
1467 assert id == to_string(activity.id)
1471 test "multi-hashtag timeline", %{conn: conn} do
1472 user = insert(:user)
1474 {:ok, activity_test} = CommonAPI.post(user, %{"status" => "#test"})
1475 {:ok, activity_test1} = CommonAPI.post(user, %{"status" => "#test #test1"})
1476 {:ok, activity_none} = CommonAPI.post(user, %{"status" => "#test #none"})
1480 |> get("/api/v1/timelines/tag/test", %{"any" => ["test1"]})
1482 [status_none, status_test1, status_test] = json_response(any_test, 200)
1484 assert to_string(activity_test.id) == status_test["id"]
1485 assert to_string(activity_test1.id) == status_test1["id"]
1486 assert to_string(activity_none.id) == status_none["id"]
1490 |> get("/api/v1/timelines/tag/test", %{"all" => ["test1"], "none" => ["none"]})
1492 assert [status_test1] == json_response(restricted_test, 200)
1494 all_test = conn |> get("/api/v1/timelines/tag/test", %{"all" => ["none"]})
1496 assert [status_none] == json_response(all_test, 200)
1499 test "getting followers", %{conn: conn} do
1500 user = insert(:user)
1501 other_user = insert(:user)
1502 {:ok, user} = User.follow(user, other_user)
1506 |> get("/api/v1/accounts/#{other_user.id}/followers")
1508 assert [%{"id" => id}] = json_response(conn, 200)
1509 assert id == to_string(user.id)
1512 test "getting followers, hide_followers", %{conn: conn} do
1513 user = insert(:user)
1514 other_user = insert(:user, %{info: %{hide_followers: true}})
1515 {:ok, _user} = User.follow(user, other_user)
1519 |> get("/api/v1/accounts/#{other_user.id}/followers")
1521 assert [] == json_response(conn, 200)
1524 test "getting followers, hide_followers, same user requesting", %{conn: conn} do
1525 user = insert(:user)
1526 other_user = insert(:user, %{info: %{hide_followers: true}})
1527 {:ok, _user} = User.follow(user, other_user)
1531 |> assign(:user, other_user)
1532 |> get("/api/v1/accounts/#{other_user.id}/followers")
1534 refute [] == json_response(conn, 200)
1537 test "getting followers, pagination", %{conn: conn} do
1538 user = insert(:user)
1539 follower1 = insert(:user)
1540 follower2 = insert(:user)
1541 follower3 = insert(:user)
1542 {:ok, _} = User.follow(follower1, user)
1543 {:ok, _} = User.follow(follower2, user)
1544 {:ok, _} = User.follow(follower3, user)
1548 |> assign(:user, user)
1552 |> get("/api/v1/accounts/#{user.id}/followers?since_id=#{follower1.id}")
1554 assert [%{"id" => id3}, %{"id" => id2}] = json_response(res_conn, 200)
1555 assert id3 == follower3.id
1556 assert id2 == follower2.id
1560 |> get("/api/v1/accounts/#{user.id}/followers?max_id=#{follower3.id}")
1562 assert [%{"id" => id2}, %{"id" => id1}] = json_response(res_conn, 200)
1563 assert id2 == follower2.id
1564 assert id1 == follower1.id
1568 |> get("/api/v1/accounts/#{user.id}/followers?limit=1&max_id=#{follower3.id}")
1570 assert [%{"id" => id2}] = json_response(res_conn, 200)
1571 assert id2 == follower2.id
1573 assert [link_header] = get_resp_header(res_conn, "link")
1574 assert link_header =~ ~r/min_id=#{follower2.id}/
1575 assert link_header =~ ~r/max_id=#{follower2.id}/
1578 test "getting following", %{conn: conn} do
1579 user = insert(:user)
1580 other_user = insert(:user)
1581 {:ok, user} = User.follow(user, other_user)
1585 |> get("/api/v1/accounts/#{user.id}/following")
1587 assert [%{"id" => id}] = json_response(conn, 200)
1588 assert id == to_string(other_user.id)
1591 test "getting following, hide_follows", %{conn: conn} do
1592 user = insert(:user, %{info: %{hide_follows: true}})
1593 other_user = insert(:user)
1594 {:ok, user} = User.follow(user, other_user)
1598 |> get("/api/v1/accounts/#{user.id}/following")
1600 assert [] == json_response(conn, 200)
1603 test "getting following, hide_follows, same user requesting", %{conn: conn} do
1604 user = insert(:user, %{info: %{hide_follows: true}})
1605 other_user = insert(:user)
1606 {:ok, user} = User.follow(user, other_user)
1610 |> assign(:user, user)
1611 |> get("/api/v1/accounts/#{user.id}/following")
1613 refute [] == json_response(conn, 200)
1616 test "getting following, pagination", %{conn: conn} do
1617 user = insert(:user)
1618 following1 = insert(:user)
1619 following2 = insert(:user)
1620 following3 = insert(:user)
1621 {:ok, _} = User.follow(user, following1)
1622 {:ok, _} = User.follow(user, following2)
1623 {:ok, _} = User.follow(user, following3)
1627 |> assign(:user, user)
1631 |> get("/api/v1/accounts/#{user.id}/following?since_id=#{following1.id}")
1633 assert [%{"id" => id3}, %{"id" => id2}] = json_response(res_conn, 200)
1634 assert id3 == following3.id
1635 assert id2 == following2.id
1639 |> get("/api/v1/accounts/#{user.id}/following?max_id=#{following3.id}")
1641 assert [%{"id" => id2}, %{"id" => id1}] = json_response(res_conn, 200)
1642 assert id2 == following2.id
1643 assert id1 == following1.id
1647 |> get("/api/v1/accounts/#{user.id}/following?limit=1&max_id=#{following3.id}")
1649 assert [%{"id" => id2}] = json_response(res_conn, 200)
1650 assert id2 == following2.id
1652 assert [link_header] = get_resp_header(res_conn, "link")
1653 assert link_header =~ ~r/min_id=#{following2.id}/
1654 assert link_header =~ ~r/max_id=#{following2.id}/
1657 test "following / unfollowing a user", %{conn: conn} do
1658 user = insert(:user)
1659 other_user = insert(:user)
1663 |> assign(:user, user)
1664 |> post("/api/v1/accounts/#{other_user.id}/follow")
1666 assert %{"id" => _id, "following" => true} = json_response(conn, 200)
1668 user = User.get_cached_by_id(user.id)
1672 |> assign(:user, user)
1673 |> post("/api/v1/accounts/#{other_user.id}/unfollow")
1675 assert %{"id" => _id, "following" => false} = json_response(conn, 200)
1677 user = User.get_cached_by_id(user.id)
1681 |> assign(:user, user)
1682 |> post("/api/v1/follows", %{"uri" => other_user.nickname})
1684 assert %{"id" => id} = json_response(conn, 200)
1685 assert id == to_string(other_user.id)
1688 test "following without reblogs" do
1689 follower = insert(:user)
1690 followed = insert(:user)
1691 other_user = insert(:user)
1695 |> assign(:user, follower)
1696 |> post("/api/v1/accounts/#{followed.id}/follow?reblogs=false")
1698 assert %{"showing_reblogs" => false} = json_response(conn, 200)
1700 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "hey"})
1701 {:ok, reblog, _} = CommonAPI.repeat(activity.id, followed)
1705 |> assign(:user, User.get_cached_by_id(follower.id))
1706 |> get("/api/v1/timelines/home")
1708 assert [] == json_response(conn, 200)
1712 |> assign(:user, follower)
1713 |> post("/api/v1/accounts/#{followed.id}/follow?reblogs=true")
1715 assert %{"showing_reblogs" => true} = json_response(conn, 200)
1719 |> assign(:user, User.get_cached_by_id(follower.id))
1720 |> get("/api/v1/timelines/home")
1722 expected_activity_id = reblog.id
1723 assert [%{"id" => ^expected_activity_id}] = json_response(conn, 200)
1726 test "following / unfollowing errors" do
1727 user = insert(:user)
1731 |> assign(:user, user)
1734 conn_res = post(conn, "/api/v1/accounts/#{user.id}/follow")
1735 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
1738 user = User.get_cached_by_id(user.id)
1739 conn_res = post(conn, "/api/v1/accounts/#{user.id}/unfollow")
1740 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
1742 # self follow via uri
1743 user = User.get_cached_by_id(user.id)
1744 conn_res = post(conn, "/api/v1/follows", %{"uri" => user.nickname})
1745 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
1747 # follow non existing user
1748 conn_res = post(conn, "/api/v1/accounts/doesntexist/follow")
1749 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
1751 # follow non existing user via uri
1752 conn_res = post(conn, "/api/v1/follows", %{"uri" => "doesntexist"})
1753 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
1755 # unfollow non existing user
1756 conn_res = post(conn, "/api/v1/accounts/doesntexist/unfollow")
1757 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
1760 test "muting / unmuting a user", %{conn: conn} do
1761 user = insert(:user)
1762 other_user = insert(:user)
1766 |> assign(:user, user)
1767 |> post("/api/v1/accounts/#{other_user.id}/mute")
1769 assert %{"id" => _id, "muting" => true} = json_response(conn, 200)
1771 user = User.get_cached_by_id(user.id)
1775 |> assign(:user, user)
1776 |> post("/api/v1/accounts/#{other_user.id}/unmute")
1778 assert %{"id" => _id, "muting" => false} = json_response(conn, 200)
1781 test "subscribing / unsubscribing to a user", %{conn: conn} do
1782 user = insert(:user)
1783 subscription_target = insert(:user)
1787 |> assign(:user, user)
1788 |> post("/api/v1/pleroma/accounts/#{subscription_target.id}/subscribe")
1790 assert %{"id" => _id, "subscribing" => true} = json_response(conn, 200)
1794 |> assign(:user, user)
1795 |> post("/api/v1/pleroma/accounts/#{subscription_target.id}/unsubscribe")
1797 assert %{"id" => _id, "subscribing" => false} = json_response(conn, 200)
1800 test "getting a list of mutes", %{conn: conn} do
1801 user = insert(:user)
1802 other_user = insert(:user)
1804 {:ok, user} = User.mute(user, other_user)
1808 |> assign(:user, user)
1809 |> get("/api/v1/mutes")
1811 other_user_id = to_string(other_user.id)
1812 assert [%{"id" => ^other_user_id}] = json_response(conn, 200)
1815 test "blocking / unblocking a user", %{conn: conn} do
1816 user = insert(:user)
1817 other_user = insert(:user)
1821 |> assign(:user, user)
1822 |> post("/api/v1/accounts/#{other_user.id}/block")
1824 assert %{"id" => _id, "blocking" => true} = json_response(conn, 200)
1826 user = User.get_cached_by_id(user.id)
1830 |> assign(:user, user)
1831 |> post("/api/v1/accounts/#{other_user.id}/unblock")
1833 assert %{"id" => _id, "blocking" => false} = json_response(conn, 200)
1836 test "getting a list of blocks", %{conn: conn} do
1837 user = insert(:user)
1838 other_user = insert(:user)
1840 {:ok, user} = User.block(user, other_user)
1844 |> assign(:user, user)
1845 |> get("/api/v1/blocks")
1847 other_user_id = to_string(other_user.id)
1848 assert [%{"id" => ^other_user_id}] = json_response(conn, 200)
1851 test "blocking / unblocking a domain", %{conn: conn} do
1852 user = insert(:user)
1853 other_user = insert(:user, %{ap_id: "https://dogwhistle.zone/@pundit"})
1857 |> assign(:user, user)
1858 |> post("/api/v1/domain_blocks", %{"domain" => "dogwhistle.zone"})
1860 assert %{} = json_response(conn, 200)
1861 user = User.get_cached_by_ap_id(user.ap_id)
1862 assert User.blocks?(user, other_user)
1866 |> assign(:user, user)
1867 |> delete("/api/v1/domain_blocks", %{"domain" => "dogwhistle.zone"})
1869 assert %{} = json_response(conn, 200)
1870 user = User.get_cached_by_ap_id(user.ap_id)
1871 refute User.blocks?(user, other_user)
1874 test "getting a list of domain blocks", %{conn: conn} do
1875 user = insert(:user)
1877 {:ok, user} = User.block_domain(user, "bad.site")
1878 {:ok, user} = User.block_domain(user, "even.worse.site")
1882 |> assign(:user, user)
1883 |> get("/api/v1/domain_blocks")
1885 domain_blocks = json_response(conn, 200)
1887 assert "bad.site" in domain_blocks
1888 assert "even.worse.site" in domain_blocks
1891 test "unimplemented follow_requests, blocks, domain blocks" do
1892 user = insert(:user)
1894 ["blocks", "domain_blocks", "follow_requests"]
1895 |> Enum.each(fn endpoint ->
1898 |> assign(:user, user)
1899 |> get("/api/v1/#{endpoint}")
1901 assert [] = json_response(conn, 200)
1905 test "account search", %{conn: conn} do
1906 user = insert(:user)
1907 user_two = insert(:user, %{nickname: "shp@shitposter.club"})
1908 user_three = insert(:user, %{nickname: "shp@heldscal.la", name: "I love 2hu"})
1912 |> assign(:user, user)
1913 |> get("/api/v1/accounts/search", %{"q" => "shp"})
1914 |> json_response(200)
1916 result_ids = for result <- results, do: result["acct"]
1918 assert user_two.nickname in result_ids
1919 assert user_three.nickname in result_ids
1923 |> assign(:user, user)
1924 |> get("/api/v1/accounts/search", %{"q" => "2hu"})
1925 |> json_response(200)
1927 result_ids = for result <- results, do: result["acct"]
1929 assert user_three.nickname in result_ids
1932 test "search", %{conn: conn} do
1933 user = insert(:user)
1934 user_two = insert(:user, %{nickname: "shp@shitposter.club"})
1935 user_three = insert(:user, %{nickname: "shp@heldscal.la", name: "I love 2hu"})
1937 {:ok, activity} = CommonAPI.post(user, %{"status" => "This is about 2hu"})
1940 CommonAPI.post(user, %{
1941 "status" => "This is about 2hu, but private",
1942 "visibility" => "private"
1945 {:ok, _} = CommonAPI.post(user_two, %{"status" => "This isn't"})
1949 |> get("/api/v1/search", %{"q" => "2hu"})
1951 assert results = json_response(conn, 200)
1953 [account | _] = results["accounts"]
1954 assert account["id"] == to_string(user_three.id)
1956 assert results["hashtags"] == []
1958 [status] = results["statuses"]
1959 assert status["id"] == to_string(activity.id)
1962 test "search fetches remote statuses", %{conn: conn} do
1966 |> get("/api/v1/search", %{"q" => "https://shitposter.club/notice/2827873"})
1968 assert results = json_response(conn, 200)
1970 [status] = results["statuses"]
1971 assert status["uri"] == "tag:shitposter.club,2017-05-05:noticeId=2827873:objectType=comment"
1975 test "search doesn't show statuses that it shouldn't", %{conn: conn} do
1977 CommonAPI.post(insert(:user), %{
1978 "status" => "This is about 2hu, but private",
1979 "visibility" => "private"
1985 |> get("/api/v1/search", %{"q" => Object.normalize(activity).data["id"]})
1987 assert results = json_response(conn, 200)
1989 [] = results["statuses"]
1993 test "search fetches remote accounts", %{conn: conn} do
1996 |> get("/api/v1/search", %{"q" => "shp@social.heldscal.la", "resolve" => "true"})
1998 assert results = json_response(conn, 200)
1999 [account] = results["accounts"]
2000 assert account["acct"] == "shp@social.heldscal.la"
2003 test "returns the favorites of a user", %{conn: conn} do
2004 user = insert(:user)
2005 other_user = insert(:user)
2007 {:ok, _} = CommonAPI.post(other_user, %{"status" => "bla"})
2008 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "traps are happy"})
2010 {:ok, _, _} = CommonAPI.favorite(activity.id, user)
2014 |> assign(:user, user)
2015 |> get("/api/v1/favourites")
2017 assert [status] = json_response(first_conn, 200)
2018 assert status["id"] == to_string(activity.id)
2020 assert [{"link", _link_header}] =
2021 Enum.filter(first_conn.resp_headers, fn element -> match?({"link", _}, element) end)
2023 # Honours query params
2024 {:ok, second_activity} =
2025 CommonAPI.post(other_user, %{
2027 "Trees Are Never Sad Look At Them Every Once In Awhile They're Quite Beautiful."
2030 {:ok, _, _} = CommonAPI.favorite(second_activity.id, user)
2032 last_like = status["id"]
2036 |> assign(:user, user)
2037 |> get("/api/v1/favourites?since_id=#{last_like}")
2039 assert [second_status] = json_response(second_conn, 200)
2040 assert second_status["id"] == to_string(second_activity.id)
2044 |> assign(:user, user)
2045 |> get("/api/v1/favourites?limit=0")
2047 assert [] = json_response(third_conn, 200)
2050 describe "getting favorites timeline of specified user" do
2052 [current_user, user] = insert_pair(:user, %{info: %{hide_favorites: false}})
2053 [current_user: current_user, user: user]
2056 test "returns list of statuses favorited by specified user", %{
2058 current_user: current_user,
2061 [activity | _] = insert_pair(:note_activity)
2062 CommonAPI.favorite(activity.id, user)
2066 |> assign(:user, current_user)
2067 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2068 |> json_response(:ok)
2072 assert length(response) == 1
2073 assert like["id"] == activity.id
2076 test "returns favorites for specified user_id when user is not logged in", %{
2080 activity = insert(:note_activity)
2081 CommonAPI.favorite(activity.id, user)
2085 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2086 |> json_response(:ok)
2088 assert length(response) == 1
2091 test "returns favorited DM only when user is logged in and he is one of recipients", %{
2093 current_user: current_user,
2097 CommonAPI.post(current_user, %{
2098 "status" => "Hi @#{user.nickname}!",
2099 "visibility" => "direct"
2102 CommonAPI.favorite(direct.id, user)
2106 |> assign(:user, current_user)
2107 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2108 |> json_response(:ok)
2110 assert length(response) == 1
2112 anonymous_response =
2114 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2115 |> json_response(:ok)
2117 assert length(anonymous_response) == 0
2120 test "does not return others' favorited DM when user is not one of recipients", %{
2122 current_user: current_user,
2125 user_two = insert(:user)
2128 CommonAPI.post(user_two, %{
2129 "status" => "Hi @#{user.nickname}!",
2130 "visibility" => "direct"
2133 CommonAPI.favorite(direct.id, user)
2137 |> assign(:user, current_user)
2138 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2139 |> json_response(:ok)
2141 assert length(response) == 0
2144 test "paginates favorites using since_id and max_id", %{
2146 current_user: current_user,
2149 activities = insert_list(10, :note_activity)
2151 Enum.each(activities, fn activity ->
2152 CommonAPI.favorite(activity.id, user)
2155 third_activity = Enum.at(activities, 2)
2156 seventh_activity = Enum.at(activities, 6)
2160 |> assign(:user, current_user)
2161 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites", %{
2162 since_id: third_activity.id,
2163 max_id: seventh_activity.id
2165 |> json_response(:ok)
2167 assert length(response) == 3
2168 refute third_activity in response
2169 refute seventh_activity in response
2172 test "limits favorites using limit parameter", %{
2174 current_user: current_user,
2178 |> insert_list(:note_activity)
2179 |> Enum.each(fn activity ->
2180 CommonAPI.favorite(activity.id, user)
2185 |> assign(:user, current_user)
2186 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites", %{limit: "3"})
2187 |> json_response(:ok)
2189 assert length(response) == 3
2192 test "returns empty response when user does not have any favorited statuses", %{
2194 current_user: current_user,
2199 |> assign(:user, current_user)
2200 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2201 |> json_response(:ok)
2203 assert Enum.empty?(response)
2206 test "returns 404 error when specified user is not exist", %{conn: conn} do
2207 conn = get(conn, "/api/v1/pleroma/accounts/test/favourites")
2209 assert json_response(conn, 404) == %{"error" => "Record not found"}
2212 test "returns 403 error when user has hidden own favorites", %{
2214 current_user: current_user
2216 user = insert(:user, %{info: %{hide_favorites: true}})
2217 activity = insert(:note_activity)
2218 CommonAPI.favorite(activity.id, user)
2222 |> assign(:user, current_user)
2223 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2225 assert json_response(conn, 403) == %{"error" => "Can't get favorites"}
2228 test "hides favorites for new users by default", %{conn: conn, current_user: current_user} do
2229 user = insert(:user)
2230 activity = insert(:note_activity)
2231 CommonAPI.favorite(activity.id, user)
2235 |> assign(:user, current_user)
2236 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2238 assert user.info.hide_favorites
2239 assert json_response(conn, 403) == %{"error" => "Can't get favorites"}
2243 describe "updating credentials" do
2244 test "updates the user's bio", %{conn: conn} do
2245 user = insert(:user)
2246 user2 = insert(:user)
2250 |> assign(:user, user)
2251 |> patch("/api/v1/accounts/update_credentials", %{
2252 "note" => "I drink #cofe with @#{user2.nickname}"
2255 assert user = json_response(conn, 200)
2257 assert user["note"] ==
2258 ~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=") <>
2260 ~s(" class="u-url mention" href=") <>
2261 user2.ap_id <> ~s(">@<span>) <> user2.nickname <> ~s(</span></a></span>)
2264 test "updates the user's locking status", %{conn: conn} do
2265 user = insert(:user)
2269 |> assign(:user, user)
2270 |> patch("/api/v1/accounts/update_credentials", %{locked: "true"})
2272 assert user = json_response(conn, 200)
2273 assert user["locked"] == true
2276 test "updates the user's default scope", %{conn: conn} do
2277 user = insert(:user)
2281 |> assign(:user, user)
2282 |> patch("/api/v1/accounts/update_credentials", %{default_scope: "cofe"})
2284 assert user = json_response(conn, 200)
2285 assert user["source"]["privacy"] == "cofe"
2288 test "updates the user's hide_followers status", %{conn: conn} do
2289 user = insert(:user)
2293 |> assign(:user, user)
2294 |> patch("/api/v1/accounts/update_credentials", %{hide_followers: "true"})
2296 assert user = json_response(conn, 200)
2297 assert user["pleroma"]["hide_followers"] == true
2300 test "updates the user's hide_follows status", %{conn: conn} do
2301 user = insert(:user)
2305 |> assign(:user, user)
2306 |> patch("/api/v1/accounts/update_credentials", %{hide_follows: "true"})
2308 assert user = json_response(conn, 200)
2309 assert user["pleroma"]["hide_follows"] == true
2312 test "updates the user's hide_favorites status", %{conn: conn} do
2313 user = insert(:user)
2317 |> assign(:user, user)
2318 |> patch("/api/v1/accounts/update_credentials", %{hide_favorites: "true"})
2320 assert user = json_response(conn, 200)
2321 assert user["pleroma"]["hide_favorites"] == true
2324 test "updates the user's show_role status", %{conn: conn} do
2325 user = insert(:user)
2329 |> assign(:user, user)
2330 |> patch("/api/v1/accounts/update_credentials", %{show_role: "false"})
2332 assert user = json_response(conn, 200)
2333 assert user["source"]["pleroma"]["show_role"] == false
2336 test "updates the user's no_rich_text status", %{conn: conn} do
2337 user = insert(:user)
2341 |> assign(:user, user)
2342 |> patch("/api/v1/accounts/update_credentials", %{no_rich_text: "true"})
2344 assert user = json_response(conn, 200)
2345 assert user["source"]["pleroma"]["no_rich_text"] == true
2348 test "updates the user's name", %{conn: conn} do
2349 user = insert(:user)
2353 |> assign(:user, user)
2354 |> patch("/api/v1/accounts/update_credentials", %{"display_name" => "markorepairs"})
2356 assert user = json_response(conn, 200)
2357 assert user["display_name"] == "markorepairs"
2360 test "updates the user's avatar", %{conn: conn} do
2361 user = insert(:user)
2363 new_avatar = %Plug.Upload{
2364 content_type: "image/jpg",
2365 path: Path.absname("test/fixtures/image.jpg"),
2366 filename: "an_image.jpg"
2371 |> assign(:user, user)
2372 |> patch("/api/v1/accounts/update_credentials", %{"avatar" => new_avatar})
2374 assert user_response = json_response(conn, 200)
2375 assert user_response["avatar"] != User.avatar_url(user)
2378 test "updates the user's banner", %{conn: conn} do
2379 user = insert(:user)
2381 new_header = %Plug.Upload{
2382 content_type: "image/jpg",
2383 path: Path.absname("test/fixtures/image.jpg"),
2384 filename: "an_image.jpg"
2389 |> assign(:user, user)
2390 |> patch("/api/v1/accounts/update_credentials", %{"header" => new_header})
2392 assert user_response = json_response(conn, 200)
2393 assert user_response["header"] != User.banner_url(user)
2396 test "requires 'write' permission", %{conn: conn} do
2397 token1 = insert(:oauth_token, scopes: ["read"])
2398 token2 = insert(:oauth_token, scopes: ["write", "follow"])
2400 for token <- [token1, token2] do
2403 |> put_req_header("authorization", "Bearer #{token.token}")
2404 |> patch("/api/v1/accounts/update_credentials", %{})
2406 if token == token1 do
2407 assert %{"error" => "Insufficient permissions: write."} == json_response(conn, 403)
2409 assert json_response(conn, 200)
2414 test "updates profile emojos", %{conn: conn} do
2415 user = insert(:user)
2417 note = "*sips :blank:*"
2418 name = "I am :firefox:"
2422 |> assign(:user, user)
2423 |> patch("/api/v1/accounts/update_credentials", %{
2425 "display_name" => name
2428 assert json_response(conn, 200)
2432 |> get("/api/v1/accounts/#{user.id}")
2434 assert user = json_response(conn, 200)
2436 assert user["note"] == note
2437 assert user["display_name"] == name
2438 assert [%{"shortcode" => "blank"}, %{"shortcode" => "firefox"}] = user["emojis"]
2442 test "get instance information", %{conn: conn} do
2443 conn = get(conn, "/api/v1/instance")
2444 assert result = json_response(conn, 200)
2446 email = Pleroma.Config.get([:instance, :email])
2447 # Note: not checking for "max_toot_chars" since it's optional
2453 "email" => from_config_email,
2455 "streaming_api" => _
2460 "registrations" => _
2463 assert email == from_config_email
2466 test "get instance stats", %{conn: conn} do
2467 user = insert(:user, %{local: true})
2469 user2 = insert(:user, %{local: true})
2470 {:ok, _user2} = User.deactivate(user2, !user2.info.deactivated)
2472 insert(:user, %{local: false, nickname: "u@peer1.com"})
2473 insert(:user, %{local: false, nickname: "u@peer2.com"})
2475 {:ok, _} = TwitterAPI.create_status(user, %{"status" => "cofe"})
2477 # Stats should count users with missing or nil `info.deactivated` value
2478 user = User.get_cached_by_id(user.id)
2479 info_change = Changeset.change(user.info, %{deactivated: nil})
2483 |> Changeset.change()
2484 |> Changeset.put_embed(:info, info_change)
2485 |> User.update_and_set_cache()
2487 Pleroma.Stats.update_stats()
2489 conn = get(conn, "/api/v1/instance")
2491 assert result = json_response(conn, 200)
2493 stats = result["stats"]
2496 assert stats["user_count"] == 1
2497 assert stats["status_count"] == 1
2498 assert stats["domain_count"] == 2
2501 test "get peers", %{conn: conn} do
2502 insert(:user, %{local: false, nickname: "u@peer1.com"})
2503 insert(:user, %{local: false, nickname: "u@peer2.com"})
2505 Pleroma.Stats.update_stats()
2507 conn = get(conn, "/api/v1/instance/peers")
2509 assert result = json_response(conn, 200)
2511 assert ["peer1.com", "peer2.com"] == Enum.sort(result)
2514 test "put settings", %{conn: conn} do
2515 user = insert(:user)
2519 |> assign(:user, user)
2520 |> put("/api/web/settings", %{"data" => %{"programming" => "socks"}})
2522 assert _result = json_response(conn, 200)
2524 user = User.get_cached_by_ap_id(user.ap_id)
2525 assert user.info.settings == %{"programming" => "socks"}
2528 describe "pinned statuses" do
2530 Pleroma.Config.put([:instance, :max_pinned_statuses], 1)
2532 user = insert(:user)
2533 {:ok, activity} = CommonAPI.post(user, %{"status" => "HI!!!"})
2535 [user: user, activity: activity]
2538 test "returns pinned statuses", %{conn: conn, user: user, activity: activity} do
2539 {:ok, _} = CommonAPI.pin(activity.id, user)
2543 |> assign(:user, user)
2544 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
2545 |> json_response(200)
2547 id_str = to_string(activity.id)
2549 assert [%{"id" => ^id_str, "pinned" => true}] = result
2552 test "pin status", %{conn: conn, user: user, activity: activity} do
2553 id_str = to_string(activity.id)
2555 assert %{"id" => ^id_str, "pinned" => true} =
2557 |> assign(:user, user)
2558 |> post("/api/v1/statuses/#{activity.id}/pin")
2559 |> json_response(200)
2561 assert [%{"id" => ^id_str, "pinned" => true}] =
2563 |> assign(:user, user)
2564 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
2565 |> json_response(200)
2568 test "unpin status", %{conn: conn, user: user, activity: activity} do
2569 {:ok, _} = CommonAPI.pin(activity.id, user)
2571 id_str = to_string(activity.id)
2572 user = refresh_record(user)
2574 assert %{"id" => ^id_str, "pinned" => false} =
2576 |> assign(:user, user)
2577 |> post("/api/v1/statuses/#{activity.id}/unpin")
2578 |> json_response(200)
2582 |> assign(:user, user)
2583 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
2584 |> json_response(200)
2587 test "max pinned statuses", %{conn: conn, user: user, activity: activity_one} do
2588 {:ok, activity_two} = CommonAPI.post(user, %{"status" => "HI!!!"})
2590 id_str_one = to_string(activity_one.id)
2592 assert %{"id" => ^id_str_one, "pinned" => true} =
2594 |> assign(:user, user)
2595 |> post("/api/v1/statuses/#{id_str_one}/pin")
2596 |> json_response(200)
2598 user = refresh_record(user)
2600 assert %{"error" => "You have already pinned the maximum number of statuses"} =
2602 |> assign(:user, user)
2603 |> post("/api/v1/statuses/#{activity_two.id}/pin")
2604 |> json_response(400)
2607 test "Status rich-media Card", %{conn: conn, user: user} do
2608 Pleroma.Config.put([:rich_media, :enabled], true)
2609 {:ok, activity} = CommonAPI.post(user, %{"status" => "http://example.com/ogp"})
2613 |> get("/api/v1/statuses/#{activity.id}/card")
2614 |> json_response(200)
2616 assert response == %{
2617 "image" => "http://ia.media-imdb.com/images/rock.jpg",
2618 "provider_name" => "www.imdb.com",
2619 "provider_url" => "http://www.imdb.com",
2620 "title" => "The Rock",
2622 "url" => "http://www.imdb.com/title/tt0117500/",
2623 "description" => nil,
2626 "image" => "http://ia.media-imdb.com/images/rock.jpg",
2627 "title" => "The Rock",
2628 "type" => "video.movie",
2629 "url" => "http://www.imdb.com/title/tt0117500/"
2634 # works with private posts
2636 CommonAPI.post(user, %{"status" => "http://example.com/ogp", "visibility" => "direct"})
2640 |> assign(:user, user)
2641 |> get("/api/v1/statuses/#{activity.id}/card")
2642 |> json_response(200)
2644 assert response_two == response
2646 Pleroma.Config.put([:rich_media, :enabled], false)
2651 user = insert(:user)
2652 for_user = insert(:user)
2655 CommonAPI.post(user, %{
2656 "status" => "heweoo?"
2660 CommonAPI.post(user, %{
2661 "status" => "heweoo!"
2666 |> assign(:user, for_user)
2667 |> post("/api/v1/statuses/#{activity1.id}/bookmark")
2669 assert json_response(response1, 200)["bookmarked"] == true
2673 |> assign(:user, for_user)
2674 |> post("/api/v1/statuses/#{activity2.id}/bookmark")
2676 assert json_response(response2, 200)["bookmarked"] == true
2680 |> assign(:user, for_user)
2681 |> get("/api/v1/bookmarks")
2683 assert [json_response(response2, 200), json_response(response1, 200)] ==
2684 json_response(bookmarks, 200)
2688 |> assign(:user, for_user)
2689 |> post("/api/v1/statuses/#{activity1.id}/unbookmark")
2691 assert json_response(response1, 200)["bookmarked"] == false
2695 |> assign(:user, for_user)
2696 |> get("/api/v1/bookmarks")
2698 assert [json_response(response2, 200)] == json_response(bookmarks, 200)
2701 describe "conversation muting" do
2703 user = insert(:user)
2704 {:ok, activity} = CommonAPI.post(user, %{"status" => "HIE"})
2706 [user: user, activity: activity]
2709 test "mute conversation", %{conn: conn, user: user, activity: activity} do
2710 id_str = to_string(activity.id)
2712 assert %{"id" => ^id_str, "muted" => true} =
2714 |> assign(:user, user)
2715 |> post("/api/v1/statuses/#{activity.id}/mute")
2716 |> json_response(200)
2719 test "unmute conversation", %{conn: conn, user: user, activity: activity} do
2720 {:ok, _} = CommonAPI.add_mute(user, activity)
2722 id_str = to_string(activity.id)
2723 user = refresh_record(user)
2725 assert %{"id" => ^id_str, "muted" => false} =
2727 |> assign(:user, user)
2728 |> post("/api/v1/statuses/#{activity.id}/unmute")
2729 |> json_response(200)
2733 test "flavours switching (Pleroma Extension)", %{conn: conn} do
2734 user = insert(:user)
2738 |> assign(:user, user)
2739 |> get("/api/v1/pleroma/flavour")
2741 assert "glitch" == json_response(get_old_flavour, 200)
2745 |> assign(:user, user)
2746 |> post("/api/v1/pleroma/flavour/vanilla")
2748 assert "vanilla" == json_response(set_flavour, 200)
2752 |> assign(:user, user)
2753 |> post("/api/v1/pleroma/flavour/vanilla")
2755 assert json_response(set_flavour, 200) == json_response(get_new_flavour, 200)
2758 describe "reports" do
2760 reporter = insert(:user)
2761 target_user = insert(:user)
2763 {:ok, activity} = CommonAPI.post(target_user, %{"status" => "foobar"})
2765 [reporter: reporter, target_user: target_user, activity: activity]
2768 test "submit a basic report", %{conn: conn, reporter: reporter, target_user: target_user} do
2769 assert %{"action_taken" => false, "id" => _} =
2771 |> assign(:user, reporter)
2772 |> post("/api/v1/reports", %{"account_id" => target_user.id})
2773 |> json_response(200)
2776 test "submit a report with statuses and comment", %{
2779 target_user: target_user,
2782 assert %{"action_taken" => false, "id" => _} =
2784 |> assign(:user, reporter)
2785 |> post("/api/v1/reports", %{
2786 "account_id" => target_user.id,
2787 "status_ids" => [activity.id],
2788 "comment" => "bad status!"
2790 |> json_response(200)
2793 test "account_id is required", %{
2798 assert %{"error" => "Valid `account_id` required"} =
2800 |> assign(:user, reporter)
2801 |> post("/api/v1/reports", %{"status_ids" => [activity.id]})
2802 |> json_response(400)
2805 test "comment must be up to the size specified in the config", %{
2808 target_user: target_user
2810 max_size = Pleroma.Config.get([:instance, :max_report_comment_size], 1000)
2811 comment = String.pad_trailing("a", max_size + 1, "a")
2813 error = %{"error" => "Comment must be up to #{max_size} characters"}
2817 |> assign(:user, reporter)
2818 |> post("/api/v1/reports", %{"account_id" => target_user.id, "comment" => comment})
2819 |> json_response(400)
2823 describe "link headers" do
2824 test "preserves parameters in link headers", %{conn: conn} do
2825 user = insert(:user)
2826 other_user = insert(:user)
2829 CommonAPI.post(other_user, %{
2830 "status" => "hi @#{user.nickname}",
2831 "visibility" => "public"
2835 CommonAPI.post(other_user, %{
2836 "status" => "hi @#{user.nickname}",
2837 "visibility" => "public"
2840 notification1 = Repo.get_by(Notification, activity_id: activity1.id)
2841 notification2 = Repo.get_by(Notification, activity_id: activity2.id)
2845 |> assign(:user, user)
2846 |> get("/api/v1/notifications", %{media_only: true})
2848 assert [link_header] = get_resp_header(conn, "link")
2849 assert link_header =~ ~r/media_only=true/
2850 assert link_header =~ ~r/min_id=#{notification2.id}/
2851 assert link_header =~ ~r/max_id=#{notification1.id}/
2855 test "accounts fetches correct account for nicknames beginning with numbers", %{conn: conn} do
2856 # Need to set an old-style integer ID to reproduce the problem
2857 # (these are no longer assigned to new accounts but were preserved
2858 # for existing accounts during the migration to flakeIDs)
2859 user_one = insert(:user, %{id: 1212})
2860 user_two = insert(:user, %{nickname: "#{user_one.id}garbage"})
2864 |> get("/api/v1/accounts/#{user_one.id}")
2868 |> get("/api/v1/accounts/#{user_two.nickname}")
2872 |> get("/api/v1/accounts/#{user_two.id}")
2874 acc_one = json_response(resp_one, 200)
2875 acc_two = json_response(resp_two, 200)
2876 acc_three = json_response(resp_three, 200)
2877 refute acc_one == acc_two
2878 assert acc_two == acc_three
2881 describe "custom emoji" do
2882 test "with tags", %{conn: conn} do
2885 |> get("/api/v1/custom_emojis")
2886 |> json_response(200)
2888 assert Map.has_key?(emoji, "shortcode")
2889 assert Map.has_key?(emoji, "static_url")
2890 assert Map.has_key?(emoji, "tags")
2891 assert is_list(emoji["tags"])
2892 assert Map.has_key?(emoji, "url")
2893 assert Map.has_key?(emoji, "visible_in_picker")
2897 describe "index/2 redirections" do
2898 setup %{conn: conn} do
2902 signing_salt: "cooldude"
2907 |> Plug.Session.call(Plug.Session.init(session_opts))
2910 test_path = "/web/statuses/test"
2911 %{conn: conn, path: test_path}
2914 test "redirects not logged-in users to the login page", %{conn: conn, path: path} do
2915 conn = get(conn, path)
2917 assert conn.status == 302
2918 assert redirected_to(conn) == "/web/login"
2921 test "does not redirect logged in users to the login page", %{conn: conn, path: path} do
2922 token = insert(:oauth_token)
2926 |> assign(:user, token.user)
2927 |> put_session(:oauth_token, token.token)
2930 assert conn.status == 200
2933 test "saves referer path to session", %{conn: conn, path: path} do
2934 conn = get(conn, path)
2935 return_to = Plug.Conn.get_session(conn, :return_to)
2937 assert return_to == path
2940 test "redirects to the saved path after log in", %{conn: conn, path: path} do
2941 app = insert(:oauth_app, client_name: "Mastodon-Local", redirect_uris: ".")
2942 auth = insert(:oauth_authorization, app: app)
2946 |> put_session(:return_to, path)
2947 |> get("/web/login", %{code: auth.token})
2949 assert conn.status == 302
2950 assert redirected_to(conn) == path
2953 test "redirects to the getting-started page when referer is not present", %{conn: conn} do
2954 app = insert(:oauth_app, client_name: "Mastodon-Local", redirect_uris: ".")
2955 auth = insert(:oauth_authorization, app: app)
2957 conn = get(conn, "/web/login", %{code: auth.token})
2959 assert conn.status == 302
2960 assert redirected_to(conn) == "/web/getting-started"
2964 describe "scheduled activities" do
2965 test "creates a scheduled activity", %{conn: conn} do
2966 user = insert(:user)
2967 scheduled_at = NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond)
2971 |> assign(:user, user)
2972 |> post("/api/v1/statuses", %{
2973 "status" => "scheduled",
2974 "scheduled_at" => scheduled_at
2977 assert %{"scheduled_at" => expected_scheduled_at} = json_response(conn, 200)
2978 assert expected_scheduled_at == Pleroma.Web.CommonAPI.Utils.to_masto_date(scheduled_at)
2979 assert [] == Repo.all(Activity)
2982 test "creates a scheduled activity with a media attachment", %{conn: conn} do
2983 user = insert(:user)
2984 scheduled_at = NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond)
2986 file = %Plug.Upload{
2987 content_type: "image/jpg",
2988 path: Path.absname("test/fixtures/image.jpg"),
2989 filename: "an_image.jpg"
2992 {:ok, upload} = ActivityPub.upload(file, actor: user.ap_id)
2996 |> assign(:user, user)
2997 |> post("/api/v1/statuses", %{
2998 "media_ids" => [to_string(upload.id)],
2999 "status" => "scheduled",
3000 "scheduled_at" => scheduled_at
3003 assert %{"media_attachments" => [media_attachment]} = json_response(conn, 200)
3004 assert %{"type" => "image"} = media_attachment
3007 test "skips the scheduling and creates the activity if scheduled_at is earlier than 5 minutes from now",
3009 user = insert(:user)
3012 NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(5) - 1, :millisecond)
3016 |> assign(:user, user)
3017 |> post("/api/v1/statuses", %{
3018 "status" => "not scheduled",
3019 "scheduled_at" => scheduled_at
3022 assert %{"content" => "not scheduled"} = json_response(conn, 200)
3023 assert [] == Repo.all(ScheduledActivity)
3026 test "returns error when daily user limit is exceeded", %{conn: conn} do
3027 user = insert(:user)
3030 NaiveDateTime.utc_now()
3031 |> NaiveDateTime.add(:timer.minutes(6), :millisecond)
3032 |> NaiveDateTime.to_iso8601()
3034 attrs = %{params: %{}, scheduled_at: today}
3035 {:ok, _} = ScheduledActivity.create(user, attrs)
3036 {:ok, _} = ScheduledActivity.create(user, attrs)
3040 |> assign(:user, user)
3041 |> post("/api/v1/statuses", %{"status" => "scheduled", "scheduled_at" => today})
3043 assert %{"error" => "daily limit exceeded"} == json_response(conn, 422)
3046 test "returns error when total user limit is exceeded", %{conn: conn} do
3047 user = insert(:user)
3050 NaiveDateTime.utc_now()
3051 |> NaiveDateTime.add(:timer.minutes(6), :millisecond)
3052 |> NaiveDateTime.to_iso8601()
3055 NaiveDateTime.utc_now()
3056 |> NaiveDateTime.add(:timer.hours(36), :millisecond)
3057 |> NaiveDateTime.to_iso8601()
3059 attrs = %{params: %{}, scheduled_at: today}
3060 {:ok, _} = ScheduledActivity.create(user, attrs)
3061 {:ok, _} = ScheduledActivity.create(user, attrs)
3062 {:ok, _} = ScheduledActivity.create(user, %{params: %{}, scheduled_at: tomorrow})
3066 |> assign(:user, user)
3067 |> post("/api/v1/statuses", %{"status" => "scheduled", "scheduled_at" => tomorrow})
3069 assert %{"error" => "total limit exceeded"} == json_response(conn, 422)
3072 test "shows scheduled activities", %{conn: conn} do
3073 user = insert(:user)
3074 scheduled_activity_id1 = insert(:scheduled_activity, user: user).id |> to_string()
3075 scheduled_activity_id2 = insert(:scheduled_activity, user: user).id |> to_string()
3076 scheduled_activity_id3 = insert(:scheduled_activity, user: user).id |> to_string()
3077 scheduled_activity_id4 = insert(:scheduled_activity, user: user).id |> to_string()
3081 |> assign(:user, user)
3086 |> get("/api/v1/scheduled_statuses?limit=2&min_id=#{scheduled_activity_id1}")
3088 result = json_response(conn_res, 200)
3089 assert [%{"id" => ^scheduled_activity_id3}, %{"id" => ^scheduled_activity_id2}] = result
3094 |> get("/api/v1/scheduled_statuses?limit=2&since_id=#{scheduled_activity_id1}")
3096 result = json_response(conn_res, 200)
3097 assert [%{"id" => ^scheduled_activity_id4}, %{"id" => ^scheduled_activity_id3}] = result
3102 |> get("/api/v1/scheduled_statuses?limit=2&max_id=#{scheduled_activity_id4}")
3104 result = json_response(conn_res, 200)
3105 assert [%{"id" => ^scheduled_activity_id3}, %{"id" => ^scheduled_activity_id2}] = result
3108 test "shows a scheduled activity", %{conn: conn} do
3109 user = insert(:user)
3110 scheduled_activity = insert(:scheduled_activity, user: user)
3114 |> assign(:user, user)
3115 |> get("/api/v1/scheduled_statuses/#{scheduled_activity.id}")
3117 assert %{"id" => scheduled_activity_id} = json_response(res_conn, 200)
3118 assert scheduled_activity_id == scheduled_activity.id |> to_string()
3122 |> assign(:user, user)
3123 |> get("/api/v1/scheduled_statuses/404")
3125 assert %{"error" => "Record not found"} = json_response(res_conn, 404)
3128 test "updates a scheduled activity", %{conn: conn} do
3129 user = insert(:user)
3130 scheduled_activity = insert(:scheduled_activity, user: user)
3133 NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond)
3137 |> assign(:user, user)
3138 |> put("/api/v1/scheduled_statuses/#{scheduled_activity.id}", %{
3139 scheduled_at: new_scheduled_at
3142 assert %{"scheduled_at" => expected_scheduled_at} = json_response(res_conn, 200)
3143 assert expected_scheduled_at == Pleroma.Web.CommonAPI.Utils.to_masto_date(new_scheduled_at)
3147 |> assign(:user, user)
3148 |> put("/api/v1/scheduled_statuses/404", %{scheduled_at: new_scheduled_at})
3150 assert %{"error" => "Record not found"} = json_response(res_conn, 404)
3153 test "deletes a scheduled activity", %{conn: conn} do
3154 user = insert(:user)
3155 scheduled_activity = insert(:scheduled_activity, user: user)
3159 |> assign(:user, user)
3160 |> delete("/api/v1/scheduled_statuses/#{scheduled_activity.id}")
3162 assert %{} = json_response(res_conn, 200)
3163 assert nil == Repo.get(ScheduledActivity, scheduled_activity.id)
3167 |> assign(:user, user)
3168 |> delete("/api/v1/scheduled_statuses/#{scheduled_activity.id}")
3170 assert %{"error" => "Record not found"} = json_response(res_conn, 404)
3174 test "Repeated posts that are replies incorrectly have in_reply_to_id null", %{conn: conn} do
3175 user1 = insert(:user)
3176 user2 = insert(:user)
3177 user3 = insert(:user)
3179 {:ok, replied_to} = TwitterAPI.create_status(user1, %{"status" => "cofe"})
3181 # Reply to status from another user
3184 |> assign(:user, user2)
3185 |> post("/api/v1/statuses", %{"status" => "xD", "in_reply_to_id" => replied_to.id})
3187 assert %{"content" => "xD", "id" => id} = json_response(conn1, 200)
3189 activity = Activity.get_by_id_with_object(id)
3191 assert Object.normalize(activity).data["inReplyTo"] == Object.normalize(replied_to).data["id"]
3192 assert Activity.get_in_reply_to_activity(activity).id == replied_to.id
3194 # Reblog from the third user
3197 |> assign(:user, user3)
3198 |> post("/api/v1/statuses/#{activity.id}/reblog")
3200 assert %{"reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 1}} =
3201 json_response(conn2, 200)
3203 assert to_string(activity.id) == id
3205 # Getting third user status
3208 |> assign(:user, user3)
3209 |> get("api/v1/timelines/home")
3211 [reblogged_activity] = json_response(conn3, 200)
3213 assert reblogged_activity["reblog"]["in_reply_to_id"] == replied_to.id
3215 replied_to_user = User.get_by_ap_id(replied_to.data["actor"])
3216 assert reblogged_activity["reblog"]["in_reply_to_account_id"] == replied_to_user.id