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_cached_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 CommonAPI.favorite(activity.id, user2)
1025 {:ok, user2} = User.bookmark(user2, activity.data["object"]["id"])
1026 {:ok, reblog_activity1, _object} = CommonAPI.repeat(activity.id, user1)
1027 {:ok, _, _object} = CommonAPI.repeat(activity.id, user2)
1031 |> assign(:user, user3)
1032 |> get("/api/v1/statuses/#{reblog_activity1.id}")
1035 "reblog" => %{"id" => id, "reblogged" => false, "reblogs_count" => 2},
1036 "reblogged" => false,
1037 "favourited" => false,
1038 "bookmarked" => false
1039 } = json_response(conn_res, 200)
1043 |> assign(:user, user2)
1044 |> get("/api/v1/statuses/#{reblog_activity1.id}")
1047 "reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 2},
1048 "reblogged" => true,
1049 "favourited" => true,
1050 "bookmarked" => true
1051 } = json_response(conn_res, 200)
1053 assert to_string(activity.id) == id
1057 describe "unreblogging" do
1058 test "unreblogs and returns the unreblogged status", %{conn: conn} do
1059 activity = insert(:note_activity)
1060 user = insert(:user)
1062 {:ok, _, _} = CommonAPI.repeat(activity.id, user)
1066 |> assign(:user, user)
1067 |> post("/api/v1/statuses/#{activity.id}/unreblog")
1069 assert %{"id" => id, "reblogged" => false, "reblogs_count" => 0} = json_response(conn, 200)
1071 assert to_string(activity.id) == id
1075 describe "favoriting" do
1076 test "favs a status and returns it", %{conn: conn} do
1077 activity = insert(:note_activity)
1078 user = insert(:user)
1082 |> assign(:user, user)
1083 |> post("/api/v1/statuses/#{activity.id}/favourite")
1085 assert %{"id" => id, "favourites_count" => 1, "favourited" => true} =
1086 json_response(conn, 200)
1088 assert to_string(activity.id) == id
1091 test "returns 500 for a wrong id", %{conn: conn} do
1092 user = insert(:user)
1096 |> assign(:user, user)
1097 |> post("/api/v1/statuses/1/favourite")
1098 |> json_response(500)
1100 assert resp == "Something went wrong"
1104 describe "unfavoriting" do
1105 test "unfavorites a status and returns it", %{conn: conn} do
1106 activity = insert(:note_activity)
1107 user = insert(:user)
1109 {:ok, _, _} = CommonAPI.favorite(activity.id, user)
1113 |> assign(:user, user)
1114 |> post("/api/v1/statuses/#{activity.id}/unfavourite")
1116 assert %{"id" => id, "favourites_count" => 0, "favourited" => false} =
1117 json_response(conn, 200)
1119 assert to_string(activity.id) == id
1123 describe "user timelines" do
1124 test "gets a users statuses", %{conn: conn} do
1125 user_one = insert(:user)
1126 user_two = insert(:user)
1127 user_three = insert(:user)
1129 {:ok, user_three} = User.follow(user_three, user_one)
1131 {:ok, activity} = CommonAPI.post(user_one, %{"status" => "HI!!!"})
1133 {:ok, direct_activity} =
1134 CommonAPI.post(user_one, %{
1135 "status" => "Hi, @#{user_two.nickname}.",
1136 "visibility" => "direct"
1139 {:ok, private_activity} =
1140 CommonAPI.post(user_one, %{"status" => "private", "visibility" => "private"})
1144 |> get("/api/v1/accounts/#{user_one.id}/statuses")
1146 assert [%{"id" => id}] = json_response(resp, 200)
1147 assert id == to_string(activity.id)
1151 |> assign(:user, user_two)
1152 |> get("/api/v1/accounts/#{user_one.id}/statuses")
1154 assert [%{"id" => id_one}, %{"id" => id_two}] = json_response(resp, 200)
1155 assert id_one == to_string(direct_activity.id)
1156 assert id_two == to_string(activity.id)
1160 |> assign(:user, user_three)
1161 |> get("/api/v1/accounts/#{user_one.id}/statuses")
1163 assert [%{"id" => id_one}, %{"id" => id_two}] = json_response(resp, 200)
1164 assert id_one == to_string(private_activity.id)
1165 assert id_two == to_string(activity.id)
1168 test "unimplemented pinned statuses feature", %{conn: conn} do
1169 note = insert(:note_activity)
1170 user = User.get_cached_by_ap_id(note.data["actor"])
1174 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
1176 assert json_response(conn, 200) == []
1179 test "gets an users media", %{conn: conn} do
1180 note = insert(:note_activity)
1181 user = User.get_cached_by_ap_id(note.data["actor"])
1183 file = %Plug.Upload{
1184 content_type: "image/jpg",
1185 path: Path.absname("test/fixtures/image.jpg"),
1186 filename: "an_image.jpg"
1190 TwitterAPI.upload(file, user, "json")
1194 TwitterAPI.create_status(user, %{"status" => "cofe", "media_ids" => [media["media_id"]]})
1198 |> get("/api/v1/accounts/#{user.id}/statuses", %{"only_media" => "true"})
1200 assert [%{"id" => id}] = json_response(conn, 200)
1201 assert id == to_string(image_post.id)
1205 |> get("/api/v1/accounts/#{user.id}/statuses", %{"only_media" => "1"})
1207 assert [%{"id" => id}] = json_response(conn, 200)
1208 assert id == to_string(image_post.id)
1211 test "gets a user's statuses without reblogs", %{conn: conn} do
1212 user = insert(:user)
1213 {:ok, post} = CommonAPI.post(user, %{"status" => "HI!!!"})
1214 {:ok, _, _} = CommonAPI.repeat(post.id, user)
1218 |> get("/api/v1/accounts/#{user.id}/statuses", %{"exclude_reblogs" => "true"})
1220 assert [%{"id" => id}] = json_response(conn, 200)
1221 assert id == to_string(post.id)
1225 |> get("/api/v1/accounts/#{user.id}/statuses", %{"exclude_reblogs" => "1"})
1227 assert [%{"id" => id}] = json_response(conn, 200)
1228 assert id == to_string(post.id)
1232 describe "user relationships" do
1233 test "returns the relationships for the current user", %{conn: conn} do
1234 user = insert(:user)
1235 other_user = insert(:user)
1236 {:ok, user} = User.follow(user, other_user)
1240 |> assign(:user, user)
1241 |> get("/api/v1/accounts/relationships", %{"id" => [other_user.id]})
1243 assert [relationship] = json_response(conn, 200)
1245 assert to_string(other_user.id) == relationship["id"]
1249 describe "locked accounts" do
1250 test "/api/v1/follow_requests works" do
1251 user = insert(:user, %{info: %Pleroma.User.Info{locked: true}})
1252 other_user = insert(:user)
1254 {:ok, _activity} = ActivityPub.follow(other_user, user)
1256 user = User.get_cached_by_id(user.id)
1257 other_user = User.get_cached_by_id(other_user.id)
1259 assert User.following?(other_user, user) == false
1263 |> assign(:user, user)
1264 |> get("/api/v1/follow_requests")
1266 assert [relationship] = json_response(conn, 200)
1267 assert to_string(other_user.id) == relationship["id"]
1270 test "/api/v1/follow_requests/:id/authorize works" do
1271 user = insert(:user, %{info: %User.Info{locked: true}})
1272 other_user = insert(:user)
1274 {:ok, _activity} = ActivityPub.follow(other_user, user)
1276 user = User.get_cached_by_id(user.id)
1277 other_user = User.get_cached_by_id(other_user.id)
1279 assert User.following?(other_user, user) == false
1283 |> assign(:user, user)
1284 |> post("/api/v1/follow_requests/#{other_user.id}/authorize")
1286 assert relationship = json_response(conn, 200)
1287 assert to_string(other_user.id) == relationship["id"]
1289 user = User.get_cached_by_id(user.id)
1290 other_user = User.get_cached_by_id(other_user.id)
1292 assert User.following?(other_user, user) == true
1295 test "verify_credentials", %{conn: conn} do
1296 user = insert(:user, %{info: %Pleroma.User.Info{default_scope: "private"}})
1300 |> assign(:user, user)
1301 |> get("/api/v1/accounts/verify_credentials")
1303 assert %{"id" => id, "source" => %{"privacy" => "private"}} = json_response(conn, 200)
1304 assert id == to_string(user.id)
1307 test "/api/v1/follow_requests/:id/reject works" do
1308 user = insert(:user, %{info: %Pleroma.User.Info{locked: true}})
1309 other_user = insert(:user)
1311 {:ok, _activity} = ActivityPub.follow(other_user, user)
1313 user = User.get_cached_by_id(user.id)
1317 |> assign(:user, user)
1318 |> post("/api/v1/follow_requests/#{other_user.id}/reject")
1320 assert relationship = json_response(conn, 200)
1321 assert to_string(other_user.id) == relationship["id"]
1323 user = User.get_cached_by_id(user.id)
1324 other_user = User.get_cached_by_id(other_user.id)
1326 assert User.following?(other_user, user) == false
1330 test "account fetching", %{conn: conn} do
1331 user = insert(:user)
1335 |> get("/api/v1/accounts/#{user.id}")
1337 assert %{"id" => id} = json_response(conn, 200)
1338 assert id == to_string(user.id)
1342 |> get("/api/v1/accounts/-1")
1344 assert %{"error" => "Can't find user"} = json_response(conn, 404)
1347 test "account fetching also works nickname", %{conn: conn} do
1348 user = insert(:user)
1352 |> get("/api/v1/accounts/#{user.nickname}")
1354 assert %{"id" => id} = json_response(conn, 200)
1355 assert id == user.id
1358 test "media upload", %{conn: conn} do
1359 file = %Plug.Upload{
1360 content_type: "image/jpg",
1361 path: Path.absname("test/fixtures/image.jpg"),
1362 filename: "an_image.jpg"
1365 desc = "Description of the image"
1367 user = insert(:user)
1371 |> assign(:user, user)
1372 |> post("/api/v1/media", %{"file" => file, "description" => desc})
1374 assert media = json_response(conn, 200)
1376 assert media["type"] == "image"
1377 assert media["description"] == desc
1380 object = Repo.get(Object, media["id"])
1381 assert object.data["actor"] == User.ap_id(user)
1384 test "hashtag timeline", %{conn: conn} do
1385 following = insert(:user)
1388 {:ok, activity} = TwitterAPI.create_status(following, %{"status" => "test #2hu"})
1390 {:ok, [_activity]} =
1391 OStatus.fetch_activity_from_url("https://shitposter.club/notice/2827873")
1395 |> get("/api/v1/timelines/tag/2hu")
1397 assert [%{"id" => id}] = json_response(nconn, 200)
1399 assert id == to_string(activity.id)
1401 # works for different capitalization too
1404 |> get("/api/v1/timelines/tag/2HU")
1406 assert [%{"id" => id}] = json_response(nconn, 200)
1408 assert id == to_string(activity.id)
1412 test "multi-hashtag timeline", %{conn: conn} do
1413 user = insert(:user)
1415 {:ok, activity_test} = CommonAPI.post(user, %{"status" => "#test"})
1416 {:ok, activity_test1} = CommonAPI.post(user, %{"status" => "#test #test1"})
1417 {:ok, activity_none} = CommonAPI.post(user, %{"status" => "#test #none"})
1421 |> get("/api/v1/timelines/tag/test", %{"any" => ["test1"]})
1423 [status_none, status_test1, status_test] = json_response(any_test, 200)
1425 assert to_string(activity_test.id) == status_test["id"]
1426 assert to_string(activity_test1.id) == status_test1["id"]
1427 assert to_string(activity_none.id) == status_none["id"]
1431 |> get("/api/v1/timelines/tag/test", %{"all" => ["test1"], "none" => ["none"]})
1433 assert [status_test1] == json_response(restricted_test, 200)
1435 all_test = conn |> get("/api/v1/timelines/tag/test", %{"all" => ["none"]})
1437 assert [status_none] == json_response(all_test, 200)
1440 test "getting followers", %{conn: conn} do
1441 user = insert(:user)
1442 other_user = insert(:user)
1443 {:ok, user} = User.follow(user, other_user)
1447 |> get("/api/v1/accounts/#{other_user.id}/followers")
1449 assert [%{"id" => id}] = json_response(conn, 200)
1450 assert id == to_string(user.id)
1453 test "getting followers, hide_followers", %{conn: conn} do
1454 user = insert(:user)
1455 other_user = insert(:user, %{info: %{hide_followers: true}})
1456 {:ok, _user} = User.follow(user, other_user)
1460 |> get("/api/v1/accounts/#{other_user.id}/followers")
1462 assert [] == json_response(conn, 200)
1465 test "getting followers, hide_followers, same user requesting", %{conn: conn} do
1466 user = insert(:user)
1467 other_user = insert(:user, %{info: %{hide_followers: true}})
1468 {:ok, _user} = User.follow(user, other_user)
1472 |> assign(:user, other_user)
1473 |> get("/api/v1/accounts/#{other_user.id}/followers")
1475 refute [] == json_response(conn, 200)
1478 test "getting followers, pagination", %{conn: conn} do
1479 user = insert(:user)
1480 follower1 = insert(:user)
1481 follower2 = insert(:user)
1482 follower3 = insert(:user)
1483 {:ok, _} = User.follow(follower1, user)
1484 {:ok, _} = User.follow(follower2, user)
1485 {:ok, _} = User.follow(follower3, user)
1489 |> assign(:user, user)
1493 |> get("/api/v1/accounts/#{user.id}/followers?since_id=#{follower1.id}")
1495 assert [%{"id" => id3}, %{"id" => id2}] = json_response(res_conn, 200)
1496 assert id3 == follower3.id
1497 assert id2 == follower2.id
1501 |> get("/api/v1/accounts/#{user.id}/followers?max_id=#{follower3.id}")
1503 assert [%{"id" => id2}, %{"id" => id1}] = json_response(res_conn, 200)
1504 assert id2 == follower2.id
1505 assert id1 == follower1.id
1509 |> get("/api/v1/accounts/#{user.id}/followers?limit=1&max_id=#{follower3.id}")
1511 assert [%{"id" => id2}] = json_response(res_conn, 200)
1512 assert id2 == follower2.id
1514 assert [link_header] = get_resp_header(res_conn, "link")
1515 assert link_header =~ ~r/min_id=#{follower2.id}/
1516 assert link_header =~ ~r/max_id=#{follower2.id}/
1519 test "getting following", %{conn: conn} do
1520 user = insert(:user)
1521 other_user = insert(:user)
1522 {:ok, user} = User.follow(user, other_user)
1526 |> get("/api/v1/accounts/#{user.id}/following")
1528 assert [%{"id" => id}] = json_response(conn, 200)
1529 assert id == to_string(other_user.id)
1532 test "getting following, hide_follows", %{conn: conn} do
1533 user = insert(:user, %{info: %{hide_follows: true}})
1534 other_user = insert(:user)
1535 {:ok, user} = User.follow(user, other_user)
1539 |> get("/api/v1/accounts/#{user.id}/following")
1541 assert [] == json_response(conn, 200)
1544 test "getting following, hide_follows, same user requesting", %{conn: conn} do
1545 user = insert(:user, %{info: %{hide_follows: true}})
1546 other_user = insert(:user)
1547 {:ok, user} = User.follow(user, other_user)
1551 |> assign(:user, user)
1552 |> get("/api/v1/accounts/#{user.id}/following")
1554 refute [] == json_response(conn, 200)
1557 test "getting following, pagination", %{conn: conn} do
1558 user = insert(:user)
1559 following1 = insert(:user)
1560 following2 = insert(:user)
1561 following3 = insert(:user)
1562 {:ok, _} = User.follow(user, following1)
1563 {:ok, _} = User.follow(user, following2)
1564 {:ok, _} = User.follow(user, following3)
1568 |> assign(:user, user)
1572 |> get("/api/v1/accounts/#{user.id}/following?since_id=#{following1.id}")
1574 assert [%{"id" => id3}, %{"id" => id2}] = json_response(res_conn, 200)
1575 assert id3 == following3.id
1576 assert id2 == following2.id
1580 |> get("/api/v1/accounts/#{user.id}/following?max_id=#{following3.id}")
1582 assert [%{"id" => id2}, %{"id" => id1}] = json_response(res_conn, 200)
1583 assert id2 == following2.id
1584 assert id1 == following1.id
1588 |> get("/api/v1/accounts/#{user.id}/following?limit=1&max_id=#{following3.id}")
1590 assert [%{"id" => id2}] = json_response(res_conn, 200)
1591 assert id2 == following2.id
1593 assert [link_header] = get_resp_header(res_conn, "link")
1594 assert link_header =~ ~r/min_id=#{following2.id}/
1595 assert link_header =~ ~r/max_id=#{following2.id}/
1598 test "following / unfollowing a user", %{conn: conn} do
1599 user = insert(:user)
1600 other_user = insert(:user)
1604 |> assign(:user, user)
1605 |> post("/api/v1/accounts/#{other_user.id}/follow")
1607 assert %{"id" => _id, "following" => true} = json_response(conn, 200)
1609 user = User.get_cached_by_id(user.id)
1613 |> assign(:user, user)
1614 |> post("/api/v1/accounts/#{other_user.id}/unfollow")
1616 assert %{"id" => _id, "following" => false} = json_response(conn, 200)
1618 user = User.get_cached_by_id(user.id)
1622 |> assign(:user, user)
1623 |> post("/api/v1/follows", %{"uri" => other_user.nickname})
1625 assert %{"id" => id} = json_response(conn, 200)
1626 assert id == to_string(other_user.id)
1629 test "following without reblogs" do
1630 follower = insert(:user)
1631 followed = insert(:user)
1632 other_user = insert(:user)
1636 |> assign(:user, follower)
1637 |> post("/api/v1/accounts/#{followed.id}/follow?reblogs=false")
1639 assert %{"showing_reblogs" => false} = json_response(conn, 200)
1641 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "hey"})
1642 {:ok, reblog, _} = CommonAPI.repeat(activity.id, followed)
1646 |> assign(:user, User.get_cached_by_id(follower.id))
1647 |> get("/api/v1/timelines/home")
1649 assert [] == json_response(conn, 200)
1653 |> assign(:user, follower)
1654 |> post("/api/v1/accounts/#{followed.id}/follow?reblogs=true")
1656 assert %{"showing_reblogs" => true} = json_response(conn, 200)
1660 |> assign(:user, User.get_cached_by_id(follower.id))
1661 |> get("/api/v1/timelines/home")
1663 expected_activity_id = reblog.id
1664 assert [%{"id" => ^expected_activity_id}] = json_response(conn, 200)
1667 test "following / unfollowing errors" do
1668 user = insert(:user)
1672 |> assign(:user, user)
1675 conn_res = post(conn, "/api/v1/accounts/#{user.id}/follow")
1676 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
1679 user = User.get_cached_by_id(user.id)
1680 conn_res = post(conn, "/api/v1/accounts/#{user.id}/unfollow")
1681 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
1683 # self follow via uri
1684 user = User.get_cached_by_id(user.id)
1685 conn_res = post(conn, "/api/v1/follows", %{"uri" => user.nickname})
1686 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
1688 # follow non existing user
1689 conn_res = post(conn, "/api/v1/accounts/doesntexist/follow")
1690 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
1692 # follow non existing user via uri
1693 conn_res = post(conn, "/api/v1/follows", %{"uri" => "doesntexist"})
1694 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
1696 # unfollow non existing user
1697 conn_res = post(conn, "/api/v1/accounts/doesntexist/unfollow")
1698 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
1701 test "muting / unmuting a user", %{conn: conn} do
1702 user = insert(:user)
1703 other_user = insert(:user)
1707 |> assign(:user, user)
1708 |> post("/api/v1/accounts/#{other_user.id}/mute")
1710 assert %{"id" => _id, "muting" => true} = json_response(conn, 200)
1712 user = User.get_cached_by_id(user.id)
1716 |> assign(:user, user)
1717 |> post("/api/v1/accounts/#{other_user.id}/unmute")
1719 assert %{"id" => _id, "muting" => false} = json_response(conn, 200)
1722 test "subscribing / unsubscribing to a user", %{conn: conn} do
1723 user = insert(:user)
1724 subscription_target = insert(:user)
1728 |> assign(:user, user)
1729 |> post("/api/v1/pleroma/accounts/#{subscription_target.id}/subscribe")
1731 assert %{"id" => _id, "subscribing" => true} = json_response(conn, 200)
1735 |> assign(:user, user)
1736 |> post("/api/v1/pleroma/accounts/#{subscription_target.id}/unsubscribe")
1738 assert %{"id" => _id, "subscribing" => false} = json_response(conn, 200)
1741 test "getting a list of mutes", %{conn: conn} do
1742 user = insert(:user)
1743 other_user = insert(:user)
1745 {:ok, user} = User.mute(user, other_user)
1749 |> assign(:user, user)
1750 |> get("/api/v1/mutes")
1752 other_user_id = to_string(other_user.id)
1753 assert [%{"id" => ^other_user_id}] = json_response(conn, 200)
1756 test "blocking / unblocking a user", %{conn: conn} do
1757 user = insert(:user)
1758 other_user = insert(:user)
1762 |> assign(:user, user)
1763 |> post("/api/v1/accounts/#{other_user.id}/block")
1765 assert %{"id" => _id, "blocking" => true} = json_response(conn, 200)
1767 user = User.get_cached_by_id(user.id)
1771 |> assign(:user, user)
1772 |> post("/api/v1/accounts/#{other_user.id}/unblock")
1774 assert %{"id" => _id, "blocking" => false} = json_response(conn, 200)
1777 test "getting a list of blocks", %{conn: conn} do
1778 user = insert(:user)
1779 other_user = insert(:user)
1781 {:ok, user} = User.block(user, other_user)
1785 |> assign(:user, user)
1786 |> get("/api/v1/blocks")
1788 other_user_id = to_string(other_user.id)
1789 assert [%{"id" => ^other_user_id}] = json_response(conn, 200)
1792 test "blocking / unblocking a domain", %{conn: conn} do
1793 user = insert(:user)
1794 other_user = insert(:user, %{ap_id: "https://dogwhistle.zone/@pundit"})
1798 |> assign(:user, user)
1799 |> post("/api/v1/domain_blocks", %{"domain" => "dogwhistle.zone"})
1801 assert %{} = json_response(conn, 200)
1802 user = User.get_cached_by_ap_id(user.ap_id)
1803 assert User.blocks?(user, other_user)
1807 |> assign(:user, user)
1808 |> delete("/api/v1/domain_blocks", %{"domain" => "dogwhistle.zone"})
1810 assert %{} = json_response(conn, 200)
1811 user = User.get_cached_by_ap_id(user.ap_id)
1812 refute User.blocks?(user, other_user)
1815 test "getting a list of domain blocks", %{conn: conn} do
1816 user = insert(:user)
1818 {:ok, user} = User.block_domain(user, "bad.site")
1819 {:ok, user} = User.block_domain(user, "even.worse.site")
1823 |> assign(:user, user)
1824 |> get("/api/v1/domain_blocks")
1826 domain_blocks = json_response(conn, 200)
1828 assert "bad.site" in domain_blocks
1829 assert "even.worse.site" in domain_blocks
1832 test "unimplemented follow_requests, blocks, domain blocks" do
1833 user = insert(:user)
1835 ["blocks", "domain_blocks", "follow_requests"]
1836 |> Enum.each(fn endpoint ->
1839 |> assign(:user, user)
1840 |> get("/api/v1/#{endpoint}")
1842 assert [] = json_response(conn, 200)
1846 test "account search", %{conn: conn} do
1847 user = insert(:user)
1848 user_two = insert(:user, %{nickname: "shp@shitposter.club"})
1849 user_three = insert(:user, %{nickname: "shp@heldscal.la", name: "I love 2hu"})
1853 |> assign(:user, user)
1854 |> get("/api/v1/accounts/search", %{"q" => "shp"})
1855 |> json_response(200)
1857 result_ids = for result <- results, do: result["acct"]
1859 assert user_two.nickname in result_ids
1860 assert user_three.nickname in result_ids
1864 |> assign(:user, user)
1865 |> get("/api/v1/accounts/search", %{"q" => "2hu"})
1866 |> json_response(200)
1868 result_ids = for result <- results, do: result["acct"]
1870 assert user_three.nickname in result_ids
1873 test "search", %{conn: conn} do
1874 user = insert(:user)
1875 user_two = insert(:user, %{nickname: "shp@shitposter.club"})
1876 user_three = insert(:user, %{nickname: "shp@heldscal.la", name: "I love 2hu"})
1878 {:ok, activity} = CommonAPI.post(user, %{"status" => "This is about 2hu"})
1881 CommonAPI.post(user, %{
1882 "status" => "This is about 2hu, but private",
1883 "visibility" => "private"
1886 {:ok, _} = CommonAPI.post(user_two, %{"status" => "This isn't"})
1890 |> get("/api/v1/search", %{"q" => "2hu"})
1892 assert results = json_response(conn, 200)
1894 [account | _] = results["accounts"]
1895 assert account["id"] == to_string(user_three.id)
1897 assert results["hashtags"] == []
1899 [status] = results["statuses"]
1900 assert status["id"] == to_string(activity.id)
1903 test "search fetches remote statuses", %{conn: conn} do
1907 |> get("/api/v1/search", %{"q" => "https://shitposter.club/notice/2827873"})
1909 assert results = json_response(conn, 200)
1911 [status] = results["statuses"]
1912 assert status["uri"] == "tag:shitposter.club,2017-05-05:noticeId=2827873:objectType=comment"
1916 test "search doesn't show statuses that it shouldn't", %{conn: conn} do
1918 CommonAPI.post(insert(:user), %{
1919 "status" => "This is about 2hu, but private",
1920 "visibility" => "private"
1926 |> get("/api/v1/search", %{"q" => Object.normalize(activity).data["id"]})
1928 assert results = json_response(conn, 200)
1930 [] = results["statuses"]
1934 test "search fetches remote accounts", %{conn: conn} do
1937 |> get("/api/v1/search", %{"q" => "shp@social.heldscal.la", "resolve" => "true"})
1939 assert results = json_response(conn, 200)
1940 [account] = results["accounts"]
1941 assert account["acct"] == "shp@social.heldscal.la"
1944 test "returns the favorites of a user", %{conn: conn} do
1945 user = insert(:user)
1946 other_user = insert(:user)
1948 {:ok, _} = CommonAPI.post(other_user, %{"status" => "bla"})
1949 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "traps are happy"})
1951 {:ok, _, _} = CommonAPI.favorite(activity.id, user)
1955 |> assign(:user, user)
1956 |> get("/api/v1/favourites")
1958 assert [status] = json_response(first_conn, 200)
1959 assert status["id"] == to_string(activity.id)
1961 assert [{"link", _link_header}] =
1962 Enum.filter(first_conn.resp_headers, fn element -> match?({"link", _}, element) end)
1964 # Honours query params
1965 {:ok, second_activity} =
1966 CommonAPI.post(other_user, %{
1968 "Trees Are Never Sad Look At Them Every Once In Awhile They're Quite Beautiful."
1971 {:ok, _, _} = CommonAPI.favorite(second_activity.id, user)
1973 last_like = status["id"]
1977 |> assign(:user, user)
1978 |> get("/api/v1/favourites?since_id=#{last_like}")
1980 assert [second_status] = json_response(second_conn, 200)
1981 assert second_status["id"] == to_string(second_activity.id)
1985 |> assign(:user, user)
1986 |> get("/api/v1/favourites?limit=0")
1988 assert [] = json_response(third_conn, 200)
1991 describe "updating credentials" do
1992 test "updates the user's bio", %{conn: conn} do
1993 user = insert(:user)
1994 user2 = insert(:user)
1998 |> assign(:user, user)
1999 |> patch("/api/v1/accounts/update_credentials", %{
2000 "note" => "I drink #cofe with @#{user2.nickname}"
2003 assert user = json_response(conn, 200)
2005 assert user["note"] ==
2006 ~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=") <>
2008 ~s(" class="u-url mention" href=") <>
2009 user2.ap_id <> ~s(">@<span>) <> user2.nickname <> ~s(</span></a></span>)
2012 test "updates the user's locking status", %{conn: conn} do
2013 user = insert(:user)
2017 |> assign(:user, user)
2018 |> patch("/api/v1/accounts/update_credentials", %{locked: "true"})
2020 assert user = json_response(conn, 200)
2021 assert user["locked"] == true
2024 test "updates the user's name", %{conn: conn} do
2025 user = insert(:user)
2029 |> assign(:user, user)
2030 |> patch("/api/v1/accounts/update_credentials", %{"display_name" => "markorepairs"})
2032 assert user = json_response(conn, 200)
2033 assert user["display_name"] == "markorepairs"
2036 test "updates the user's avatar", %{conn: conn} do
2037 user = insert(:user)
2039 new_avatar = %Plug.Upload{
2040 content_type: "image/jpg",
2041 path: Path.absname("test/fixtures/image.jpg"),
2042 filename: "an_image.jpg"
2047 |> assign(:user, user)
2048 |> patch("/api/v1/accounts/update_credentials", %{"avatar" => new_avatar})
2050 assert user_response = json_response(conn, 200)
2051 assert user_response["avatar"] != User.avatar_url(user)
2054 test "updates the user's banner", %{conn: conn} do
2055 user = insert(:user)
2057 new_header = %Plug.Upload{
2058 content_type: "image/jpg",
2059 path: Path.absname("test/fixtures/image.jpg"),
2060 filename: "an_image.jpg"
2065 |> assign(:user, user)
2066 |> patch("/api/v1/accounts/update_credentials", %{"header" => new_header})
2068 assert user_response = json_response(conn, 200)
2069 assert user_response["header"] != User.banner_url(user)
2072 test "requires 'write' permission", %{conn: conn} do
2073 token1 = insert(:oauth_token, scopes: ["read"])
2074 token2 = insert(:oauth_token, scopes: ["write", "follow"])
2076 for token <- [token1, token2] do
2079 |> put_req_header("authorization", "Bearer #{token.token}")
2080 |> patch("/api/v1/accounts/update_credentials", %{})
2082 if token == token1 do
2083 assert %{"error" => "Insufficient permissions: write."} == json_response(conn, 403)
2085 assert json_response(conn, 200)
2091 test "get instance information", %{conn: conn} do
2092 conn = get(conn, "/api/v1/instance")
2093 assert result = json_response(conn, 200)
2095 email = Pleroma.Config.get([:instance, :email])
2096 # Note: not checking for "max_toot_chars" since it's optional
2102 "email" => from_config_email,
2104 "streaming_api" => _
2109 "registrations" => _
2112 assert email == from_config_email
2115 test "get instance stats", %{conn: conn} do
2116 user = insert(:user, %{local: true})
2118 user2 = insert(:user, %{local: true})
2119 {:ok, _user2} = User.deactivate(user2, !user2.info.deactivated)
2121 insert(:user, %{local: false, nickname: "u@peer1.com"})
2122 insert(:user, %{local: false, nickname: "u@peer2.com"})
2124 {:ok, _} = TwitterAPI.create_status(user, %{"status" => "cofe"})
2126 # Stats should count users with missing or nil `info.deactivated` value
2127 user = User.get_cached_by_id(user.id)
2128 info_change = Changeset.change(user.info, %{deactivated: nil})
2132 |> Changeset.change()
2133 |> Changeset.put_embed(:info, info_change)
2134 |> User.update_and_set_cache()
2136 Pleroma.Stats.update_stats()
2138 conn = get(conn, "/api/v1/instance")
2140 assert result = json_response(conn, 200)
2142 stats = result["stats"]
2145 assert stats["user_count"] == 1
2146 assert stats["status_count"] == 1
2147 assert stats["domain_count"] == 2
2150 test "get peers", %{conn: conn} do
2151 insert(:user, %{local: false, nickname: "u@peer1.com"})
2152 insert(:user, %{local: false, nickname: "u@peer2.com"})
2154 Pleroma.Stats.update_stats()
2156 conn = get(conn, "/api/v1/instance/peers")
2158 assert result = json_response(conn, 200)
2160 assert ["peer1.com", "peer2.com"] == Enum.sort(result)
2163 test "put settings", %{conn: conn} do
2164 user = insert(:user)
2168 |> assign(:user, user)
2169 |> put("/api/web/settings", %{"data" => %{"programming" => "socks"}})
2171 assert _result = json_response(conn, 200)
2173 user = User.get_cached_by_ap_id(user.ap_id)
2174 assert user.info.settings == %{"programming" => "socks"}
2177 describe "pinned statuses" do
2179 Pleroma.Config.put([:instance, :max_pinned_statuses], 1)
2181 user = insert(:user)
2182 {:ok, activity} = CommonAPI.post(user, %{"status" => "HI!!!"})
2184 [user: user, activity: activity]
2187 test "returns pinned statuses", %{conn: conn, user: user, activity: activity} do
2188 {:ok, _} = CommonAPI.pin(activity.id, user)
2192 |> assign(:user, user)
2193 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
2194 |> json_response(200)
2196 id_str = to_string(activity.id)
2198 assert [%{"id" => ^id_str, "pinned" => true}] = result
2201 test "pin status", %{conn: conn, user: user, activity: activity} do
2202 id_str = to_string(activity.id)
2204 assert %{"id" => ^id_str, "pinned" => true} =
2206 |> assign(:user, user)
2207 |> post("/api/v1/statuses/#{activity.id}/pin")
2208 |> json_response(200)
2210 assert [%{"id" => ^id_str, "pinned" => true}] =
2212 |> assign(:user, user)
2213 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
2214 |> json_response(200)
2217 test "unpin status", %{conn: conn, user: user, activity: activity} do
2218 {:ok, _} = CommonAPI.pin(activity.id, user)
2220 id_str = to_string(activity.id)
2221 user = refresh_record(user)
2223 assert %{"id" => ^id_str, "pinned" => false} =
2225 |> assign(:user, user)
2226 |> post("/api/v1/statuses/#{activity.id}/unpin")
2227 |> json_response(200)
2231 |> assign(:user, user)
2232 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
2233 |> json_response(200)
2236 test "max pinned statuses", %{conn: conn, user: user, activity: activity_one} do
2237 {:ok, activity_two} = CommonAPI.post(user, %{"status" => "HI!!!"})
2239 id_str_one = to_string(activity_one.id)
2241 assert %{"id" => ^id_str_one, "pinned" => true} =
2243 |> assign(:user, user)
2244 |> post("/api/v1/statuses/#{id_str_one}/pin")
2245 |> json_response(200)
2247 user = refresh_record(user)
2249 assert %{"error" => "You have already pinned the maximum number of statuses"} =
2251 |> assign(:user, user)
2252 |> post("/api/v1/statuses/#{activity_two.id}/pin")
2253 |> json_response(400)
2256 test "Status rich-media Card", %{conn: conn, user: user} do
2257 Pleroma.Config.put([:rich_media, :enabled], true)
2258 {:ok, activity} = CommonAPI.post(user, %{"status" => "http://example.com/ogp"})
2262 |> get("/api/v1/statuses/#{activity.id}/card")
2263 |> json_response(200)
2265 assert response == %{
2266 "image" => "http://ia.media-imdb.com/images/rock.jpg",
2267 "provider_name" => "www.imdb.com",
2268 "provider_url" => "http://www.imdb.com",
2269 "title" => "The Rock",
2271 "url" => "http://www.imdb.com/title/tt0117500/",
2272 "description" => nil,
2275 "image" => "http://ia.media-imdb.com/images/rock.jpg",
2276 "title" => "The Rock",
2277 "type" => "video.movie",
2278 "url" => "http://www.imdb.com/title/tt0117500/"
2283 # works with private posts
2285 CommonAPI.post(user, %{"status" => "http://example.com/ogp", "visibility" => "direct"})
2289 |> assign(:user, user)
2290 |> get("/api/v1/statuses/#{activity.id}/card")
2291 |> json_response(200)
2293 assert response_two == response
2295 Pleroma.Config.put([:rich_media, :enabled], false)
2300 user = insert(:user)
2301 for_user = insert(:user)
2304 CommonAPI.post(user, %{
2305 "status" => "heweoo?"
2309 CommonAPI.post(user, %{
2310 "status" => "heweoo!"
2315 |> assign(:user, for_user)
2316 |> post("/api/v1/statuses/#{activity1.id}/bookmark")
2318 assert json_response(response1, 200)["bookmarked"] == true
2322 |> assign(:user, for_user)
2323 |> post("/api/v1/statuses/#{activity2.id}/bookmark")
2325 assert json_response(response2, 200)["bookmarked"] == true
2329 |> assign(:user, for_user)
2330 |> get("/api/v1/bookmarks")
2332 assert [json_response(response2, 200), json_response(response1, 200)] ==
2333 json_response(bookmarks, 200)
2337 |> assign(:user, for_user)
2338 |> post("/api/v1/statuses/#{activity1.id}/unbookmark")
2340 assert json_response(response1, 200)["bookmarked"] == false
2344 |> assign(:user, for_user)
2345 |> get("/api/v1/bookmarks")
2347 assert [json_response(response2, 200)] == json_response(bookmarks, 200)
2350 describe "conversation muting" do
2352 user = insert(:user)
2353 {:ok, activity} = CommonAPI.post(user, %{"status" => "HIE"})
2355 [user: user, activity: activity]
2358 test "mute conversation", %{conn: conn, user: user, activity: activity} do
2359 id_str = to_string(activity.id)
2361 assert %{"id" => ^id_str, "muted" => true} =
2363 |> assign(:user, user)
2364 |> post("/api/v1/statuses/#{activity.id}/mute")
2365 |> json_response(200)
2368 test "unmute conversation", %{conn: conn, user: user, activity: activity} do
2369 {:ok, _} = CommonAPI.add_mute(user, activity)
2371 id_str = to_string(activity.id)
2372 user = refresh_record(user)
2374 assert %{"id" => ^id_str, "muted" => false} =
2376 |> assign(:user, user)
2377 |> post("/api/v1/statuses/#{activity.id}/unmute")
2378 |> json_response(200)
2382 test "flavours switching (Pleroma Extension)", %{conn: conn} do
2383 user = insert(:user)
2387 |> assign(:user, user)
2388 |> get("/api/v1/pleroma/flavour")
2390 assert "glitch" == json_response(get_old_flavour, 200)
2394 |> assign(:user, user)
2395 |> post("/api/v1/pleroma/flavour/vanilla")
2397 assert "vanilla" == json_response(set_flavour, 200)
2401 |> assign(:user, user)
2402 |> post("/api/v1/pleroma/flavour/vanilla")
2404 assert json_response(set_flavour, 200) == json_response(get_new_flavour, 200)
2407 describe "reports" do
2409 reporter = insert(:user)
2410 target_user = insert(:user)
2412 {:ok, activity} = CommonAPI.post(target_user, %{"status" => "foobar"})
2414 [reporter: reporter, target_user: target_user, activity: activity]
2417 test "submit a basic report", %{conn: conn, reporter: reporter, target_user: target_user} do
2418 assert %{"action_taken" => false, "id" => _} =
2420 |> assign(:user, reporter)
2421 |> post("/api/v1/reports", %{"account_id" => target_user.id})
2422 |> json_response(200)
2425 test "submit a report with statuses and comment", %{
2428 target_user: target_user,
2431 assert %{"action_taken" => false, "id" => _} =
2433 |> assign(:user, reporter)
2434 |> post("/api/v1/reports", %{
2435 "account_id" => target_user.id,
2436 "status_ids" => [activity.id],
2437 "comment" => "bad status!"
2439 |> json_response(200)
2442 test "account_id is required", %{
2447 assert %{"error" => "Valid `account_id` required"} =
2449 |> assign(:user, reporter)
2450 |> post("/api/v1/reports", %{"status_ids" => [activity.id]})
2451 |> json_response(400)
2454 test "comment must be up to the size specified in the config", %{
2457 target_user: target_user
2459 max_size = Pleroma.Config.get([:instance, :max_report_comment_size], 1000)
2460 comment = String.pad_trailing("a", max_size + 1, "a")
2462 error = %{"error" => "Comment must be up to #{max_size} characters"}
2466 |> assign(:user, reporter)
2467 |> post("/api/v1/reports", %{"account_id" => target_user.id, "comment" => comment})
2468 |> json_response(400)
2472 describe "link headers" do
2473 test "preserves parameters in link headers", %{conn: conn} do
2474 user = insert(:user)
2475 other_user = insert(:user)
2478 CommonAPI.post(other_user, %{
2479 "status" => "hi @#{user.nickname}",
2480 "visibility" => "public"
2484 CommonAPI.post(other_user, %{
2485 "status" => "hi @#{user.nickname}",
2486 "visibility" => "public"
2489 notification1 = Repo.get_by(Notification, activity_id: activity1.id)
2490 notification2 = Repo.get_by(Notification, activity_id: activity2.id)
2494 |> assign(:user, user)
2495 |> get("/api/v1/notifications", %{media_only: true})
2497 assert [link_header] = get_resp_header(conn, "link")
2498 assert link_header =~ ~r/media_only=true/
2499 assert link_header =~ ~r/min_id=#{notification2.id}/
2500 assert link_header =~ ~r/max_id=#{notification1.id}/
2504 test "accounts fetches correct account for nicknames beginning with numbers", %{conn: conn} do
2505 # Need to set an old-style integer ID to reproduce the problem
2506 # (these are no longer assigned to new accounts but were preserved
2507 # for existing accounts during the migration to flakeIDs)
2508 user_one = insert(:user, %{id: 1212})
2509 user_two = insert(:user, %{nickname: "#{user_one.id}garbage"})
2513 |> get("/api/v1/accounts/#{user_one.id}")
2517 |> get("/api/v1/accounts/#{user_two.nickname}")
2521 |> get("/api/v1/accounts/#{user_two.id}")
2523 acc_one = json_response(resp_one, 200)
2524 acc_two = json_response(resp_two, 200)
2525 acc_three = json_response(resp_three, 200)
2526 refute acc_one == acc_two
2527 assert acc_two == acc_three
2530 describe "custom emoji" do
2531 test "with tags", %{conn: conn} do
2534 |> get("/api/v1/custom_emojis")
2535 |> json_response(200)
2537 assert Map.has_key?(emoji, "shortcode")
2538 assert Map.has_key?(emoji, "static_url")
2539 assert Map.has_key?(emoji, "tags")
2540 assert is_list(emoji["tags"])
2541 assert Map.has_key?(emoji, "url")
2542 assert Map.has_key?(emoji, "visible_in_picker")
2546 describe "index/2 redirections" do
2547 setup %{conn: conn} do
2551 signing_salt: "cooldude"
2556 |> Plug.Session.call(Plug.Session.init(session_opts))
2559 test_path = "/web/statuses/test"
2560 %{conn: conn, path: test_path}
2563 test "redirects not logged-in users to the login page", %{conn: conn, path: path} do
2564 conn = get(conn, path)
2566 assert conn.status == 302
2567 assert redirected_to(conn) == "/web/login"
2570 test "does not redirect logged in users to the login page", %{conn: conn, path: path} do
2571 token = insert(:oauth_token)
2575 |> assign(:user, token.user)
2576 |> put_session(:oauth_token, token.token)
2579 assert conn.status == 200
2582 test "saves referer path to session", %{conn: conn, path: path} do
2583 conn = get(conn, path)
2584 return_to = Plug.Conn.get_session(conn, :return_to)
2586 assert return_to == path
2589 test "redirects to the saved path after log in", %{conn: conn, path: path} do
2590 app = insert(:oauth_app, client_name: "Mastodon-Local", redirect_uris: ".")
2591 auth = insert(:oauth_authorization, app: app)
2595 |> put_session(:return_to, path)
2596 |> get("/web/login", %{code: auth.token})
2598 assert conn.status == 302
2599 assert redirected_to(conn) == path
2602 test "redirects to the getting-started page when referer is not present", %{conn: conn} do
2603 app = insert(:oauth_app, client_name: "Mastodon-Local", redirect_uris: ".")
2604 auth = insert(:oauth_authorization, app: app)
2606 conn = get(conn, "/web/login", %{code: auth.token})
2608 assert conn.status == 302
2609 assert redirected_to(conn) == "/web/getting-started"
2613 describe "scheduled activities" do
2614 test "creates a scheduled activity", %{conn: conn} do
2615 user = insert(:user)
2616 scheduled_at = NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond)
2620 |> assign(:user, user)
2621 |> post("/api/v1/statuses", %{
2622 "status" => "scheduled",
2623 "scheduled_at" => scheduled_at
2626 assert %{"scheduled_at" => expected_scheduled_at} = json_response(conn, 200)
2627 assert expected_scheduled_at == Pleroma.Web.CommonAPI.Utils.to_masto_date(scheduled_at)
2628 assert [] == Repo.all(Activity)
2631 test "creates a scheduled activity with a media attachment", %{conn: conn} do
2632 user = insert(:user)
2633 scheduled_at = NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond)
2635 file = %Plug.Upload{
2636 content_type: "image/jpg",
2637 path: Path.absname("test/fixtures/image.jpg"),
2638 filename: "an_image.jpg"
2641 {:ok, upload} = ActivityPub.upload(file, actor: user.ap_id)
2645 |> assign(:user, user)
2646 |> post("/api/v1/statuses", %{
2647 "media_ids" => [to_string(upload.id)],
2648 "status" => "scheduled",
2649 "scheduled_at" => scheduled_at
2652 assert %{"media_attachments" => [media_attachment]} = json_response(conn, 200)
2653 assert %{"type" => "image"} = media_attachment
2656 test "skips the scheduling and creates the activity if scheduled_at is earlier than 5 minutes from now",
2658 user = insert(:user)
2661 NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(5) - 1, :millisecond)
2665 |> assign(:user, user)
2666 |> post("/api/v1/statuses", %{
2667 "status" => "not scheduled",
2668 "scheduled_at" => scheduled_at
2671 assert %{"content" => "not scheduled"} = json_response(conn, 200)
2672 assert [] == Repo.all(ScheduledActivity)
2675 test "returns error when daily user limit is exceeded", %{conn: conn} do
2676 user = insert(:user)
2679 NaiveDateTime.utc_now()
2680 |> NaiveDateTime.add(:timer.minutes(6), :millisecond)
2681 |> NaiveDateTime.to_iso8601()
2683 attrs = %{params: %{}, scheduled_at: today}
2684 {:ok, _} = ScheduledActivity.create(user, attrs)
2685 {:ok, _} = ScheduledActivity.create(user, attrs)
2689 |> assign(:user, user)
2690 |> post("/api/v1/statuses", %{"status" => "scheduled", "scheduled_at" => today})
2692 assert %{"error" => "daily limit exceeded"} == json_response(conn, 422)
2695 test "returns error when total user limit is exceeded", %{conn: conn} do
2696 user = insert(:user)
2699 NaiveDateTime.utc_now()
2700 |> NaiveDateTime.add(:timer.minutes(6), :millisecond)
2701 |> NaiveDateTime.to_iso8601()
2704 NaiveDateTime.utc_now()
2705 |> NaiveDateTime.add(:timer.hours(36), :millisecond)
2706 |> NaiveDateTime.to_iso8601()
2708 attrs = %{params: %{}, scheduled_at: today}
2709 {:ok, _} = ScheduledActivity.create(user, attrs)
2710 {:ok, _} = ScheduledActivity.create(user, attrs)
2711 {:ok, _} = ScheduledActivity.create(user, %{params: %{}, scheduled_at: tomorrow})
2715 |> assign(:user, user)
2716 |> post("/api/v1/statuses", %{"status" => "scheduled", "scheduled_at" => tomorrow})
2718 assert %{"error" => "total limit exceeded"} == json_response(conn, 422)
2721 test "shows scheduled activities", %{conn: conn} do
2722 user = insert(:user)
2723 scheduled_activity_id1 = insert(:scheduled_activity, user: user).id |> to_string()
2724 scheduled_activity_id2 = insert(:scheduled_activity, user: user).id |> to_string()
2725 scheduled_activity_id3 = insert(:scheduled_activity, user: user).id |> to_string()
2726 scheduled_activity_id4 = insert(:scheduled_activity, user: user).id |> to_string()
2730 |> assign(:user, user)
2735 |> get("/api/v1/scheduled_statuses?limit=2&min_id=#{scheduled_activity_id1}")
2737 result = json_response(conn_res, 200)
2738 assert [%{"id" => ^scheduled_activity_id3}, %{"id" => ^scheduled_activity_id2}] = result
2743 |> get("/api/v1/scheduled_statuses?limit=2&since_id=#{scheduled_activity_id1}")
2745 result = json_response(conn_res, 200)
2746 assert [%{"id" => ^scheduled_activity_id4}, %{"id" => ^scheduled_activity_id3}] = result
2751 |> get("/api/v1/scheduled_statuses?limit=2&max_id=#{scheduled_activity_id4}")
2753 result = json_response(conn_res, 200)
2754 assert [%{"id" => ^scheduled_activity_id3}, %{"id" => ^scheduled_activity_id2}] = result
2757 test "shows a scheduled activity", %{conn: conn} do
2758 user = insert(:user)
2759 scheduled_activity = insert(:scheduled_activity, user: user)
2763 |> assign(:user, user)
2764 |> get("/api/v1/scheduled_statuses/#{scheduled_activity.id}")
2766 assert %{"id" => scheduled_activity_id} = json_response(res_conn, 200)
2767 assert scheduled_activity_id == scheduled_activity.id |> to_string()
2771 |> assign(:user, user)
2772 |> get("/api/v1/scheduled_statuses/404")
2774 assert %{"error" => "Record not found"} = json_response(res_conn, 404)
2777 test "updates a scheduled activity", %{conn: conn} do
2778 user = insert(:user)
2779 scheduled_activity = insert(:scheduled_activity, user: user)
2782 NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond)
2786 |> assign(:user, user)
2787 |> put("/api/v1/scheduled_statuses/#{scheduled_activity.id}", %{
2788 scheduled_at: new_scheduled_at
2791 assert %{"scheduled_at" => expected_scheduled_at} = json_response(res_conn, 200)
2792 assert expected_scheduled_at == Pleroma.Web.CommonAPI.Utils.to_masto_date(new_scheduled_at)
2796 |> assign(:user, user)
2797 |> put("/api/v1/scheduled_statuses/404", %{scheduled_at: new_scheduled_at})
2799 assert %{"error" => "Record not found"} = json_response(res_conn, 404)
2802 test "deletes a scheduled activity", %{conn: conn} do
2803 user = insert(:user)
2804 scheduled_activity = insert(:scheduled_activity, user: user)
2808 |> assign(:user, user)
2809 |> delete("/api/v1/scheduled_statuses/#{scheduled_activity.id}")
2811 assert %{} = json_response(res_conn, 200)
2812 assert nil == Repo.get(ScheduledActivity, scheduled_activity.id)
2816 |> assign(:user, user)
2817 |> delete("/api/v1/scheduled_statuses/#{scheduled_activity.id}")
2819 assert %{"error" => "Record not found"} = json_response(res_conn, 404)
2823 test "Repeated posts that are replies incorrectly have in_reply_to_id null", %{conn: conn} do
2824 user1 = insert(:user)
2825 user2 = insert(:user)
2826 user3 = insert(:user)
2828 {:ok, replied_to} = TwitterAPI.create_status(user1, %{"status" => "cofe"})
2830 # Reply to status from another user
2833 |> assign(:user, user2)
2834 |> post("/api/v1/statuses", %{"status" => "xD", "in_reply_to_id" => replied_to.id})
2836 assert %{"content" => "xD", "id" => id} = json_response(conn1, 200)
2838 activity = Activity.get_by_id_with_object(id)
2840 assert Object.normalize(activity).data["inReplyTo"] == Object.normalize(replied_to).data["id"]
2841 assert Activity.get_in_reply_to_activity(activity).id == replied_to.id
2843 # Reblog from the third user
2846 |> assign(:user, user3)
2847 |> post("/api/v1/statuses/#{activity.id}/reblog")
2849 assert %{"reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 1}} =
2850 json_response(conn2, 200)
2852 assert to_string(activity.id) == id
2854 # Getting third user status
2857 |> assign(:user, user3)
2858 |> get("api/v1/timelines/home")
2860 [reblogged_activity] = json_response(conn3, 200)
2862 assert reblogged_activity["reblog"]["in_reply_to_id"] == replied_to.id
2864 replied_to_user = User.get_by_ap_id(replied_to.data["actor"])
2865 assert reblogged_activity["reblog"]["in_reply_to_account_id"] == replied_to_user.id