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 / unfollowing errors" do
1624 user = insert(:user)
1628 |> assign(:user, user)
1631 conn_res = post(conn, "/api/v1/accounts/#{user.id}/follow")
1632 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
1635 user = User.get_cached_by_id(user.id)
1636 conn_res = post(conn, "/api/v1/accounts/#{user.id}/unfollow")
1637 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
1639 # self follow via uri
1640 user = User.get_cached_by_id(user.id)
1641 conn_res = post(conn, "/api/v1/follows", %{"uri" => user.nickname})
1642 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
1644 # follow non existing user
1645 conn_res = post(conn, "/api/v1/accounts/doesntexist/follow")
1646 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
1648 # follow non existing user via uri
1649 conn_res = post(conn, "/api/v1/follows", %{"uri" => "doesntexist"})
1650 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
1652 # unfollow non existing user
1653 conn_res = post(conn, "/api/v1/accounts/doesntexist/unfollow")
1654 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
1657 test "muting / unmuting 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}/mute")
1666 assert %{"id" => _id, "muting" => true} = json_response(conn, 200)
1668 user = User.get_by_id(user.id)
1672 |> assign(:user, user)
1673 |> post("/api/v1/accounts/#{other_user.id}/unmute")
1675 assert %{"id" => _id, "muting" => false} = json_response(conn, 200)
1678 test "subscribing / unsubscribing to a user", %{conn: conn} do
1679 user = insert(:user)
1680 subscription_target = insert(:user)
1684 |> assign(:user, user)
1685 |> post("/api/v1/pleroma/accounts/#{subscription_target.id}/subscribe")
1687 assert %{"id" => _id, "subscribing" => true} = json_response(conn, 200)
1691 |> assign(:user, user)
1692 |> post("/api/v1/pleroma/accounts/#{subscription_target.id}/unsubscribe")
1694 assert %{"id" => _id, "subscribing" => false} = json_response(conn, 200)
1697 test "getting a list of mutes", %{conn: conn} do
1698 user = insert(:user)
1699 other_user = insert(:user)
1701 {:ok, user} = User.mute(user, other_user)
1705 |> assign(:user, user)
1706 |> get("/api/v1/mutes")
1708 other_user_id = to_string(other_user.id)
1709 assert [%{"id" => ^other_user_id}] = json_response(conn, 200)
1712 test "blocking / unblocking a user", %{conn: conn} do
1713 user = insert(:user)
1714 other_user = insert(:user)
1718 |> assign(:user, user)
1719 |> post("/api/v1/accounts/#{other_user.id}/block")
1721 assert %{"id" => _id, "blocking" => true} = json_response(conn, 200)
1723 user = User.get_by_id(user.id)
1727 |> assign(:user, user)
1728 |> post("/api/v1/accounts/#{other_user.id}/unblock")
1730 assert %{"id" => _id, "blocking" => false} = json_response(conn, 200)
1733 test "getting a list of blocks", %{conn: conn} do
1734 user = insert(:user)
1735 other_user = insert(:user)
1737 {:ok, user} = User.block(user, other_user)
1741 |> assign(:user, user)
1742 |> get("/api/v1/blocks")
1744 other_user_id = to_string(other_user.id)
1745 assert [%{"id" => ^other_user_id}] = json_response(conn, 200)
1748 test "blocking / unblocking a domain", %{conn: conn} do
1749 user = insert(:user)
1750 other_user = insert(:user, %{ap_id: "https://dogwhistle.zone/@pundit"})
1754 |> assign(:user, user)
1755 |> post("/api/v1/domain_blocks", %{"domain" => "dogwhistle.zone"})
1757 assert %{} = json_response(conn, 200)
1758 user = User.get_cached_by_ap_id(user.ap_id)
1759 assert User.blocks?(user, other_user)
1763 |> assign(:user, user)
1764 |> delete("/api/v1/domain_blocks", %{"domain" => "dogwhistle.zone"})
1766 assert %{} = json_response(conn, 200)
1767 user = User.get_cached_by_ap_id(user.ap_id)
1768 refute User.blocks?(user, other_user)
1771 test "getting a list of domain blocks", %{conn: conn} do
1772 user = insert(:user)
1774 {:ok, user} = User.block_domain(user, "bad.site")
1775 {:ok, user} = User.block_domain(user, "even.worse.site")
1779 |> assign(:user, user)
1780 |> get("/api/v1/domain_blocks")
1782 domain_blocks = json_response(conn, 200)
1784 assert "bad.site" in domain_blocks
1785 assert "even.worse.site" in domain_blocks
1788 test "unimplemented follow_requests, blocks, domain blocks" do
1789 user = insert(:user)
1791 ["blocks", "domain_blocks", "follow_requests"]
1792 |> Enum.each(fn endpoint ->
1795 |> assign(:user, user)
1796 |> get("/api/v1/#{endpoint}")
1798 assert [] = json_response(conn, 200)
1802 test "account search", %{conn: conn} do
1803 user = insert(:user)
1804 user_two = insert(:user, %{nickname: "shp@shitposter.club"})
1805 user_three = insert(:user, %{nickname: "shp@heldscal.la", name: "I love 2hu"})
1809 |> assign(:user, user)
1810 |> get("/api/v1/accounts/search", %{"q" => "shp"})
1811 |> json_response(200)
1813 result_ids = for result <- results, do: result["acct"]
1815 assert user_two.nickname in result_ids
1816 assert user_three.nickname in result_ids
1820 |> assign(:user, user)
1821 |> get("/api/v1/accounts/search", %{"q" => "2hu"})
1822 |> json_response(200)
1824 result_ids = for result <- results, do: result["acct"]
1826 assert user_three.nickname in result_ids
1829 test "search", %{conn: conn} do
1830 user = insert(:user)
1831 user_two = insert(:user, %{nickname: "shp@shitposter.club"})
1832 user_three = insert(:user, %{nickname: "shp@heldscal.la", name: "I love 2hu"})
1834 {:ok, activity} = CommonAPI.post(user, %{"status" => "This is about 2hu"})
1837 CommonAPI.post(user, %{
1838 "status" => "This is about 2hu, but private",
1839 "visibility" => "private"
1842 {:ok, _} = CommonAPI.post(user_two, %{"status" => "This isn't"})
1846 |> get("/api/v1/search", %{"q" => "2hu"})
1848 assert results = json_response(conn, 200)
1850 [account | _] = results["accounts"]
1851 assert account["id"] == to_string(user_three.id)
1853 assert results["hashtags"] == []
1855 [status] = results["statuses"]
1856 assert status["id"] == to_string(activity.id)
1859 test "search fetches remote statuses", %{conn: conn} do
1863 |> get("/api/v1/search", %{"q" => "https://shitposter.club/notice/2827873"})
1865 assert results = json_response(conn, 200)
1867 [status] = results["statuses"]
1868 assert status["uri"] == "tag:shitposter.club,2017-05-05:noticeId=2827873:objectType=comment"
1872 test "search doesn't show statuses that it shouldn't", %{conn: conn} do
1874 CommonAPI.post(insert(:user), %{
1875 "status" => "This is about 2hu, but private",
1876 "visibility" => "private"
1882 |> get("/api/v1/search", %{"q" => Object.normalize(activity).data["id"]})
1884 assert results = json_response(conn, 200)
1886 [] = results["statuses"]
1890 test "search fetches remote accounts", %{conn: conn} do
1893 |> get("/api/v1/search", %{"q" => "shp@social.heldscal.la", "resolve" => "true"})
1895 assert results = json_response(conn, 200)
1896 [account] = results["accounts"]
1897 assert account["acct"] == "shp@social.heldscal.la"
1900 test "returns the favorites of a user", %{conn: conn} do
1901 user = insert(:user)
1902 other_user = insert(:user)
1904 {:ok, _} = CommonAPI.post(other_user, %{"status" => "bla"})
1905 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "traps are happy"})
1907 {:ok, _, _} = CommonAPI.favorite(activity.id, user)
1911 |> assign(:user, user)
1912 |> get("/api/v1/favourites")
1914 assert [status] = json_response(first_conn, 200)
1915 assert status["id"] == to_string(activity.id)
1917 assert [{"link", _link_header}] =
1918 Enum.filter(first_conn.resp_headers, fn element -> match?({"link", _}, element) end)
1920 # Honours query params
1921 {:ok, second_activity} =
1922 CommonAPI.post(other_user, %{
1924 "Trees Are Never Sad Look At Them Every Once In Awhile They're Quite Beautiful."
1927 {:ok, _, _} = CommonAPI.favorite(second_activity.id, user)
1929 last_like = status["id"]
1933 |> assign(:user, user)
1934 |> get("/api/v1/favourites?since_id=#{last_like}")
1936 assert [second_status] = json_response(second_conn, 200)
1937 assert second_status["id"] == to_string(second_activity.id)
1941 |> assign(:user, user)
1942 |> get("/api/v1/favourites?limit=0")
1944 assert [] = json_response(third_conn, 200)
1947 describe "updating credentials" do
1948 test "updates the user's bio", %{conn: conn} do
1949 user = insert(:user)
1950 user2 = insert(:user)
1954 |> assign(:user, user)
1955 |> patch("/api/v1/accounts/update_credentials", %{
1956 "note" => "I drink #cofe with @#{user2.nickname}"
1959 assert user = json_response(conn, 200)
1961 assert user["note"] ==
1962 ~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=") <>
1964 ~s(" class="u-url mention" href=") <>
1965 user2.ap_id <> ~s(">@<span>) <> user2.nickname <> ~s(</span></a></span>)
1968 test "updates the user's locking status", %{conn: conn} do
1969 user = insert(:user)
1973 |> assign(:user, user)
1974 |> patch("/api/v1/accounts/update_credentials", %{locked: "true"})
1976 assert user = json_response(conn, 200)
1977 assert user["locked"] == true
1980 test "updates the user's name", %{conn: conn} do
1981 user = insert(:user)
1985 |> assign(:user, user)
1986 |> patch("/api/v1/accounts/update_credentials", %{"display_name" => "markorepairs"})
1988 assert user = json_response(conn, 200)
1989 assert user["display_name"] == "markorepairs"
1992 test "updates the user's avatar", %{conn: conn} do
1993 user = insert(:user)
1995 new_avatar = %Plug.Upload{
1996 content_type: "image/jpg",
1997 path: Path.absname("test/fixtures/image.jpg"),
1998 filename: "an_image.jpg"
2003 |> assign(:user, user)
2004 |> patch("/api/v1/accounts/update_credentials", %{"avatar" => new_avatar})
2006 assert user_response = json_response(conn, 200)
2007 assert user_response["avatar"] != User.avatar_url(user)
2010 test "updates the user's banner", %{conn: conn} do
2011 user = insert(:user)
2013 new_header = %Plug.Upload{
2014 content_type: "image/jpg",
2015 path: Path.absname("test/fixtures/image.jpg"),
2016 filename: "an_image.jpg"
2021 |> assign(:user, user)
2022 |> patch("/api/v1/accounts/update_credentials", %{"header" => new_header})
2024 assert user_response = json_response(conn, 200)
2025 assert user_response["header"] != User.banner_url(user)
2028 test "requires 'write' permission", %{conn: conn} do
2029 token1 = insert(:oauth_token, scopes: ["read"])
2030 token2 = insert(:oauth_token, scopes: ["write", "follow"])
2032 for token <- [token1, token2] do
2035 |> put_req_header("authorization", "Bearer #{token.token}")
2036 |> patch("/api/v1/accounts/update_credentials", %{})
2038 if token == token1 do
2039 assert %{"error" => "Insufficient permissions: write."} == json_response(conn, 403)
2041 assert json_response(conn, 200)
2047 test "get instance information", %{conn: conn} do
2048 conn = get(conn, "/api/v1/instance")
2049 assert result = json_response(conn, 200)
2051 email = Pleroma.Config.get([:instance, :email])
2052 # Note: not checking for "max_toot_chars" since it's optional
2058 "email" => from_config_email,
2060 "streaming_api" => _
2065 "registrations" => _
2068 assert email == from_config_email
2071 test "get instance stats", %{conn: conn} do
2072 user = insert(:user, %{local: true})
2074 user2 = insert(:user, %{local: true})
2075 {:ok, _user2} = User.deactivate(user2, !user2.info.deactivated)
2077 insert(:user, %{local: false, nickname: "u@peer1.com"})
2078 insert(:user, %{local: false, nickname: "u@peer2.com"})
2080 {:ok, _} = TwitterAPI.create_status(user, %{"status" => "cofe"})
2082 # Stats should count users with missing or nil `info.deactivated` value
2083 user = User.get_by_id(user.id)
2084 info_change = Changeset.change(user.info, %{deactivated: nil})
2088 |> Changeset.change()
2089 |> Changeset.put_embed(:info, info_change)
2090 |> User.update_and_set_cache()
2092 Pleroma.Stats.update_stats()
2094 conn = get(conn, "/api/v1/instance")
2096 assert result = json_response(conn, 200)
2098 stats = result["stats"]
2101 assert stats["user_count"] == 1
2102 assert stats["status_count"] == 1
2103 assert stats["domain_count"] == 2
2106 test "get peers", %{conn: conn} do
2107 insert(:user, %{local: false, nickname: "u@peer1.com"})
2108 insert(:user, %{local: false, nickname: "u@peer2.com"})
2110 Pleroma.Stats.update_stats()
2112 conn = get(conn, "/api/v1/instance/peers")
2114 assert result = json_response(conn, 200)
2116 assert ["peer1.com", "peer2.com"] == Enum.sort(result)
2119 test "put settings", %{conn: conn} do
2120 user = insert(:user)
2124 |> assign(:user, user)
2125 |> put("/api/web/settings", %{"data" => %{"programming" => "socks"}})
2127 assert _result = json_response(conn, 200)
2129 user = User.get_cached_by_ap_id(user.ap_id)
2130 assert user.info.settings == %{"programming" => "socks"}
2133 describe "pinned statuses" do
2135 Pleroma.Config.put([:instance, :max_pinned_statuses], 1)
2137 user = insert(:user)
2138 {:ok, activity} = CommonAPI.post(user, %{"status" => "HI!!!"})
2140 [user: user, activity: activity]
2143 test "returns pinned statuses", %{conn: conn, user: user, activity: activity} do
2144 {:ok, _} = CommonAPI.pin(activity.id, user)
2148 |> assign(:user, user)
2149 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
2150 |> json_response(200)
2152 id_str = to_string(activity.id)
2154 assert [%{"id" => ^id_str, "pinned" => true}] = result
2157 test "pin status", %{conn: conn, user: user, activity: activity} do
2158 id_str = to_string(activity.id)
2160 assert %{"id" => ^id_str, "pinned" => true} =
2162 |> assign(:user, user)
2163 |> post("/api/v1/statuses/#{activity.id}/pin")
2164 |> json_response(200)
2166 assert [%{"id" => ^id_str, "pinned" => true}] =
2168 |> assign(:user, user)
2169 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
2170 |> json_response(200)
2173 test "unpin status", %{conn: conn, user: user, activity: activity} do
2174 {:ok, _} = CommonAPI.pin(activity.id, user)
2176 id_str = to_string(activity.id)
2177 user = refresh_record(user)
2179 assert %{"id" => ^id_str, "pinned" => false} =
2181 |> assign(:user, user)
2182 |> post("/api/v1/statuses/#{activity.id}/unpin")
2183 |> json_response(200)
2187 |> assign(:user, user)
2188 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
2189 |> json_response(200)
2192 test "max pinned statuses", %{conn: conn, user: user, activity: activity_one} do
2193 {:ok, activity_two} = CommonAPI.post(user, %{"status" => "HI!!!"})
2195 id_str_one = to_string(activity_one.id)
2197 assert %{"id" => ^id_str_one, "pinned" => true} =
2199 |> assign(:user, user)
2200 |> post("/api/v1/statuses/#{id_str_one}/pin")
2201 |> json_response(200)
2203 user = refresh_record(user)
2205 assert %{"error" => "You have already pinned the maximum number of statuses"} =
2207 |> assign(:user, user)
2208 |> post("/api/v1/statuses/#{activity_two.id}/pin")
2209 |> json_response(400)
2212 test "Status rich-media Card", %{conn: conn, user: user} do
2213 Pleroma.Config.put([:rich_media, :enabled], true)
2214 {:ok, activity} = CommonAPI.post(user, %{"status" => "http://example.com/ogp"})
2218 |> get("/api/v1/statuses/#{activity.id}/card")
2219 |> json_response(200)
2221 assert response == %{
2222 "image" => "http://ia.media-imdb.com/images/rock.jpg",
2223 "provider_name" => "www.imdb.com",
2224 "provider_url" => "http://www.imdb.com",
2225 "title" => "The Rock",
2227 "url" => "http://www.imdb.com/title/tt0117500/",
2228 "description" => nil,
2231 "image" => "http://ia.media-imdb.com/images/rock.jpg",
2232 "title" => "The Rock",
2233 "type" => "video.movie",
2234 "url" => "http://www.imdb.com/title/tt0117500/"
2239 # works with private posts
2241 CommonAPI.post(user, %{"status" => "http://example.com/ogp", "visibility" => "direct"})
2245 |> assign(:user, user)
2246 |> get("/api/v1/statuses/#{activity.id}/card")
2247 |> json_response(200)
2249 assert response_two == response
2251 Pleroma.Config.put([:rich_media, :enabled], false)
2256 user = insert(:user)
2257 for_user = insert(:user)
2260 CommonAPI.post(user, %{
2261 "status" => "heweoo?"
2265 CommonAPI.post(user, %{
2266 "status" => "heweoo!"
2271 |> assign(:user, for_user)
2272 |> post("/api/v1/statuses/#{activity1.id}/bookmark")
2274 assert json_response(response1, 200)["bookmarked"] == true
2278 |> assign(:user, for_user)
2279 |> post("/api/v1/statuses/#{activity2.id}/bookmark")
2281 assert json_response(response2, 200)["bookmarked"] == true
2285 |> assign(:user, for_user)
2286 |> get("/api/v1/bookmarks")
2288 assert [json_response(response2, 200), json_response(response1, 200)] ==
2289 json_response(bookmarks, 200)
2293 |> assign(:user, for_user)
2294 |> post("/api/v1/statuses/#{activity1.id}/unbookmark")
2296 assert json_response(response1, 200)["bookmarked"] == false
2300 |> assign(:user, for_user)
2301 |> get("/api/v1/bookmarks")
2303 assert [json_response(response2, 200)] == json_response(bookmarks, 200)
2306 describe "conversation muting" do
2308 user = insert(:user)
2309 {:ok, activity} = CommonAPI.post(user, %{"status" => "HIE"})
2311 [user: user, activity: activity]
2314 test "mute conversation", %{conn: conn, user: user, activity: activity} do
2315 id_str = to_string(activity.id)
2317 assert %{"id" => ^id_str, "muted" => true} =
2319 |> assign(:user, user)
2320 |> post("/api/v1/statuses/#{activity.id}/mute")
2321 |> json_response(200)
2324 test "unmute conversation", %{conn: conn, user: user, activity: activity} do
2325 {:ok, _} = CommonAPI.add_mute(user, activity)
2327 id_str = to_string(activity.id)
2328 user = refresh_record(user)
2330 assert %{"id" => ^id_str, "muted" => false} =
2332 |> assign(:user, user)
2333 |> post("/api/v1/statuses/#{activity.id}/unmute")
2334 |> json_response(200)
2338 test "flavours switching (Pleroma Extension)", %{conn: conn} do
2339 user = insert(:user)
2343 |> assign(:user, user)
2344 |> get("/api/v1/pleroma/flavour")
2346 assert "glitch" == json_response(get_old_flavour, 200)
2350 |> assign(:user, user)
2351 |> post("/api/v1/pleroma/flavour/vanilla")
2353 assert "vanilla" == json_response(set_flavour, 200)
2357 |> assign(:user, user)
2358 |> post("/api/v1/pleroma/flavour/vanilla")
2360 assert json_response(set_flavour, 200) == json_response(get_new_flavour, 200)
2363 describe "reports" do
2365 reporter = insert(:user)
2366 target_user = insert(:user)
2368 {:ok, activity} = CommonAPI.post(target_user, %{"status" => "foobar"})
2370 [reporter: reporter, target_user: target_user, activity: activity]
2373 test "submit a basic report", %{conn: conn, reporter: reporter, target_user: target_user} do
2374 assert %{"action_taken" => false, "id" => _} =
2376 |> assign(:user, reporter)
2377 |> post("/api/v1/reports", %{"account_id" => target_user.id})
2378 |> json_response(200)
2381 test "submit a report with statuses and comment", %{
2384 target_user: target_user,
2387 assert %{"action_taken" => false, "id" => _} =
2389 |> assign(:user, reporter)
2390 |> post("/api/v1/reports", %{
2391 "account_id" => target_user.id,
2392 "status_ids" => [activity.id],
2393 "comment" => "bad status!"
2395 |> json_response(200)
2398 test "account_id is required", %{
2403 assert %{"error" => "Valid `account_id` required"} =
2405 |> assign(:user, reporter)
2406 |> post("/api/v1/reports", %{"status_ids" => [activity.id]})
2407 |> json_response(400)
2410 test "comment must be up to the size specified in the config", %{
2413 target_user: target_user
2415 max_size = Pleroma.Config.get([:instance, :max_report_comment_size], 1000)
2416 comment = String.pad_trailing("a", max_size + 1, "a")
2418 error = %{"error" => "Comment must be up to #{max_size} characters"}
2422 |> assign(:user, reporter)
2423 |> post("/api/v1/reports", %{"account_id" => target_user.id, "comment" => comment})
2424 |> json_response(400)
2428 describe "link headers" do
2429 test "preserves parameters in link headers", %{conn: conn} do
2430 user = insert(:user)
2431 other_user = insert(:user)
2434 CommonAPI.post(other_user, %{
2435 "status" => "hi @#{user.nickname}",
2436 "visibility" => "public"
2440 CommonAPI.post(other_user, %{
2441 "status" => "hi @#{user.nickname}",
2442 "visibility" => "public"
2445 notification1 = Repo.get_by(Notification, activity_id: activity1.id)
2446 notification2 = Repo.get_by(Notification, activity_id: activity2.id)
2450 |> assign(:user, user)
2451 |> get("/api/v1/notifications", %{media_only: true})
2453 assert [link_header] = get_resp_header(conn, "link")
2454 assert link_header =~ ~r/media_only=true/
2455 assert link_header =~ ~r/min_id=#{notification2.id}/
2456 assert link_header =~ ~r/max_id=#{notification1.id}/
2460 test "accounts fetches correct account for nicknames beginning with numbers", %{conn: conn} do
2461 # Need to set an old-style integer ID to reproduce the problem
2462 # (these are no longer assigned to new accounts but were preserved
2463 # for existing accounts during the migration to flakeIDs)
2464 user_one = insert(:user, %{id: 1212})
2465 user_two = insert(:user, %{nickname: "#{user_one.id}garbage"})
2469 |> get("/api/v1/accounts/#{user_one.id}")
2473 |> get("/api/v1/accounts/#{user_two.nickname}")
2477 |> get("/api/v1/accounts/#{user_two.id}")
2479 acc_one = json_response(resp_one, 200)
2480 acc_two = json_response(resp_two, 200)
2481 acc_three = json_response(resp_three, 200)
2482 refute acc_one == acc_two
2483 assert acc_two == acc_three
2486 describe "custom emoji" do
2487 test "with tags", %{conn: conn} do
2490 |> get("/api/v1/custom_emojis")
2491 |> json_response(200)
2493 assert Map.has_key?(emoji, "shortcode")
2494 assert Map.has_key?(emoji, "static_url")
2495 assert Map.has_key?(emoji, "tags")
2496 assert is_list(emoji["tags"])
2497 assert Map.has_key?(emoji, "url")
2498 assert Map.has_key?(emoji, "visible_in_picker")
2502 describe "index/2 redirections" do
2503 setup %{conn: conn} do
2507 signing_salt: "cooldude"
2512 |> Plug.Session.call(Plug.Session.init(session_opts))
2515 test_path = "/web/statuses/test"
2516 %{conn: conn, path: test_path}
2519 test "redirects not logged-in users to the login page", %{conn: conn, path: path} do
2520 conn = get(conn, path)
2522 assert conn.status == 302
2523 assert redirected_to(conn) == "/web/login"
2526 test "does not redirect logged in users to the login page", %{conn: conn, path: path} do
2527 token = insert(:oauth_token)
2531 |> assign(:user, token.user)
2532 |> put_session(:oauth_token, token.token)
2535 assert conn.status == 200
2538 test "saves referer path to session", %{conn: conn, path: path} do
2539 conn = get(conn, path)
2540 return_to = Plug.Conn.get_session(conn, :return_to)
2542 assert return_to == path
2545 test "redirects to the saved path after log in", %{conn: conn, path: path} do
2546 app = insert(:oauth_app, client_name: "Mastodon-Local", redirect_uris: ".")
2547 auth = insert(:oauth_authorization, app: app)
2551 |> put_session(:return_to, path)
2552 |> get("/web/login", %{code: auth.token})
2554 assert conn.status == 302
2555 assert redirected_to(conn) == path
2558 test "redirects to the getting-started page when referer is not present", %{conn: conn} do
2559 app = insert(:oauth_app, client_name: "Mastodon-Local", redirect_uris: ".")
2560 auth = insert(:oauth_authorization, app: app)
2562 conn = get(conn, "/web/login", %{code: auth.token})
2564 assert conn.status == 302
2565 assert redirected_to(conn) == "/web/getting-started"
2569 describe "scheduled activities" do
2570 test "creates a scheduled activity", %{conn: conn} do
2571 user = insert(:user)
2572 scheduled_at = NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond)
2576 |> assign(:user, user)
2577 |> post("/api/v1/statuses", %{
2578 "status" => "scheduled",
2579 "scheduled_at" => scheduled_at
2582 assert %{"scheduled_at" => expected_scheduled_at} = json_response(conn, 200)
2583 assert expected_scheduled_at == Pleroma.Web.CommonAPI.Utils.to_masto_date(scheduled_at)
2584 assert [] == Repo.all(Activity)
2587 test "creates a scheduled activity with a media attachment", %{conn: conn} do
2588 user = insert(:user)
2589 scheduled_at = NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond)
2591 file = %Plug.Upload{
2592 content_type: "image/jpg",
2593 path: Path.absname("test/fixtures/image.jpg"),
2594 filename: "an_image.jpg"
2597 {:ok, upload} = ActivityPub.upload(file, actor: user.ap_id)
2601 |> assign(:user, user)
2602 |> post("/api/v1/statuses", %{
2603 "media_ids" => [to_string(upload.id)],
2604 "status" => "scheduled",
2605 "scheduled_at" => scheduled_at
2608 assert %{"media_attachments" => [media_attachment]} = json_response(conn, 200)
2609 assert %{"type" => "image"} = media_attachment
2612 test "skips the scheduling and creates the activity if scheduled_at is earlier than 5 minutes from now",
2614 user = insert(:user)
2617 NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(5) - 1, :millisecond)
2621 |> assign(:user, user)
2622 |> post("/api/v1/statuses", %{
2623 "status" => "not scheduled",
2624 "scheduled_at" => scheduled_at
2627 assert %{"content" => "not scheduled"} = json_response(conn, 200)
2628 assert [] == Repo.all(ScheduledActivity)
2631 test "returns error when daily user limit is exceeded", %{conn: conn} do
2632 user = insert(:user)
2635 NaiveDateTime.utc_now()
2636 |> NaiveDateTime.add(:timer.minutes(6), :millisecond)
2637 |> NaiveDateTime.to_iso8601()
2639 attrs = %{params: %{}, scheduled_at: today}
2640 {:ok, _} = ScheduledActivity.create(user, attrs)
2641 {:ok, _} = ScheduledActivity.create(user, attrs)
2645 |> assign(:user, user)
2646 |> post("/api/v1/statuses", %{"status" => "scheduled", "scheduled_at" => today})
2648 assert %{"error" => "daily limit exceeded"} == json_response(conn, 422)
2651 test "returns error when total user limit is exceeded", %{conn: conn} do
2652 user = insert(:user)
2655 NaiveDateTime.utc_now()
2656 |> NaiveDateTime.add(:timer.minutes(6), :millisecond)
2657 |> NaiveDateTime.to_iso8601()
2660 NaiveDateTime.utc_now()
2661 |> NaiveDateTime.add(:timer.hours(36), :millisecond)
2662 |> NaiveDateTime.to_iso8601()
2664 attrs = %{params: %{}, scheduled_at: today}
2665 {:ok, _} = ScheduledActivity.create(user, attrs)
2666 {:ok, _} = ScheduledActivity.create(user, attrs)
2667 {:ok, _} = ScheduledActivity.create(user, %{params: %{}, scheduled_at: tomorrow})
2671 |> assign(:user, user)
2672 |> post("/api/v1/statuses", %{"status" => "scheduled", "scheduled_at" => tomorrow})
2674 assert %{"error" => "total limit exceeded"} == json_response(conn, 422)
2677 test "shows scheduled activities", %{conn: conn} do
2678 user = insert(:user)
2679 scheduled_activity_id1 = insert(:scheduled_activity, user: user).id |> to_string()
2680 scheduled_activity_id2 = insert(:scheduled_activity, user: user).id |> to_string()
2681 scheduled_activity_id3 = insert(:scheduled_activity, user: user).id |> to_string()
2682 scheduled_activity_id4 = insert(:scheduled_activity, user: user).id |> to_string()
2686 |> assign(:user, user)
2691 |> get("/api/v1/scheduled_statuses?limit=2&min_id=#{scheduled_activity_id1}")
2693 result = json_response(conn_res, 200)
2694 assert [%{"id" => ^scheduled_activity_id3}, %{"id" => ^scheduled_activity_id2}] = result
2699 |> get("/api/v1/scheduled_statuses?limit=2&since_id=#{scheduled_activity_id1}")
2701 result = json_response(conn_res, 200)
2702 assert [%{"id" => ^scheduled_activity_id4}, %{"id" => ^scheduled_activity_id3}] = result
2707 |> get("/api/v1/scheduled_statuses?limit=2&max_id=#{scheduled_activity_id4}")
2709 result = json_response(conn_res, 200)
2710 assert [%{"id" => ^scheduled_activity_id3}, %{"id" => ^scheduled_activity_id2}] = result
2713 test "shows a scheduled activity", %{conn: conn} do
2714 user = insert(:user)
2715 scheduled_activity = insert(:scheduled_activity, user: user)
2719 |> assign(:user, user)
2720 |> get("/api/v1/scheduled_statuses/#{scheduled_activity.id}")
2722 assert %{"id" => scheduled_activity_id} = json_response(res_conn, 200)
2723 assert scheduled_activity_id == scheduled_activity.id |> to_string()
2727 |> assign(:user, user)
2728 |> get("/api/v1/scheduled_statuses/404")
2730 assert %{"error" => "Record not found"} = json_response(res_conn, 404)
2733 test "updates a scheduled activity", %{conn: conn} do
2734 user = insert(:user)
2735 scheduled_activity = insert(:scheduled_activity, user: user)
2738 NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond)
2742 |> assign(:user, user)
2743 |> put("/api/v1/scheduled_statuses/#{scheduled_activity.id}", %{
2744 scheduled_at: new_scheduled_at
2747 assert %{"scheduled_at" => expected_scheduled_at} = json_response(res_conn, 200)
2748 assert expected_scheduled_at == Pleroma.Web.CommonAPI.Utils.to_masto_date(new_scheduled_at)
2752 |> assign(:user, user)
2753 |> put("/api/v1/scheduled_statuses/404", %{scheduled_at: new_scheduled_at})
2755 assert %{"error" => "Record not found"} = json_response(res_conn, 404)
2758 test "deletes a scheduled activity", %{conn: conn} do
2759 user = insert(:user)
2760 scheduled_activity = insert(:scheduled_activity, user: user)
2764 |> assign(:user, user)
2765 |> delete("/api/v1/scheduled_statuses/#{scheduled_activity.id}")
2767 assert %{} = json_response(res_conn, 200)
2768 assert nil == Repo.get(ScheduledActivity, scheduled_activity.id)
2772 |> assign(:user, user)
2773 |> delete("/api/v1/scheduled_statuses/#{scheduled_activity.id}")
2775 assert %{"error" => "Record not found"} = json_response(res_conn, 404)
2779 test "Repeated posts that are replies incorrectly have in_reply_to_id null", %{conn: conn} do
2780 user1 = insert(:user)
2781 user2 = insert(:user)
2782 user3 = insert(:user)
2784 {:ok, replied_to} = TwitterAPI.create_status(user1, %{"status" => "cofe"})
2786 # Reply to status from another user
2789 |> assign(:user, user2)
2790 |> post("/api/v1/statuses", %{"status" => "xD", "in_reply_to_id" => replied_to.id})
2792 assert %{"content" => "xD", "id" => id} = json_response(conn1, 200)
2794 activity = Activity.get_by_id_with_object(id)
2796 assert Object.normalize(activity).data["inReplyTo"] == Object.normalize(replied_to).data["id"]
2797 assert Activity.get_in_reply_to_activity(activity).id == replied_to.id
2799 # Reblog from the third user
2802 |> assign(:user, user3)
2803 |> post("/api/v1/statuses/#{activity.id}/reblog")
2805 assert %{"reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 1}} =
2806 json_response(conn2, 200)
2808 assert to_string(activity.id) == id
2810 # Getting third user status
2813 |> assign(:user, user3)
2814 |> get("api/v1/timelines/home")
2816 [reblogged_activity] = json_response(conn3, 200)
2818 assert reblogged_activity["reblog"]["in_reply_to_id"] == replied_to.id
2820 replied_to_user = User.get_by_ap_id(replied_to.data["actor"])
2821 assert reblogged_activity["reblog"]["in_reply_to_account_id"] == replied_to_user.id