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 "doesn't include DMs from blocked users", %{conn: conn} do
304 blocker = insert(:user)
305 blocked = insert(:user)
307 {:ok, blocker} = User.block(blocker, blocked)
309 {:ok, _blocked_direct} =
310 CommonAPI.post(blocked, %{
311 "status" => "Hi @#{blocker.nickname}!",
312 "visibility" => "direct"
316 CommonAPI.post(user, %{
317 "status" => "Hi @#{blocker.nickname}!",
318 "visibility" => "direct"
323 |> assign(:user, user)
324 |> get("api/v1/timelines/direct")
326 [status] = json_response(res_conn, 200)
327 assert status["id"] == direct.id
330 test "replying to a status", %{conn: conn} do
333 {:ok, replied_to} = TwitterAPI.create_status(user, %{"status" => "cofe"})
337 |> assign(:user, user)
338 |> post("/api/v1/statuses", %{"status" => "xD", "in_reply_to_id" => replied_to.id})
340 assert %{"content" => "xD", "id" => id} = json_response(conn, 200)
342 activity = Activity.get_by_id(id)
344 assert activity.data["context"] == replied_to.data["context"]
345 assert Activity.get_in_reply_to_activity(activity).id == replied_to.id
348 test "posting a status with an invalid in_reply_to_id", %{conn: conn} do
353 |> assign(:user, user)
354 |> post("/api/v1/statuses", %{"status" => "xD", "in_reply_to_id" => ""})
356 assert %{"content" => "xD", "id" => id} = json_response(conn, 200)
358 activity = Activity.get_by_id(id)
363 test "verify_credentials", %{conn: conn} do
368 |> assign(:user, user)
369 |> get("/api/v1/accounts/verify_credentials")
371 assert %{"id" => id, "source" => %{"privacy" => "public"}} = json_response(conn, 200)
372 assert id == to_string(user.id)
375 test "verify_credentials default scope unlisted", %{conn: conn} do
376 user = insert(:user, %{info: %Pleroma.User.Info{default_scope: "unlisted"}})
380 |> assign(:user, user)
381 |> get("/api/v1/accounts/verify_credentials")
383 assert %{"id" => id, "source" => %{"privacy" => "unlisted"}} = json_response(conn, 200)
384 assert id == to_string(user.id)
387 test "apps/verify_credentials", %{conn: conn} do
388 token = insert(:oauth_token)
392 |> assign(:user, token.user)
393 |> assign(:token, token)
394 |> get("/api/v1/apps/verify_credentials")
396 app = Repo.preload(token, :app).app
399 "name" => app.client_name,
400 "website" => app.website,
401 "vapid_key" => Push.vapid_config() |> Keyword.get(:public_key)
404 assert expected == json_response(conn, 200)
407 test "creates an oauth app", %{conn: conn} do
409 app_attrs = build(:oauth_app)
413 |> assign(:user, user)
414 |> post("/api/v1/apps", %{
415 client_name: app_attrs.client_name,
416 redirect_uris: app_attrs.redirect_uris
419 [app] = Repo.all(App)
422 "name" => app.client_name,
423 "website" => app.website,
424 "client_id" => app.client_id,
425 "client_secret" => app.client_secret,
426 "id" => app.id |> to_string(),
427 "redirect_uri" => app.redirect_uris,
428 "vapid_key" => Push.vapid_config() |> Keyword.get(:public_key)
431 assert expected == json_response(conn, 200)
434 test "get a status", %{conn: conn} do
435 activity = insert(:note_activity)
439 |> get("/api/v1/statuses/#{activity.id}")
441 assert %{"id" => id} = json_response(conn, 200)
442 assert id == to_string(activity.id)
445 describe "deleting a status" do
446 test "when you created it", %{conn: conn} do
447 activity = insert(:note_activity)
448 author = User.get_by_ap_id(activity.data["actor"])
452 |> assign(:user, author)
453 |> delete("/api/v1/statuses/#{activity.id}")
455 assert %{} = json_response(conn, 200)
457 refute Activity.get_by_id(activity.id)
460 test "when you didn't create it", %{conn: conn} do
461 activity = insert(:note_activity)
466 |> assign(:user, user)
467 |> delete("/api/v1/statuses/#{activity.id}")
469 assert %{"error" => _} = json_response(conn, 403)
471 assert Activity.get_by_id(activity.id) == activity
474 test "when you're an admin or moderator", %{conn: conn} do
475 activity1 = insert(:note_activity)
476 activity2 = insert(:note_activity)
477 admin = insert(:user, info: %{is_admin: true})
478 moderator = insert(:user, info: %{is_moderator: true})
482 |> assign(:user, admin)
483 |> delete("/api/v1/statuses/#{activity1.id}")
485 assert %{} = json_response(res_conn, 200)
489 |> assign(:user, moderator)
490 |> delete("/api/v1/statuses/#{activity2.id}")
492 assert %{} = json_response(res_conn, 200)
494 refute Activity.get_by_id(activity1.id)
495 refute Activity.get_by_id(activity2.id)
499 describe "filters" do
500 test "creating a filter", %{conn: conn} do
503 filter = %Pleroma.Filter{
510 |> assign(:user, user)
511 |> post("/api/v1/filters", %{"phrase" => filter.phrase, context: filter.context})
513 assert response = json_response(conn, 200)
514 assert response["phrase"] == filter.phrase
515 assert response["context"] == filter.context
516 assert response["id"] != nil
517 assert response["id"] != ""
520 test "fetching a list of filters", %{conn: conn} do
523 query_one = %Pleroma.Filter{
530 query_two = %Pleroma.Filter{
537 {:ok, filter_one} = Pleroma.Filter.create(query_one)
538 {:ok, filter_two} = Pleroma.Filter.create(query_two)
542 |> assign(:user, user)
543 |> get("/api/v1/filters")
544 |> json_response(200)
550 filters: [filter_two, filter_one]
554 test "get a filter", %{conn: conn} do
557 query = %Pleroma.Filter{
564 {:ok, filter} = Pleroma.Filter.create(query)
568 |> assign(:user, user)
569 |> get("/api/v1/filters/#{filter.filter_id}")
571 assert _response = json_response(conn, 200)
574 test "update a filter", %{conn: conn} do
577 query = %Pleroma.Filter{
584 {:ok, _filter} = Pleroma.Filter.create(query)
586 new = %Pleroma.Filter{
593 |> assign(:user, user)
594 |> put("/api/v1/filters/#{query.filter_id}", %{
599 assert response = json_response(conn, 200)
600 assert response["phrase"] == new.phrase
601 assert response["context"] == new.context
604 test "delete a filter", %{conn: conn} do
607 query = %Pleroma.Filter{
614 {:ok, filter} = Pleroma.Filter.create(query)
618 |> assign(:user, user)
619 |> delete("/api/v1/filters/#{filter.filter_id}")
621 assert response = json_response(conn, 200)
622 assert response == %{}
627 test "creating a list", %{conn: conn} do
632 |> assign(:user, user)
633 |> post("/api/v1/lists", %{"title" => "cuties"})
635 assert %{"title" => title} = json_response(conn, 200)
636 assert title == "cuties"
639 test "adding users to a list", %{conn: conn} do
641 other_user = insert(:user)
642 {:ok, list} = Pleroma.List.create("name", user)
646 |> assign(:user, user)
647 |> post("/api/v1/lists/#{list.id}/accounts", %{"account_ids" => [other_user.id]})
649 assert %{} == json_response(conn, 200)
650 %Pleroma.List{following: following} = Pleroma.List.get(list.id, user)
651 assert following == [other_user.follower_address]
654 test "removing users from a list", %{conn: conn} do
656 other_user = insert(:user)
657 third_user = insert(:user)
658 {:ok, list} = Pleroma.List.create("name", user)
659 {:ok, list} = Pleroma.List.follow(list, other_user)
660 {:ok, list} = Pleroma.List.follow(list, third_user)
664 |> assign(:user, user)
665 |> delete("/api/v1/lists/#{list.id}/accounts", %{"account_ids" => [other_user.id]})
667 assert %{} == json_response(conn, 200)
668 %Pleroma.List{following: following} = Pleroma.List.get(list.id, user)
669 assert following == [third_user.follower_address]
672 test "listing users in a list", %{conn: conn} do
674 other_user = insert(:user)
675 {:ok, list} = Pleroma.List.create("name", user)
676 {:ok, list} = Pleroma.List.follow(list, other_user)
680 |> assign(:user, user)
681 |> get("/api/v1/lists/#{list.id}/accounts", %{"account_ids" => [other_user.id]})
683 assert [%{"id" => id}] = json_response(conn, 200)
684 assert id == to_string(other_user.id)
687 test "retrieving a list", %{conn: conn} do
689 {:ok, list} = Pleroma.List.create("name", user)
693 |> assign(:user, user)
694 |> get("/api/v1/lists/#{list.id}")
696 assert %{"id" => id} = json_response(conn, 200)
697 assert id == to_string(list.id)
700 test "renaming a list", %{conn: conn} do
702 {:ok, list} = Pleroma.List.create("name", user)
706 |> assign(:user, user)
707 |> put("/api/v1/lists/#{list.id}", %{"title" => "newname"})
709 assert %{"title" => name} = json_response(conn, 200)
710 assert name == "newname"
713 test "deleting a list", %{conn: conn} do
715 {:ok, list} = Pleroma.List.create("name", user)
719 |> assign(:user, user)
720 |> delete("/api/v1/lists/#{list.id}")
722 assert %{} = json_response(conn, 200)
723 assert is_nil(Repo.get(Pleroma.List, list.id))
726 test "list timeline", %{conn: conn} do
728 other_user = insert(:user)
729 {:ok, _activity_one} = TwitterAPI.create_status(user, %{"status" => "Marisa is cute."})
730 {:ok, activity_two} = TwitterAPI.create_status(other_user, %{"status" => "Marisa is cute."})
731 {:ok, list} = Pleroma.List.create("name", user)
732 {:ok, list} = Pleroma.List.follow(list, other_user)
736 |> assign(:user, user)
737 |> get("/api/v1/timelines/list/#{list.id}")
739 assert [%{"id" => id}] = json_response(conn, 200)
741 assert id == to_string(activity_two.id)
744 test "list timeline does not leak non-public statuses for unfollowed users", %{conn: conn} do
746 other_user = insert(:user)
747 {:ok, activity_one} = TwitterAPI.create_status(other_user, %{"status" => "Marisa is cute."})
749 {:ok, _activity_two} =
750 TwitterAPI.create_status(other_user, %{
751 "status" => "Marisa is cute.",
752 "visibility" => "private"
755 {:ok, list} = Pleroma.List.create("name", user)
756 {:ok, list} = Pleroma.List.follow(list, other_user)
760 |> assign(:user, user)
761 |> get("/api/v1/timelines/list/#{list.id}")
763 assert [%{"id" => id}] = json_response(conn, 200)
765 assert id == to_string(activity_one.id)
769 describe "notifications" do
770 test "list of notifications", %{conn: conn} do
772 other_user = insert(:user)
775 TwitterAPI.create_status(other_user, %{"status" => "hi @#{user.nickname}"})
777 {:ok, [_notification]} = Notification.create_notifications(activity)
781 |> assign(:user, user)
782 |> get("/api/v1/notifications")
785 "hi <span class=\"h-card\"><a data-user=\"#{user.id}\" class=\"u-url mention\" href=\"#{
787 }\">@<span>#{user.nickname}</span></a></span>"
789 assert [%{"status" => %{"content" => response}} | _rest] = json_response(conn, 200)
790 assert response == expected_response
793 test "getting a single notification", %{conn: conn} do
795 other_user = insert(:user)
798 TwitterAPI.create_status(other_user, %{"status" => "hi @#{user.nickname}"})
800 {:ok, [notification]} = Notification.create_notifications(activity)
804 |> assign(:user, user)
805 |> get("/api/v1/notifications/#{notification.id}")
808 "hi <span class=\"h-card\"><a data-user=\"#{user.id}\" class=\"u-url mention\" href=\"#{
810 }\">@<span>#{user.nickname}</span></a></span>"
812 assert %{"status" => %{"content" => response}} = json_response(conn, 200)
813 assert response == expected_response
816 test "dismissing a single notification", %{conn: conn} do
818 other_user = insert(:user)
821 TwitterAPI.create_status(other_user, %{"status" => "hi @#{user.nickname}"})
823 {:ok, [notification]} = Notification.create_notifications(activity)
827 |> assign(:user, user)
828 |> post("/api/v1/notifications/dismiss", %{"id" => notification.id})
830 assert %{} = json_response(conn, 200)
833 test "clearing all notifications", %{conn: conn} do
835 other_user = insert(:user)
838 TwitterAPI.create_status(other_user, %{"status" => "hi @#{user.nickname}"})
840 {:ok, [_notification]} = Notification.create_notifications(activity)
844 |> assign(:user, user)
845 |> post("/api/v1/notifications/clear")
847 assert %{} = json_response(conn, 200)
851 |> assign(:user, user)
852 |> get("/api/v1/notifications")
854 assert all = json_response(conn, 200)
858 test "paginates notifications using min_id, since_id, max_id, and limit", %{conn: conn} do
860 other_user = insert(:user)
862 {:ok, activity1} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
863 {:ok, activity2} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
864 {:ok, activity3} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
865 {:ok, activity4} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
867 notification1_id = Repo.get_by(Notification, activity_id: activity1.id).id |> to_string()
868 notification2_id = Repo.get_by(Notification, activity_id: activity2.id).id |> to_string()
869 notification3_id = Repo.get_by(Notification, activity_id: activity3.id).id |> to_string()
870 notification4_id = Repo.get_by(Notification, activity_id: activity4.id).id |> to_string()
874 |> assign(:user, user)
879 |> get("/api/v1/notifications?limit=2&min_id=#{notification1_id}")
881 result = json_response(conn_res, 200)
882 assert [%{"id" => ^notification3_id}, %{"id" => ^notification2_id}] = result
887 |> get("/api/v1/notifications?limit=2&since_id=#{notification1_id}")
889 result = json_response(conn_res, 200)
890 assert [%{"id" => ^notification4_id}, %{"id" => ^notification3_id}] = result
895 |> get("/api/v1/notifications?limit=2&max_id=#{notification4_id}")
897 result = json_response(conn_res, 200)
898 assert [%{"id" => ^notification3_id}, %{"id" => ^notification2_id}] = result
901 test "filters notifications using exclude_types", %{conn: conn} do
903 other_user = insert(:user)
905 {:ok, mention_activity} = CommonAPI.post(other_user, %{"status" => "hey @#{user.nickname}"})
906 {:ok, create_activity} = CommonAPI.post(user, %{"status" => "hey"})
907 {:ok, favorite_activity, _} = CommonAPI.favorite(create_activity.id, other_user)
908 {:ok, reblog_activity, _} = CommonAPI.repeat(create_activity.id, other_user)
909 {:ok, _, _, follow_activity} = CommonAPI.follow(other_user, user)
911 mention_notification_id =
912 Repo.get_by(Notification, activity_id: mention_activity.id).id |> to_string()
914 favorite_notification_id =
915 Repo.get_by(Notification, activity_id: favorite_activity.id).id |> to_string()
917 reblog_notification_id =
918 Repo.get_by(Notification, activity_id: reblog_activity.id).id |> to_string()
920 follow_notification_id =
921 Repo.get_by(Notification, activity_id: follow_activity.id).id |> to_string()
925 |> assign(:user, user)
928 get(conn, "/api/v1/notifications", %{exclude_types: ["mention", "favourite", "reblog"]})
930 assert [%{"id" => ^follow_notification_id}] = json_response(conn_res, 200)
933 get(conn, "/api/v1/notifications", %{exclude_types: ["favourite", "reblog", "follow"]})
935 assert [%{"id" => ^mention_notification_id}] = json_response(conn_res, 200)
938 get(conn, "/api/v1/notifications", %{exclude_types: ["reblog", "follow", "mention"]})
940 assert [%{"id" => ^favorite_notification_id}] = json_response(conn_res, 200)
943 get(conn, "/api/v1/notifications", %{exclude_types: ["follow", "mention", "favourite"]})
945 assert [%{"id" => ^reblog_notification_id}] = json_response(conn_res, 200)
948 test "destroy multiple", %{conn: conn} do
950 other_user = insert(:user)
952 {:ok, activity1} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
953 {:ok, activity2} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
954 {:ok, activity3} = CommonAPI.post(user, %{"status" => "hi @#{other_user.nickname}"})
955 {:ok, activity4} = CommonAPI.post(user, %{"status" => "hi @#{other_user.nickname}"})
957 notification1_id = Repo.get_by(Notification, activity_id: activity1.id).id |> to_string()
958 notification2_id = Repo.get_by(Notification, activity_id: activity2.id).id |> to_string()
959 notification3_id = Repo.get_by(Notification, activity_id: activity3.id).id |> to_string()
960 notification4_id = Repo.get_by(Notification, activity_id: activity4.id).id |> to_string()
964 |> assign(:user, user)
968 |> get("/api/v1/notifications")
970 result = json_response(conn_res, 200)
971 assert [%{"id" => ^notification2_id}, %{"id" => ^notification1_id}] = result
975 |> assign(:user, other_user)
979 |> get("/api/v1/notifications")
981 result = json_response(conn_res, 200)
982 assert [%{"id" => ^notification4_id}, %{"id" => ^notification3_id}] = result
986 |> delete("/api/v1/notifications/destroy_multiple", %{
987 "ids" => [notification1_id, notification2_id]
990 assert json_response(conn_destroy, 200) == %{}
994 |> get("/api/v1/notifications")
996 result = json_response(conn_res, 200)
997 assert [%{"id" => ^notification4_id}, %{"id" => ^notification3_id}] = result
1001 describe "reblogging" do
1002 test "reblogs and returns the reblogged status", %{conn: conn} do
1003 activity = insert(:note_activity)
1004 user = insert(:user)
1008 |> assign(:user, user)
1009 |> post("/api/v1/statuses/#{activity.id}/reblog")
1012 "reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 1},
1014 } = json_response(conn, 200)
1016 assert to_string(activity.id) == id
1019 test "reblogged status for another user", %{conn: conn} do
1020 activity = insert(:note_activity)
1021 user1 = insert(:user)
1022 user2 = insert(:user)
1023 user3 = insert(:user)
1024 {:ok, reblog_activity1, _object} = CommonAPI.repeat(activity.id, user1)
1025 {:ok, _, _object} = CommonAPI.repeat(activity.id, user2)
1029 |> assign(:user, user3)
1030 |> get("/api/v1/statuses/#{reblog_activity1.id}")
1033 "reblog" => %{"id" => id, "reblogged" => false, "reblogs_count" => 2},
1034 "reblogged" => false
1035 } = json_response(conn_res, 200)
1039 |> assign(:user, user2)
1040 |> get("/api/v1/statuses/#{reblog_activity1.id}")
1043 "reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 2},
1045 } = json_response(conn_res, 200)
1047 assert to_string(activity.id) == id
1051 describe "unreblogging" do
1052 test "unreblogs and returns the unreblogged status", %{conn: conn} do
1053 activity = insert(:note_activity)
1054 user = insert(:user)
1056 {:ok, _, _} = CommonAPI.repeat(activity.id, user)
1060 |> assign(:user, user)
1061 |> post("/api/v1/statuses/#{activity.id}/unreblog")
1063 assert %{"id" => id, "reblogged" => false, "reblogs_count" => 0} = json_response(conn, 200)
1065 assert to_string(activity.id) == id
1069 describe "favoriting" do
1070 test "favs a status and returns it", %{conn: conn} do
1071 activity = insert(:note_activity)
1072 user = insert(:user)
1076 |> assign(:user, user)
1077 |> post("/api/v1/statuses/#{activity.id}/favourite")
1079 assert %{"id" => id, "favourites_count" => 1, "favourited" => true} =
1080 json_response(conn, 200)
1082 assert to_string(activity.id) == id
1085 test "returns 500 for a wrong id", %{conn: conn} do
1086 user = insert(:user)
1090 |> assign(:user, user)
1091 |> post("/api/v1/statuses/1/favourite")
1092 |> json_response(500)
1094 assert resp == "Something went wrong"
1098 describe "unfavoriting" do
1099 test "unfavorites a status and returns it", %{conn: conn} do
1100 activity = insert(:note_activity)
1101 user = insert(:user)
1103 {:ok, _, _} = CommonAPI.favorite(activity.id, user)
1107 |> assign(:user, user)
1108 |> post("/api/v1/statuses/#{activity.id}/unfavourite")
1110 assert %{"id" => id, "favourites_count" => 0, "favourited" => false} =
1111 json_response(conn, 200)
1113 assert to_string(activity.id) == id
1117 describe "user timelines" do
1118 test "gets a users statuses", %{conn: conn} do
1119 user_one = insert(:user)
1120 user_two = insert(:user)
1121 user_three = insert(:user)
1123 {:ok, user_three} = User.follow(user_three, user_one)
1125 {:ok, activity} = CommonAPI.post(user_one, %{"status" => "HI!!!"})
1127 {:ok, direct_activity} =
1128 CommonAPI.post(user_one, %{
1129 "status" => "Hi, @#{user_two.nickname}.",
1130 "visibility" => "direct"
1133 {:ok, private_activity} =
1134 CommonAPI.post(user_one, %{"status" => "private", "visibility" => "private"})
1138 |> get("/api/v1/accounts/#{user_one.id}/statuses")
1140 assert [%{"id" => id}] = json_response(resp, 200)
1141 assert id == to_string(activity.id)
1145 |> assign(:user, user_two)
1146 |> get("/api/v1/accounts/#{user_one.id}/statuses")
1148 assert [%{"id" => id_one}, %{"id" => id_two}] = json_response(resp, 200)
1149 assert id_one == to_string(direct_activity.id)
1150 assert id_two == to_string(activity.id)
1154 |> assign(:user, user_three)
1155 |> get("/api/v1/accounts/#{user_one.id}/statuses")
1157 assert [%{"id" => id_one}, %{"id" => id_two}] = json_response(resp, 200)
1158 assert id_one == to_string(private_activity.id)
1159 assert id_two == to_string(activity.id)
1162 test "unimplemented pinned statuses feature", %{conn: conn} do
1163 note = insert(:note_activity)
1164 user = User.get_by_ap_id(note.data["actor"])
1168 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
1170 assert json_response(conn, 200) == []
1173 test "gets an users media", %{conn: conn} do
1174 note = insert(:note_activity)
1175 user = User.get_by_ap_id(note.data["actor"])
1177 file = %Plug.Upload{
1178 content_type: "image/jpg",
1179 path: Path.absname("test/fixtures/image.jpg"),
1180 filename: "an_image.jpg"
1184 TwitterAPI.upload(file, user, "json")
1188 TwitterAPI.create_status(user, %{"status" => "cofe", "media_ids" => [media["media_id"]]})
1192 |> get("/api/v1/accounts/#{user.id}/statuses", %{"only_media" => "true"})
1194 assert [%{"id" => id}] = json_response(conn, 200)
1195 assert id == to_string(image_post.id)
1199 |> get("/api/v1/accounts/#{user.id}/statuses", %{"only_media" => "1"})
1201 assert [%{"id" => id}] = json_response(conn, 200)
1202 assert id == to_string(image_post.id)
1205 test "gets a user's statuses without reblogs", %{conn: conn} do
1206 user = insert(:user)
1207 {:ok, post} = CommonAPI.post(user, %{"status" => "HI!!!"})
1208 {:ok, _, _} = CommonAPI.repeat(post.id, user)
1212 |> get("/api/v1/accounts/#{user.id}/statuses", %{"exclude_reblogs" => "true"})
1214 assert [%{"id" => id}] = json_response(conn, 200)
1215 assert id == to_string(post.id)
1219 |> get("/api/v1/accounts/#{user.id}/statuses", %{"exclude_reblogs" => "1"})
1221 assert [%{"id" => id}] = json_response(conn, 200)
1222 assert id == to_string(post.id)
1226 describe "user relationships" do
1227 test "returns the relationships for the current user", %{conn: conn} do
1228 user = insert(:user)
1229 other_user = insert(:user)
1230 {:ok, user} = User.follow(user, other_user)
1234 |> assign(:user, user)
1235 |> get("/api/v1/accounts/relationships", %{"id" => [other_user.id]})
1237 assert [relationship] = json_response(conn, 200)
1239 assert to_string(other_user.id) == relationship["id"]
1243 describe "locked accounts" do
1244 test "/api/v1/follow_requests works" do
1245 user = insert(:user, %{info: %Pleroma.User.Info{locked: true}})
1246 other_user = insert(:user)
1248 {:ok, _activity} = ActivityPub.follow(other_user, user)
1250 user = User.get_by_id(user.id)
1251 other_user = User.get_by_id(other_user.id)
1253 assert User.following?(other_user, user) == false
1257 |> assign(:user, user)
1258 |> get("/api/v1/follow_requests")
1260 assert [relationship] = json_response(conn, 200)
1261 assert to_string(other_user.id) == relationship["id"]
1264 test "/api/v1/follow_requests/:id/authorize works" do
1265 user = insert(:user, %{info: %User.Info{locked: true}})
1266 other_user = insert(:user)
1268 {:ok, _activity} = ActivityPub.follow(other_user, user)
1270 user = User.get_by_id(user.id)
1271 other_user = User.get_by_id(other_user.id)
1273 assert User.following?(other_user, user) == false
1277 |> assign(:user, user)
1278 |> post("/api/v1/follow_requests/#{other_user.id}/authorize")
1280 assert relationship = json_response(conn, 200)
1281 assert to_string(other_user.id) == relationship["id"]
1283 user = User.get_by_id(user.id)
1284 other_user = User.get_by_id(other_user.id)
1286 assert User.following?(other_user, user) == true
1289 test "verify_credentials", %{conn: conn} do
1290 user = insert(:user, %{info: %Pleroma.User.Info{default_scope: "private"}})
1294 |> assign(:user, user)
1295 |> get("/api/v1/accounts/verify_credentials")
1297 assert %{"id" => id, "source" => %{"privacy" => "private"}} = json_response(conn, 200)
1298 assert id == to_string(user.id)
1301 test "/api/v1/follow_requests/:id/reject works" do
1302 user = insert(:user, %{info: %Pleroma.User.Info{locked: true}})
1303 other_user = insert(:user)
1305 {:ok, _activity} = ActivityPub.follow(other_user, user)
1307 user = User.get_by_id(user.id)
1311 |> assign(:user, user)
1312 |> post("/api/v1/follow_requests/#{other_user.id}/reject")
1314 assert relationship = json_response(conn, 200)
1315 assert to_string(other_user.id) == relationship["id"]
1317 user = User.get_by_id(user.id)
1318 other_user = User.get_by_id(other_user.id)
1320 assert User.following?(other_user, user) == false
1324 test "account fetching", %{conn: conn} do
1325 user = insert(:user)
1329 |> get("/api/v1/accounts/#{user.id}")
1331 assert %{"id" => id} = json_response(conn, 200)
1332 assert id == to_string(user.id)
1336 |> get("/api/v1/accounts/-1")
1338 assert %{"error" => "Can't find user"} = json_response(conn, 404)
1341 test "account fetching also works nickname", %{conn: conn} do
1342 user = insert(:user)
1346 |> get("/api/v1/accounts/#{user.nickname}")
1348 assert %{"id" => id} = json_response(conn, 200)
1349 assert id == user.id
1352 test "media upload", %{conn: conn} do
1353 file = %Plug.Upload{
1354 content_type: "image/jpg",
1355 path: Path.absname("test/fixtures/image.jpg"),
1356 filename: "an_image.jpg"
1359 desc = "Description of the image"
1361 user = insert(:user)
1365 |> assign(:user, user)
1366 |> post("/api/v1/media", %{"file" => file, "description" => desc})
1368 assert media = json_response(conn, 200)
1370 assert media["type"] == "image"
1371 assert media["description"] == desc
1374 object = Repo.get(Object, media["id"])
1375 assert object.data["actor"] == User.ap_id(user)
1378 test "hashtag timeline", %{conn: conn} do
1379 following = insert(:user)
1382 {:ok, activity} = TwitterAPI.create_status(following, %{"status" => "test #2hu"})
1384 {:ok, [_activity]} =
1385 OStatus.fetch_activity_from_url("https://shitposter.club/notice/2827873")
1389 |> get("/api/v1/timelines/tag/2hu")
1391 assert [%{"id" => id}] = json_response(nconn, 200)
1393 assert id == to_string(activity.id)
1395 # works for different capitalization too
1398 |> get("/api/v1/timelines/tag/2HU")
1400 assert [%{"id" => id}] = json_response(nconn, 200)
1402 assert id == to_string(activity.id)
1406 test "multi-hashtag timeline", %{conn: conn} do
1407 user = insert(:user)
1409 {:ok, activity_test} = CommonAPI.post(user, %{"status" => "#test"})
1410 {:ok, activity_test1} = CommonAPI.post(user, %{"status" => "#test #test1"})
1411 {:ok, activity_none} = CommonAPI.post(user, %{"status" => "#test #none"})
1415 |> get("/api/v1/timelines/tag/test", %{"any" => ["test1"]})
1417 [status_none, status_test1, status_test] = json_response(any_test, 200)
1419 assert to_string(activity_test.id) == status_test["id"]
1420 assert to_string(activity_test1.id) == status_test1["id"]
1421 assert to_string(activity_none.id) == status_none["id"]
1425 |> get("/api/v1/timelines/tag/test", %{"all" => ["test1"], "none" => ["none"]})
1427 assert [status_test1] == json_response(restricted_test, 200)
1429 all_test = conn |> get("/api/v1/timelines/tag/test", %{"all" => ["none"]})
1431 assert [status_none] == json_response(all_test, 200)
1434 test "getting followers", %{conn: conn} do
1435 user = insert(:user)
1436 other_user = insert(:user)
1437 {:ok, user} = User.follow(user, other_user)
1441 |> get("/api/v1/accounts/#{other_user.id}/followers")
1443 assert [%{"id" => id}] = json_response(conn, 200)
1444 assert id == to_string(user.id)
1447 test "getting followers, hide_followers", %{conn: conn} do
1448 user = insert(:user)
1449 other_user = insert(:user, %{info: %{hide_followers: true}})
1450 {:ok, _user} = User.follow(user, other_user)
1454 |> get("/api/v1/accounts/#{other_user.id}/followers")
1456 assert [] == json_response(conn, 200)
1459 test "getting followers, hide_followers, same user requesting", %{conn: conn} do
1460 user = insert(:user)
1461 other_user = insert(:user, %{info: %{hide_followers: true}})
1462 {:ok, _user} = User.follow(user, other_user)
1466 |> assign(:user, other_user)
1467 |> get("/api/v1/accounts/#{other_user.id}/followers")
1469 refute [] == json_response(conn, 200)
1472 test "getting followers, pagination", %{conn: conn} do
1473 user = insert(:user)
1474 follower1 = insert(:user)
1475 follower2 = insert(:user)
1476 follower3 = insert(:user)
1477 {:ok, _} = User.follow(follower1, user)
1478 {:ok, _} = User.follow(follower2, user)
1479 {:ok, _} = User.follow(follower3, user)
1483 |> assign(:user, user)
1487 |> get("/api/v1/accounts/#{user.id}/followers?since_id=#{follower1.id}")
1489 assert [%{"id" => id3}, %{"id" => id2}] = json_response(res_conn, 200)
1490 assert id3 == follower3.id
1491 assert id2 == follower2.id
1495 |> get("/api/v1/accounts/#{user.id}/followers?max_id=#{follower3.id}")
1497 assert [%{"id" => id2}, %{"id" => id1}] = json_response(res_conn, 200)
1498 assert id2 == follower2.id
1499 assert id1 == follower1.id
1503 |> get("/api/v1/accounts/#{user.id}/followers?limit=1&max_id=#{follower3.id}")
1505 assert [%{"id" => id2}] = json_response(res_conn, 200)
1506 assert id2 == follower2.id
1508 assert [link_header] = get_resp_header(res_conn, "link")
1509 assert link_header =~ ~r/min_id=#{follower2.id}/
1510 assert link_header =~ ~r/max_id=#{follower2.id}/
1513 test "getting following", %{conn: conn} do
1514 user = insert(:user)
1515 other_user = insert(:user)
1516 {:ok, user} = User.follow(user, other_user)
1520 |> get("/api/v1/accounts/#{user.id}/following")
1522 assert [%{"id" => id}] = json_response(conn, 200)
1523 assert id == to_string(other_user.id)
1526 test "getting following, hide_follows", %{conn: conn} do
1527 user = insert(:user, %{info: %{hide_follows: true}})
1528 other_user = insert(:user)
1529 {:ok, user} = User.follow(user, other_user)
1533 |> get("/api/v1/accounts/#{user.id}/following")
1535 assert [] == json_response(conn, 200)
1538 test "getting following, hide_follows, same user requesting", %{conn: conn} do
1539 user = insert(:user, %{info: %{hide_follows: true}})
1540 other_user = insert(:user)
1541 {:ok, user} = User.follow(user, other_user)
1545 |> assign(:user, user)
1546 |> get("/api/v1/accounts/#{user.id}/following")
1548 refute [] == json_response(conn, 200)
1551 test "getting following, pagination", %{conn: conn} do
1552 user = insert(:user)
1553 following1 = insert(:user)
1554 following2 = insert(:user)
1555 following3 = insert(:user)
1556 {:ok, _} = User.follow(user, following1)
1557 {:ok, _} = User.follow(user, following2)
1558 {:ok, _} = User.follow(user, following3)
1562 |> assign(:user, user)
1566 |> get("/api/v1/accounts/#{user.id}/following?since_id=#{following1.id}")
1568 assert [%{"id" => id3}, %{"id" => id2}] = json_response(res_conn, 200)
1569 assert id3 == following3.id
1570 assert id2 == following2.id
1574 |> get("/api/v1/accounts/#{user.id}/following?max_id=#{following3.id}")
1576 assert [%{"id" => id2}, %{"id" => id1}] = json_response(res_conn, 200)
1577 assert id2 == following2.id
1578 assert id1 == following1.id
1582 |> get("/api/v1/accounts/#{user.id}/following?limit=1&max_id=#{following3.id}")
1584 assert [%{"id" => id2}] = json_response(res_conn, 200)
1585 assert id2 == following2.id
1587 assert [link_header] = get_resp_header(res_conn, "link")
1588 assert link_header =~ ~r/min_id=#{following2.id}/
1589 assert link_header =~ ~r/max_id=#{following2.id}/
1592 test "following / unfollowing a user", %{conn: conn} do
1593 user = insert(:user)
1594 other_user = insert(:user)
1598 |> assign(:user, user)
1599 |> post("/api/v1/accounts/#{other_user.id}/follow")
1601 assert %{"id" => _id, "following" => true} = json_response(conn, 200)
1603 user = User.get_by_id(user.id)
1607 |> assign(:user, user)
1608 |> post("/api/v1/accounts/#{other_user.id}/unfollow")
1610 assert %{"id" => _id, "following" => false} = json_response(conn, 200)
1612 user = User.get_by_id(user.id)
1616 |> assign(:user, user)
1617 |> post("/api/v1/follows", %{"uri" => other_user.nickname})
1619 assert %{"id" => id} = json_response(conn, 200)
1620 assert id == to_string(other_user.id)
1623 test "following without reblogs" do
1624 follower = insert(:user)
1625 followed = insert(:user)
1626 other_user = insert(:user)
1630 |> assign(:user, follower)
1631 |> post("/api/v1/accounts/#{followed.id}/follow?reblogs=false")
1633 assert %{"showing_reblogs" => false} = json_response(conn, 200)
1635 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "hey"})
1636 {:ok, reblog, _} = CommonAPI.repeat(activity.id, followed)
1640 |> assign(:user, User.get_cached_by_id(follower.id))
1641 |> get("/api/v1/timelines/home")
1643 assert [] == json_response(conn, 200)
1647 |> assign(:user, follower)
1648 |> post("/api/v1/accounts/#{followed.id}/follow?reblogs=true")
1650 assert %{"showing_reblogs" => true} = json_response(conn, 200)
1654 |> assign(:user, User.get_cached_by_id(follower.id))
1655 |> get("/api/v1/timelines/home")
1657 expected_activity_id = reblog.id
1658 assert [%{"id" => ^expected_activity_id}] = json_response(conn, 200)
1661 test "following / unfollowing errors" do
1662 user = insert(:user)
1666 |> assign(:user, user)
1669 conn_res = post(conn, "/api/v1/accounts/#{user.id}/follow")
1670 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
1673 user = User.get_cached_by_id(user.id)
1674 conn_res = post(conn, "/api/v1/accounts/#{user.id}/unfollow")
1675 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
1677 # self follow via uri
1678 user = User.get_cached_by_id(user.id)
1679 conn_res = post(conn, "/api/v1/follows", %{"uri" => user.nickname})
1680 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
1682 # follow non existing user
1683 conn_res = post(conn, "/api/v1/accounts/doesntexist/follow")
1684 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
1686 # follow non existing user via uri
1687 conn_res = post(conn, "/api/v1/follows", %{"uri" => "doesntexist"})
1688 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
1690 # unfollow non existing user
1691 conn_res = post(conn, "/api/v1/accounts/doesntexist/unfollow")
1692 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
1695 test "muting / unmuting a user", %{conn: conn} do
1696 user = insert(:user)
1697 other_user = insert(:user)
1701 |> assign(:user, user)
1702 |> post("/api/v1/accounts/#{other_user.id}/mute")
1704 assert %{"id" => _id, "muting" => true} = json_response(conn, 200)
1706 user = User.get_by_id(user.id)
1710 |> assign(:user, user)
1711 |> post("/api/v1/accounts/#{other_user.id}/unmute")
1713 assert %{"id" => _id, "muting" => false} = json_response(conn, 200)
1716 test "subscribing / unsubscribing to a user", %{conn: conn} do
1717 user = insert(:user)
1718 subscription_target = insert(:user)
1722 |> assign(:user, user)
1723 |> post("/api/v1/pleroma/accounts/#{subscription_target.id}/subscribe")
1725 assert %{"id" => _id, "subscribing" => true} = json_response(conn, 200)
1729 |> assign(:user, user)
1730 |> post("/api/v1/pleroma/accounts/#{subscription_target.id}/unsubscribe")
1732 assert %{"id" => _id, "subscribing" => false} = json_response(conn, 200)
1735 test "getting a list of mutes", %{conn: conn} do
1736 user = insert(:user)
1737 other_user = insert(:user)
1739 {:ok, user} = User.mute(user, other_user)
1743 |> assign(:user, user)
1744 |> get("/api/v1/mutes")
1746 other_user_id = to_string(other_user.id)
1747 assert [%{"id" => ^other_user_id}] = json_response(conn, 200)
1750 test "blocking / unblocking a user", %{conn: conn} do
1751 user = insert(:user)
1752 other_user = insert(:user)
1756 |> assign(:user, user)
1757 |> post("/api/v1/accounts/#{other_user.id}/block")
1759 assert %{"id" => _id, "blocking" => true} = json_response(conn, 200)
1761 user = User.get_by_id(user.id)
1765 |> assign(:user, user)
1766 |> post("/api/v1/accounts/#{other_user.id}/unblock")
1768 assert %{"id" => _id, "blocking" => false} = json_response(conn, 200)
1771 test "getting a list of blocks", %{conn: conn} do
1772 user = insert(:user)
1773 other_user = insert(:user)
1775 {:ok, user} = User.block(user, other_user)
1779 |> assign(:user, user)
1780 |> get("/api/v1/blocks")
1782 other_user_id = to_string(other_user.id)
1783 assert [%{"id" => ^other_user_id}] = json_response(conn, 200)
1786 test "blocking / unblocking a domain", %{conn: conn} do
1787 user = insert(:user)
1788 other_user = insert(:user, %{ap_id: "https://dogwhistle.zone/@pundit"})
1792 |> assign(:user, user)
1793 |> post("/api/v1/domain_blocks", %{"domain" => "dogwhistle.zone"})
1795 assert %{} = json_response(conn, 200)
1796 user = User.get_cached_by_ap_id(user.ap_id)
1797 assert User.blocks?(user, other_user)
1801 |> assign(:user, user)
1802 |> delete("/api/v1/domain_blocks", %{"domain" => "dogwhistle.zone"})
1804 assert %{} = json_response(conn, 200)
1805 user = User.get_cached_by_ap_id(user.ap_id)
1806 refute User.blocks?(user, other_user)
1809 test "getting a list of domain blocks", %{conn: conn} do
1810 user = insert(:user)
1812 {:ok, user} = User.block_domain(user, "bad.site")
1813 {:ok, user} = User.block_domain(user, "even.worse.site")
1817 |> assign(:user, user)
1818 |> get("/api/v1/domain_blocks")
1820 domain_blocks = json_response(conn, 200)
1822 assert "bad.site" in domain_blocks
1823 assert "even.worse.site" in domain_blocks
1826 test "unimplemented follow_requests, blocks, domain blocks" do
1827 user = insert(:user)
1829 ["blocks", "domain_blocks", "follow_requests"]
1830 |> Enum.each(fn endpoint ->
1833 |> assign(:user, user)
1834 |> get("/api/v1/#{endpoint}")
1836 assert [] = json_response(conn, 200)
1840 test "account search", %{conn: conn} do
1841 user = insert(:user)
1842 user_two = insert(:user, %{nickname: "shp@shitposter.club"})
1843 user_three = insert(:user, %{nickname: "shp@heldscal.la", name: "I love 2hu"})
1847 |> assign(:user, user)
1848 |> get("/api/v1/accounts/search", %{"q" => "shp"})
1849 |> json_response(200)
1851 result_ids = for result <- results, do: result["acct"]
1853 assert user_two.nickname in result_ids
1854 assert user_three.nickname in result_ids
1858 |> assign(:user, user)
1859 |> get("/api/v1/accounts/search", %{"q" => "2hu"})
1860 |> json_response(200)
1862 result_ids = for result <- results, do: result["acct"]
1864 assert user_three.nickname in result_ids
1867 test "search", %{conn: conn} do
1868 user = insert(:user)
1869 user_two = insert(:user, %{nickname: "shp@shitposter.club"})
1870 user_three = insert(:user, %{nickname: "shp@heldscal.la", name: "I love 2hu"})
1872 {:ok, activity} = CommonAPI.post(user, %{"status" => "This is about 2hu"})
1875 CommonAPI.post(user, %{
1876 "status" => "This is about 2hu, but private",
1877 "visibility" => "private"
1880 {:ok, _} = CommonAPI.post(user_two, %{"status" => "This isn't"})
1884 |> get("/api/v1/search", %{"q" => "2hu"})
1886 assert results = json_response(conn, 200)
1888 [account | _] = results["accounts"]
1889 assert account["id"] == to_string(user_three.id)
1891 assert results["hashtags"] == []
1893 [status] = results["statuses"]
1894 assert status["id"] == to_string(activity.id)
1897 test "search fetches remote statuses", %{conn: conn} do
1901 |> get("/api/v1/search", %{"q" => "https://shitposter.club/notice/2827873"})
1903 assert results = json_response(conn, 200)
1905 [status] = results["statuses"]
1906 assert status["uri"] == "tag:shitposter.club,2017-05-05:noticeId=2827873:objectType=comment"
1910 test "search doesn't show statuses that it shouldn't", %{conn: conn} do
1912 CommonAPI.post(insert(:user), %{
1913 "status" => "This is about 2hu, but private",
1914 "visibility" => "private"
1920 |> get("/api/v1/search", %{"q" => Object.normalize(activity).data["id"]})
1922 assert results = json_response(conn, 200)
1924 [] = results["statuses"]
1928 test "search fetches remote accounts", %{conn: conn} do
1931 |> get("/api/v1/search", %{"q" => "shp@social.heldscal.la", "resolve" => "true"})
1933 assert results = json_response(conn, 200)
1934 [account] = results["accounts"]
1935 assert account["acct"] == "shp@social.heldscal.la"
1938 test "returns the favorites of a user", %{conn: conn} do
1939 user = insert(:user)
1940 other_user = insert(:user)
1942 {:ok, _} = CommonAPI.post(other_user, %{"status" => "bla"})
1943 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "traps are happy"})
1945 {:ok, _, _} = CommonAPI.favorite(activity.id, user)
1949 |> assign(:user, user)
1950 |> get("/api/v1/favourites")
1952 assert [status] = json_response(first_conn, 200)
1953 assert status["id"] == to_string(activity.id)
1955 assert [{"link", _link_header}] =
1956 Enum.filter(first_conn.resp_headers, fn element -> match?({"link", _}, element) end)
1958 # Honours query params
1959 {:ok, second_activity} =
1960 CommonAPI.post(other_user, %{
1962 "Trees Are Never Sad Look At Them Every Once In Awhile They're Quite Beautiful."
1965 {:ok, _, _} = CommonAPI.favorite(second_activity.id, user)
1967 last_like = status["id"]
1971 |> assign(:user, user)
1972 |> get("/api/v1/favourites?since_id=#{last_like}")
1974 assert [second_status] = json_response(second_conn, 200)
1975 assert second_status["id"] == to_string(second_activity.id)
1979 |> assign(:user, user)
1980 |> get("/api/v1/favourites?limit=0")
1982 assert [] = json_response(third_conn, 200)
1985 describe "updating credentials" do
1986 test "updates the user's bio", %{conn: conn} do
1987 user = insert(:user)
1988 user2 = insert(:user)
1992 |> assign(:user, user)
1993 |> patch("/api/v1/accounts/update_credentials", %{
1994 "note" => "I drink #cofe with @#{user2.nickname}"
1997 assert user = json_response(conn, 200)
1999 assert user["note"] ==
2000 ~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=") <>
2002 ~s(" class="u-url mention" href=") <>
2003 user2.ap_id <> ~s(">@<span>) <> user2.nickname <> ~s(</span></a></span>)
2006 test "updates the user's locking status", %{conn: conn} do
2007 user = insert(:user)
2011 |> assign(:user, user)
2012 |> patch("/api/v1/accounts/update_credentials", %{locked: "true"})
2014 assert user = json_response(conn, 200)
2015 assert user["locked"] == true
2018 test "updates the user's name", %{conn: conn} do
2019 user = insert(:user)
2023 |> assign(:user, user)
2024 |> patch("/api/v1/accounts/update_credentials", %{"display_name" => "markorepairs"})
2026 assert user = json_response(conn, 200)
2027 assert user["display_name"] == "markorepairs"
2030 test "updates the user's avatar", %{conn: conn} do
2031 user = insert(:user)
2033 new_avatar = %Plug.Upload{
2034 content_type: "image/jpg",
2035 path: Path.absname("test/fixtures/image.jpg"),
2036 filename: "an_image.jpg"
2041 |> assign(:user, user)
2042 |> patch("/api/v1/accounts/update_credentials", %{"avatar" => new_avatar})
2044 assert user_response = json_response(conn, 200)
2045 assert user_response["avatar"] != User.avatar_url(user)
2048 test "updates the user's banner", %{conn: conn} do
2049 user = insert(:user)
2051 new_header = %Plug.Upload{
2052 content_type: "image/jpg",
2053 path: Path.absname("test/fixtures/image.jpg"),
2054 filename: "an_image.jpg"
2059 |> assign(:user, user)
2060 |> patch("/api/v1/accounts/update_credentials", %{"header" => new_header})
2062 assert user_response = json_response(conn, 200)
2063 assert user_response["header"] != User.banner_url(user)
2066 test "requires 'write' permission", %{conn: conn} do
2067 token1 = insert(:oauth_token, scopes: ["read"])
2068 token2 = insert(:oauth_token, scopes: ["write", "follow"])
2070 for token <- [token1, token2] do
2073 |> put_req_header("authorization", "Bearer #{token.token}")
2074 |> patch("/api/v1/accounts/update_credentials", %{})
2076 if token == token1 do
2077 assert %{"error" => "Insufficient permissions: write."} == json_response(conn, 403)
2079 assert json_response(conn, 200)
2085 test "get instance information", %{conn: conn} do
2086 conn = get(conn, "/api/v1/instance")
2087 assert result = json_response(conn, 200)
2089 email = Pleroma.Config.get([:instance, :email])
2090 # Note: not checking for "max_toot_chars" since it's optional
2096 "email" => from_config_email,
2098 "streaming_api" => _
2103 "registrations" => _
2106 assert email == from_config_email
2109 test "get instance stats", %{conn: conn} do
2110 user = insert(:user, %{local: true})
2112 user2 = insert(:user, %{local: true})
2113 {:ok, _user2} = User.deactivate(user2, !user2.info.deactivated)
2115 insert(:user, %{local: false, nickname: "u@peer1.com"})
2116 insert(:user, %{local: false, nickname: "u@peer2.com"})
2118 {:ok, _} = TwitterAPI.create_status(user, %{"status" => "cofe"})
2120 # Stats should count users with missing or nil `info.deactivated` value
2121 user = User.get_by_id(user.id)
2122 info_change = Changeset.change(user.info, %{deactivated: nil})
2126 |> Changeset.change()
2127 |> Changeset.put_embed(:info, info_change)
2128 |> User.update_and_set_cache()
2130 Pleroma.Stats.update_stats()
2132 conn = get(conn, "/api/v1/instance")
2134 assert result = json_response(conn, 200)
2136 stats = result["stats"]
2139 assert stats["user_count"] == 1
2140 assert stats["status_count"] == 1
2141 assert stats["domain_count"] == 2
2144 test "get peers", %{conn: conn} do
2145 insert(:user, %{local: false, nickname: "u@peer1.com"})
2146 insert(:user, %{local: false, nickname: "u@peer2.com"})
2148 Pleroma.Stats.update_stats()
2150 conn = get(conn, "/api/v1/instance/peers")
2152 assert result = json_response(conn, 200)
2154 assert ["peer1.com", "peer2.com"] == Enum.sort(result)
2157 test "put settings", %{conn: conn} do
2158 user = insert(:user)
2162 |> assign(:user, user)
2163 |> put("/api/web/settings", %{"data" => %{"programming" => "socks"}})
2165 assert _result = json_response(conn, 200)
2167 user = User.get_cached_by_ap_id(user.ap_id)
2168 assert user.info.settings == %{"programming" => "socks"}
2171 describe "pinned statuses" do
2173 Pleroma.Config.put([:instance, :max_pinned_statuses], 1)
2175 user = insert(:user)
2176 {:ok, activity} = CommonAPI.post(user, %{"status" => "HI!!!"})
2178 [user: user, activity: activity]
2181 test "returns pinned statuses", %{conn: conn, user: user, activity: activity} do
2182 {:ok, _} = CommonAPI.pin(activity.id, user)
2186 |> assign(:user, user)
2187 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
2188 |> json_response(200)
2190 id_str = to_string(activity.id)
2192 assert [%{"id" => ^id_str, "pinned" => true}] = result
2195 test "pin status", %{conn: conn, user: user, activity: activity} do
2196 id_str = to_string(activity.id)
2198 assert %{"id" => ^id_str, "pinned" => true} =
2200 |> assign(:user, user)
2201 |> post("/api/v1/statuses/#{activity.id}/pin")
2202 |> json_response(200)
2204 assert [%{"id" => ^id_str, "pinned" => true}] =
2206 |> assign(:user, user)
2207 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
2208 |> json_response(200)
2211 test "unpin status", %{conn: conn, user: user, activity: activity} do
2212 {:ok, _} = CommonAPI.pin(activity.id, user)
2214 id_str = to_string(activity.id)
2215 user = refresh_record(user)
2217 assert %{"id" => ^id_str, "pinned" => false} =
2219 |> assign(:user, user)
2220 |> post("/api/v1/statuses/#{activity.id}/unpin")
2221 |> json_response(200)
2225 |> assign(:user, user)
2226 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
2227 |> json_response(200)
2230 test "max pinned statuses", %{conn: conn, user: user, activity: activity_one} do
2231 {:ok, activity_two} = CommonAPI.post(user, %{"status" => "HI!!!"})
2233 id_str_one = to_string(activity_one.id)
2235 assert %{"id" => ^id_str_one, "pinned" => true} =
2237 |> assign(:user, user)
2238 |> post("/api/v1/statuses/#{id_str_one}/pin")
2239 |> json_response(200)
2241 user = refresh_record(user)
2243 assert %{"error" => "You have already pinned the maximum number of statuses"} =
2245 |> assign(:user, user)
2246 |> post("/api/v1/statuses/#{activity_two.id}/pin")
2247 |> json_response(400)
2250 test "Status rich-media Card", %{conn: conn, user: user} do
2251 Pleroma.Config.put([:rich_media, :enabled], true)
2252 {:ok, activity} = CommonAPI.post(user, %{"status" => "http://example.com/ogp"})
2256 |> get("/api/v1/statuses/#{activity.id}/card")
2257 |> json_response(200)
2259 assert response == %{
2260 "image" => "http://ia.media-imdb.com/images/rock.jpg",
2261 "provider_name" => "www.imdb.com",
2262 "provider_url" => "http://www.imdb.com",
2263 "title" => "The Rock",
2265 "url" => "http://www.imdb.com/title/tt0117500/",
2266 "description" => nil,
2269 "image" => "http://ia.media-imdb.com/images/rock.jpg",
2270 "title" => "The Rock",
2271 "type" => "video.movie",
2272 "url" => "http://www.imdb.com/title/tt0117500/"
2277 # works with private posts
2279 CommonAPI.post(user, %{"status" => "http://example.com/ogp", "visibility" => "direct"})
2283 |> assign(:user, user)
2284 |> get("/api/v1/statuses/#{activity.id}/card")
2285 |> json_response(200)
2287 assert response_two == response
2289 Pleroma.Config.put([:rich_media, :enabled], false)
2294 user = insert(:user)
2295 for_user = insert(:user)
2298 CommonAPI.post(user, %{
2299 "status" => "heweoo?"
2303 CommonAPI.post(user, %{
2304 "status" => "heweoo!"
2309 |> assign(:user, for_user)
2310 |> post("/api/v1/statuses/#{activity1.id}/bookmark")
2312 assert json_response(response1, 200)["bookmarked"] == true
2316 |> assign(:user, for_user)
2317 |> post("/api/v1/statuses/#{activity2.id}/bookmark")
2319 assert json_response(response2, 200)["bookmarked"] == true
2323 |> assign(:user, for_user)
2324 |> get("/api/v1/bookmarks")
2326 assert [json_response(response2, 200), json_response(response1, 200)] ==
2327 json_response(bookmarks, 200)
2331 |> assign(:user, for_user)
2332 |> post("/api/v1/statuses/#{activity1.id}/unbookmark")
2334 assert json_response(response1, 200)["bookmarked"] == false
2338 |> assign(:user, for_user)
2339 |> get("/api/v1/bookmarks")
2341 assert [json_response(response2, 200)] == json_response(bookmarks, 200)
2344 describe "conversation muting" do
2346 user = insert(:user)
2347 {:ok, activity} = CommonAPI.post(user, %{"status" => "HIE"})
2349 [user: user, activity: activity]
2352 test "mute conversation", %{conn: conn, user: user, activity: activity} do
2353 id_str = to_string(activity.id)
2355 assert %{"id" => ^id_str, "muted" => true} =
2357 |> assign(:user, user)
2358 |> post("/api/v1/statuses/#{activity.id}/mute")
2359 |> json_response(200)
2362 test "unmute conversation", %{conn: conn, user: user, activity: activity} do
2363 {:ok, _} = CommonAPI.add_mute(user, activity)
2365 id_str = to_string(activity.id)
2366 user = refresh_record(user)
2368 assert %{"id" => ^id_str, "muted" => false} =
2370 |> assign(:user, user)
2371 |> post("/api/v1/statuses/#{activity.id}/unmute")
2372 |> json_response(200)
2376 test "flavours switching (Pleroma Extension)", %{conn: conn} do
2377 user = insert(:user)
2381 |> assign(:user, user)
2382 |> get("/api/v1/pleroma/flavour")
2384 assert "glitch" == json_response(get_old_flavour, 200)
2388 |> assign(:user, user)
2389 |> post("/api/v1/pleroma/flavour/vanilla")
2391 assert "vanilla" == json_response(set_flavour, 200)
2395 |> assign(:user, user)
2396 |> post("/api/v1/pleroma/flavour/vanilla")
2398 assert json_response(set_flavour, 200) == json_response(get_new_flavour, 200)
2401 describe "reports" do
2403 reporter = insert(:user)
2404 target_user = insert(:user)
2406 {:ok, activity} = CommonAPI.post(target_user, %{"status" => "foobar"})
2408 [reporter: reporter, target_user: target_user, activity: activity]
2411 test "submit a basic report", %{conn: conn, reporter: reporter, target_user: target_user} do
2412 assert %{"action_taken" => false, "id" => _} =
2414 |> assign(:user, reporter)
2415 |> post("/api/v1/reports", %{"account_id" => target_user.id})
2416 |> json_response(200)
2419 test "submit a report with statuses and comment", %{
2422 target_user: target_user,
2425 assert %{"action_taken" => false, "id" => _} =
2427 |> assign(:user, reporter)
2428 |> post("/api/v1/reports", %{
2429 "account_id" => target_user.id,
2430 "status_ids" => [activity.id],
2431 "comment" => "bad status!"
2433 |> json_response(200)
2436 test "account_id is required", %{
2441 assert %{"error" => "Valid `account_id` required"} =
2443 |> assign(:user, reporter)
2444 |> post("/api/v1/reports", %{"status_ids" => [activity.id]})
2445 |> json_response(400)
2448 test "comment must be up to the size specified in the config", %{
2451 target_user: target_user
2453 max_size = Pleroma.Config.get([:instance, :max_report_comment_size], 1000)
2454 comment = String.pad_trailing("a", max_size + 1, "a")
2456 error = %{"error" => "Comment must be up to #{max_size} characters"}
2460 |> assign(:user, reporter)
2461 |> post("/api/v1/reports", %{"account_id" => target_user.id, "comment" => comment})
2462 |> json_response(400)
2466 describe "link headers" do
2467 test "preserves parameters in link headers", %{conn: conn} do
2468 user = insert(:user)
2469 other_user = insert(:user)
2472 CommonAPI.post(other_user, %{
2473 "status" => "hi @#{user.nickname}",
2474 "visibility" => "public"
2478 CommonAPI.post(other_user, %{
2479 "status" => "hi @#{user.nickname}",
2480 "visibility" => "public"
2483 notification1 = Repo.get_by(Notification, activity_id: activity1.id)
2484 notification2 = Repo.get_by(Notification, activity_id: activity2.id)
2488 |> assign(:user, user)
2489 |> get("/api/v1/notifications", %{media_only: true})
2491 assert [link_header] = get_resp_header(conn, "link")
2492 assert link_header =~ ~r/media_only=true/
2493 assert link_header =~ ~r/min_id=#{notification2.id}/
2494 assert link_header =~ ~r/max_id=#{notification1.id}/
2498 test "accounts fetches correct account for nicknames beginning with numbers", %{conn: conn} do
2499 # Need to set an old-style integer ID to reproduce the problem
2500 # (these are no longer assigned to new accounts but were preserved
2501 # for existing accounts during the migration to flakeIDs)
2502 user_one = insert(:user, %{id: 1212})
2503 user_two = insert(:user, %{nickname: "#{user_one.id}garbage"})
2507 |> get("/api/v1/accounts/#{user_one.id}")
2511 |> get("/api/v1/accounts/#{user_two.nickname}")
2515 |> get("/api/v1/accounts/#{user_two.id}")
2517 acc_one = json_response(resp_one, 200)
2518 acc_two = json_response(resp_two, 200)
2519 acc_three = json_response(resp_three, 200)
2520 refute acc_one == acc_two
2521 assert acc_two == acc_three
2524 describe "custom emoji" do
2525 test "with tags", %{conn: conn} do
2528 |> get("/api/v1/custom_emojis")
2529 |> json_response(200)
2531 assert Map.has_key?(emoji, "shortcode")
2532 assert Map.has_key?(emoji, "static_url")
2533 assert Map.has_key?(emoji, "tags")
2534 assert is_list(emoji["tags"])
2535 assert Map.has_key?(emoji, "url")
2536 assert Map.has_key?(emoji, "visible_in_picker")
2540 describe "index/2 redirections" do
2541 setup %{conn: conn} do
2545 signing_salt: "cooldude"
2550 |> Plug.Session.call(Plug.Session.init(session_opts))
2553 test_path = "/web/statuses/test"
2554 %{conn: conn, path: test_path}
2557 test "redirects not logged-in users to the login page", %{conn: conn, path: path} do
2558 conn = get(conn, path)
2560 assert conn.status == 302
2561 assert redirected_to(conn) == "/web/login"
2564 test "does not redirect logged in users to the login page", %{conn: conn, path: path} do
2565 token = insert(:oauth_token)
2569 |> assign(:user, token.user)
2570 |> put_session(:oauth_token, token.token)
2573 assert conn.status == 200
2576 test "saves referer path to session", %{conn: conn, path: path} do
2577 conn = get(conn, path)
2578 return_to = Plug.Conn.get_session(conn, :return_to)
2580 assert return_to == path
2583 test "redirects to the saved path after log in", %{conn: conn, path: path} do
2584 app = insert(:oauth_app, client_name: "Mastodon-Local", redirect_uris: ".")
2585 auth = insert(:oauth_authorization, app: app)
2589 |> put_session(:return_to, path)
2590 |> get("/web/login", %{code: auth.token})
2592 assert conn.status == 302
2593 assert redirected_to(conn) == path
2596 test "redirects to the getting-started page when referer is not present", %{conn: conn} do
2597 app = insert(:oauth_app, client_name: "Mastodon-Local", redirect_uris: ".")
2598 auth = insert(:oauth_authorization, app: app)
2600 conn = get(conn, "/web/login", %{code: auth.token})
2602 assert conn.status == 302
2603 assert redirected_to(conn) == "/web/getting-started"
2607 describe "scheduled activities" do
2608 test "creates a scheduled activity", %{conn: conn} do
2609 user = insert(:user)
2610 scheduled_at = NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond)
2614 |> assign(:user, user)
2615 |> post("/api/v1/statuses", %{
2616 "status" => "scheduled",
2617 "scheduled_at" => scheduled_at
2620 assert %{"scheduled_at" => expected_scheduled_at} = json_response(conn, 200)
2621 assert expected_scheduled_at == Pleroma.Web.CommonAPI.Utils.to_masto_date(scheduled_at)
2622 assert [] == Repo.all(Activity)
2625 test "creates a scheduled activity with a media attachment", %{conn: conn} do
2626 user = insert(:user)
2627 scheduled_at = NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond)
2629 file = %Plug.Upload{
2630 content_type: "image/jpg",
2631 path: Path.absname("test/fixtures/image.jpg"),
2632 filename: "an_image.jpg"
2635 {:ok, upload} = ActivityPub.upload(file, actor: user.ap_id)
2639 |> assign(:user, user)
2640 |> post("/api/v1/statuses", %{
2641 "media_ids" => [to_string(upload.id)],
2642 "status" => "scheduled",
2643 "scheduled_at" => scheduled_at
2646 assert %{"media_attachments" => [media_attachment]} = json_response(conn, 200)
2647 assert %{"type" => "image"} = media_attachment
2650 test "skips the scheduling and creates the activity if scheduled_at is earlier than 5 minutes from now",
2652 user = insert(:user)
2655 NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(5) - 1, :millisecond)
2659 |> assign(:user, user)
2660 |> post("/api/v1/statuses", %{
2661 "status" => "not scheduled",
2662 "scheduled_at" => scheduled_at
2665 assert %{"content" => "not scheduled"} = json_response(conn, 200)
2666 assert [] == Repo.all(ScheduledActivity)
2669 test "returns error when daily user limit is exceeded", %{conn: conn} do
2670 user = insert(:user)
2673 NaiveDateTime.utc_now()
2674 |> NaiveDateTime.add(:timer.minutes(6), :millisecond)
2675 |> NaiveDateTime.to_iso8601()
2677 attrs = %{params: %{}, scheduled_at: today}
2678 {:ok, _} = ScheduledActivity.create(user, attrs)
2679 {:ok, _} = ScheduledActivity.create(user, attrs)
2683 |> assign(:user, user)
2684 |> post("/api/v1/statuses", %{"status" => "scheduled", "scheduled_at" => today})
2686 assert %{"error" => "daily limit exceeded"} == json_response(conn, 422)
2689 test "returns error when total user limit is exceeded", %{conn: conn} do
2690 user = insert(:user)
2693 NaiveDateTime.utc_now()
2694 |> NaiveDateTime.add(:timer.minutes(6), :millisecond)
2695 |> NaiveDateTime.to_iso8601()
2698 NaiveDateTime.utc_now()
2699 |> NaiveDateTime.add(:timer.hours(36), :millisecond)
2700 |> NaiveDateTime.to_iso8601()
2702 attrs = %{params: %{}, scheduled_at: today}
2703 {:ok, _} = ScheduledActivity.create(user, attrs)
2704 {:ok, _} = ScheduledActivity.create(user, attrs)
2705 {:ok, _} = ScheduledActivity.create(user, %{params: %{}, scheduled_at: tomorrow})
2709 |> assign(:user, user)
2710 |> post("/api/v1/statuses", %{"status" => "scheduled", "scheduled_at" => tomorrow})
2712 assert %{"error" => "total limit exceeded"} == json_response(conn, 422)
2715 test "shows scheduled activities", %{conn: conn} do
2716 user = insert(:user)
2717 scheduled_activity_id1 = insert(:scheduled_activity, user: user).id |> to_string()
2718 scheduled_activity_id2 = insert(:scheduled_activity, user: user).id |> to_string()
2719 scheduled_activity_id3 = insert(:scheduled_activity, user: user).id |> to_string()
2720 scheduled_activity_id4 = insert(:scheduled_activity, user: user).id |> to_string()
2724 |> assign(:user, user)
2729 |> get("/api/v1/scheduled_statuses?limit=2&min_id=#{scheduled_activity_id1}")
2731 result = json_response(conn_res, 200)
2732 assert [%{"id" => ^scheduled_activity_id3}, %{"id" => ^scheduled_activity_id2}] = result
2737 |> get("/api/v1/scheduled_statuses?limit=2&since_id=#{scheduled_activity_id1}")
2739 result = json_response(conn_res, 200)
2740 assert [%{"id" => ^scheduled_activity_id4}, %{"id" => ^scheduled_activity_id3}] = result
2745 |> get("/api/v1/scheduled_statuses?limit=2&max_id=#{scheduled_activity_id4}")
2747 result = json_response(conn_res, 200)
2748 assert [%{"id" => ^scheduled_activity_id3}, %{"id" => ^scheduled_activity_id2}] = result
2751 test "shows a scheduled activity", %{conn: conn} do
2752 user = insert(:user)
2753 scheduled_activity = insert(:scheduled_activity, user: user)
2757 |> assign(:user, user)
2758 |> get("/api/v1/scheduled_statuses/#{scheduled_activity.id}")
2760 assert %{"id" => scheduled_activity_id} = json_response(res_conn, 200)
2761 assert scheduled_activity_id == scheduled_activity.id |> to_string()
2765 |> assign(:user, user)
2766 |> get("/api/v1/scheduled_statuses/404")
2768 assert %{"error" => "Record not found"} = json_response(res_conn, 404)
2771 test "updates a scheduled activity", %{conn: conn} do
2772 user = insert(:user)
2773 scheduled_activity = insert(:scheduled_activity, user: user)
2776 NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond)
2780 |> assign(:user, user)
2781 |> put("/api/v1/scheduled_statuses/#{scheduled_activity.id}", %{
2782 scheduled_at: new_scheduled_at
2785 assert %{"scheduled_at" => expected_scheduled_at} = json_response(res_conn, 200)
2786 assert expected_scheduled_at == Pleroma.Web.CommonAPI.Utils.to_masto_date(new_scheduled_at)
2790 |> assign(:user, user)
2791 |> put("/api/v1/scheduled_statuses/404", %{scheduled_at: new_scheduled_at})
2793 assert %{"error" => "Record not found"} = json_response(res_conn, 404)
2796 test "deletes a scheduled activity", %{conn: conn} do
2797 user = insert(:user)
2798 scheduled_activity = insert(:scheduled_activity, user: user)
2802 |> assign(:user, user)
2803 |> delete("/api/v1/scheduled_statuses/#{scheduled_activity.id}")
2805 assert %{} = json_response(res_conn, 200)
2806 assert nil == Repo.get(ScheduledActivity, scheduled_activity.id)
2810 |> assign(:user, user)
2811 |> delete("/api/v1/scheduled_statuses/#{scheduled_activity.id}")
2813 assert %{"error" => "Record not found"} = json_response(res_conn, 404)
2817 test "Repeated posts that are replies incorrectly have in_reply_to_id null", %{conn: conn} do
2818 user1 = insert(:user)
2819 user2 = insert(:user)
2820 user3 = insert(:user)
2822 {:ok, replied_to} = TwitterAPI.create_status(user1, %{"status" => "cofe"})
2824 # Reply to status from another user
2827 |> assign(:user, user2)
2828 |> post("/api/v1/statuses", %{"status" => "xD", "in_reply_to_id" => replied_to.id})
2830 assert %{"content" => "xD", "id" => id} = json_response(conn1, 200)
2832 activity = Activity.get_by_id_with_object(id)
2834 assert Object.normalize(activity).data["inReplyTo"] == Object.normalize(replied_to).data["id"]
2835 assert Activity.get_in_reply_to_activity(activity).id == replied_to.id
2837 # Reblog from the third user
2840 |> assign(:user, user3)
2841 |> post("/api/v1/statuses/#{activity.id}/reblog")
2843 assert %{"reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 1}} =
2844 json_response(conn2, 200)
2846 assert to_string(activity.id) == id
2848 # Getting third user status
2851 |> assign(:user, user3)
2852 |> get("api/v1/timelines/home")
2854 [reblogged_activity] = json_response(conn3, 200)
2856 assert reblogged_activity["reblog"]["in_reply_to_id"] == replied_to.id
2858 replied_to_user = User.get_by_ap_id(replied_to.data["actor"])
2859 assert reblogged_activity["reblog"]["in_reply_to_account_id"] == replied_to_user.id