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, _bookmark} = Pleroma.Bookmark.create(user2.id, activity.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 "getting favorites timeline of specified user" do
1993 [current_user, user] = insert_pair(:user, %{info: %{hide_favorites: false}})
1994 [current_user: current_user, user: user]
1997 test "returns list of statuses favorited by specified user", %{
1999 current_user: current_user,
2002 [activity | _] = insert_pair(:note_activity)
2003 CommonAPI.favorite(activity.id, user)
2007 |> assign(:user, current_user)
2008 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2009 |> json_response(:ok)
2013 assert length(response) == 1
2014 assert like["id"] == activity.id
2017 test "returns favorites for specified user_id when user is not logged in", %{
2021 activity = insert(:note_activity)
2022 CommonAPI.favorite(activity.id, user)
2026 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2027 |> json_response(:ok)
2029 assert length(response) == 1
2032 test "returns favorited DM only when user is logged in and he is one of recipients", %{
2034 current_user: current_user,
2038 CommonAPI.post(current_user, %{
2039 "status" => "Hi @#{user.nickname}!",
2040 "visibility" => "direct"
2043 CommonAPI.favorite(direct.id, user)
2047 |> assign(:user, current_user)
2048 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2049 |> json_response(:ok)
2051 assert length(response) == 1
2053 anonymous_response =
2055 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2056 |> json_response(:ok)
2058 assert length(anonymous_response) == 0
2061 test "does not return others' favorited DM when user is not one of recipients", %{
2063 current_user: current_user,
2066 user_two = insert(:user)
2069 CommonAPI.post(user_two, %{
2070 "status" => "Hi @#{user.nickname}!",
2071 "visibility" => "direct"
2074 CommonAPI.favorite(direct.id, user)
2078 |> assign(:user, current_user)
2079 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2080 |> json_response(:ok)
2082 assert length(response) == 0
2085 test "paginates favorites using since_id and max_id", %{
2087 current_user: current_user,
2090 activities = insert_list(10, :note_activity)
2092 Enum.each(activities, fn activity ->
2093 CommonAPI.favorite(activity.id, user)
2096 third_activity = Enum.at(activities, 2)
2097 seventh_activity = Enum.at(activities, 6)
2101 |> assign(:user, current_user)
2102 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites", %{
2103 since_id: third_activity.id,
2104 max_id: seventh_activity.id
2106 |> json_response(:ok)
2108 assert length(response) == 3
2109 refute third_activity in response
2110 refute seventh_activity in response
2113 test "limits favorites using limit parameter", %{
2115 current_user: current_user,
2119 |> insert_list(:note_activity)
2120 |> Enum.each(fn activity ->
2121 CommonAPI.favorite(activity.id, user)
2126 |> assign(:user, current_user)
2127 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites", %{limit: "3"})
2128 |> json_response(:ok)
2130 assert length(response) == 3
2133 test "returns empty response when user does not have any favorited statuses", %{
2135 current_user: current_user,
2140 |> assign(:user, current_user)
2141 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2142 |> json_response(:ok)
2144 assert Enum.empty?(response)
2147 test "returns 404 error when specified user is not exist", %{conn: conn} do
2148 conn = get(conn, "/api/v1/pleroma/accounts/test/favourites")
2150 assert json_response(conn, 404) == %{"error" => "Record not found"}
2153 test "returns 403 error when user has hidden own favorites", %{
2155 current_user: current_user
2157 user = insert(:user, %{info: %{hide_favorites: true}})
2158 activity = insert(:note_activity)
2159 CommonAPI.favorite(activity.id, user)
2163 |> assign(:user, current_user)
2164 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2166 assert json_response(conn, 403) == %{"error" => "Can't get favorites"}
2169 test "hides favorites for new users by default", %{conn: conn, current_user: current_user} do
2170 user = insert(:user)
2171 activity = insert(:note_activity)
2172 CommonAPI.favorite(activity.id, user)
2176 |> assign(:user, current_user)
2177 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2179 assert user.info.hide_favorites
2180 assert json_response(conn, 403) == %{"error" => "Can't get favorites"}
2184 describe "updating credentials" do
2185 test "updates the user's bio", %{conn: conn} do
2186 user = insert(:user)
2187 user2 = insert(:user)
2191 |> assign(:user, user)
2192 |> patch("/api/v1/accounts/update_credentials", %{
2193 "note" => "I drink #cofe with @#{user2.nickname}"
2196 assert user = json_response(conn, 200)
2198 assert user["note"] ==
2199 ~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=") <>
2201 ~s(" class="u-url mention" href=") <>
2202 user2.ap_id <> ~s(">@<span>) <> user2.nickname <> ~s(</span></a></span>)
2205 test "updates the user's locking status", %{conn: conn} do
2206 user = insert(:user)
2210 |> assign(:user, user)
2211 |> patch("/api/v1/accounts/update_credentials", %{locked: "true"})
2213 assert user = json_response(conn, 200)
2214 assert user["locked"] == true
2217 test "updates the user's hide_followers status", %{conn: conn} do
2218 user = insert(:user)
2222 |> assign(:user, user)
2223 |> patch("/api/v1/accounts/update_credentials", %{hide_followers: "true"})
2225 assert user = json_response(conn, 200)
2226 assert user["pleroma"]["hide_followers"] == true
2229 test "updates the user's hide_follows status", %{conn: conn} do
2230 user = insert(:user)
2234 |> assign(:user, user)
2235 |> patch("/api/v1/accounts/update_credentials", %{hide_follows: "true"})
2237 assert user = json_response(conn, 200)
2238 assert user["pleroma"]["hide_follows"] == true
2241 test "updates the user's hide_favorites status", %{conn: conn} do
2242 user = insert(:user)
2246 |> assign(:user, user)
2247 |> patch("/api/v1/accounts/update_credentials", %{hide_favorites: "true"})
2249 assert user = json_response(conn, 200)
2250 assert user["pleroma"]["hide_favorites"] == true
2253 test "updates the user's show_role status", %{conn: conn} do
2254 user = insert(:user)
2258 |> assign(:user, user)
2259 |> patch("/api/v1/accounts/update_credentials", %{show_role: "false"})
2261 assert user = json_response(conn, 200)
2262 assert user["source"]["pleroma"]["show_role"] == false
2265 test "updates the user's no_rich_text status", %{conn: conn} do
2266 user = insert(:user)
2270 |> assign(:user, user)
2271 |> patch("/api/v1/accounts/update_credentials", %{no_rich_text: "true"})
2273 assert user = json_response(conn, 200)
2274 assert user["source"]["pleroma"]["no_rich_text"] == true
2277 test "updates the user's name", %{conn: conn} do
2278 user = insert(:user)
2282 |> assign(:user, user)
2283 |> patch("/api/v1/accounts/update_credentials", %{"display_name" => "markorepairs"})
2285 assert user = json_response(conn, 200)
2286 assert user["display_name"] == "markorepairs"
2289 test "updates the user's avatar", %{conn: conn} do
2290 user = insert(:user)
2292 new_avatar = %Plug.Upload{
2293 content_type: "image/jpg",
2294 path: Path.absname("test/fixtures/image.jpg"),
2295 filename: "an_image.jpg"
2300 |> assign(:user, user)
2301 |> patch("/api/v1/accounts/update_credentials", %{"avatar" => new_avatar})
2303 assert user_response = json_response(conn, 200)
2304 assert user_response["avatar"] != User.avatar_url(user)
2307 test "updates the user's banner", %{conn: conn} do
2308 user = insert(:user)
2310 new_header = %Plug.Upload{
2311 content_type: "image/jpg",
2312 path: Path.absname("test/fixtures/image.jpg"),
2313 filename: "an_image.jpg"
2318 |> assign(:user, user)
2319 |> patch("/api/v1/accounts/update_credentials", %{"header" => new_header})
2321 assert user_response = json_response(conn, 200)
2322 assert user_response["header"] != User.banner_url(user)
2325 test "requires 'write' permission", %{conn: conn} do
2326 token1 = insert(:oauth_token, scopes: ["read"])
2327 token2 = insert(:oauth_token, scopes: ["write", "follow"])
2329 for token <- [token1, token2] do
2332 |> put_req_header("authorization", "Bearer #{token.token}")
2333 |> patch("/api/v1/accounts/update_credentials", %{})
2335 if token == token1 do
2336 assert %{"error" => "Insufficient permissions: write."} == json_response(conn, 403)
2338 assert json_response(conn, 200)
2344 test "get instance information", %{conn: conn} do
2345 conn = get(conn, "/api/v1/instance")
2346 assert result = json_response(conn, 200)
2348 email = Pleroma.Config.get([:instance, :email])
2349 # Note: not checking for "max_toot_chars" since it's optional
2355 "email" => from_config_email,
2357 "streaming_api" => _
2362 "registrations" => _
2365 assert email == from_config_email
2368 test "get instance stats", %{conn: conn} do
2369 user = insert(:user, %{local: true})
2371 user2 = insert(:user, %{local: true})
2372 {:ok, _user2} = User.deactivate(user2, !user2.info.deactivated)
2374 insert(:user, %{local: false, nickname: "u@peer1.com"})
2375 insert(:user, %{local: false, nickname: "u@peer2.com"})
2377 {:ok, _} = TwitterAPI.create_status(user, %{"status" => "cofe"})
2379 # Stats should count users with missing or nil `info.deactivated` value
2380 user = User.get_cached_by_id(user.id)
2381 info_change = Changeset.change(user.info, %{deactivated: nil})
2385 |> Changeset.change()
2386 |> Changeset.put_embed(:info, info_change)
2387 |> User.update_and_set_cache()
2389 Pleroma.Stats.update_stats()
2391 conn = get(conn, "/api/v1/instance")
2393 assert result = json_response(conn, 200)
2395 stats = result["stats"]
2398 assert stats["user_count"] == 1
2399 assert stats["status_count"] == 1
2400 assert stats["domain_count"] == 2
2403 test "get peers", %{conn: conn} do
2404 insert(:user, %{local: false, nickname: "u@peer1.com"})
2405 insert(:user, %{local: false, nickname: "u@peer2.com"})
2407 Pleroma.Stats.update_stats()
2409 conn = get(conn, "/api/v1/instance/peers")
2411 assert result = json_response(conn, 200)
2413 assert ["peer1.com", "peer2.com"] == Enum.sort(result)
2416 test "put settings", %{conn: conn} do
2417 user = insert(:user)
2421 |> assign(:user, user)
2422 |> put("/api/web/settings", %{"data" => %{"programming" => "socks"}})
2424 assert _result = json_response(conn, 200)
2426 user = User.get_cached_by_ap_id(user.ap_id)
2427 assert user.info.settings == %{"programming" => "socks"}
2430 describe "pinned statuses" do
2432 Pleroma.Config.put([:instance, :max_pinned_statuses], 1)
2434 user = insert(:user)
2435 {:ok, activity} = CommonAPI.post(user, %{"status" => "HI!!!"})
2437 [user: user, activity: activity]
2440 test "returns pinned statuses", %{conn: conn, user: user, activity: activity} do
2441 {:ok, _} = CommonAPI.pin(activity.id, user)
2445 |> assign(:user, user)
2446 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
2447 |> json_response(200)
2449 id_str = to_string(activity.id)
2451 assert [%{"id" => ^id_str, "pinned" => true}] = result
2454 test "pin status", %{conn: conn, user: user, activity: activity} do
2455 id_str = to_string(activity.id)
2457 assert %{"id" => ^id_str, "pinned" => true} =
2459 |> assign(:user, user)
2460 |> post("/api/v1/statuses/#{activity.id}/pin")
2461 |> json_response(200)
2463 assert [%{"id" => ^id_str, "pinned" => true}] =
2465 |> assign(:user, user)
2466 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
2467 |> json_response(200)
2470 test "unpin status", %{conn: conn, user: user, activity: activity} do
2471 {:ok, _} = CommonAPI.pin(activity.id, user)
2473 id_str = to_string(activity.id)
2474 user = refresh_record(user)
2476 assert %{"id" => ^id_str, "pinned" => false} =
2478 |> assign(:user, user)
2479 |> post("/api/v1/statuses/#{activity.id}/unpin")
2480 |> json_response(200)
2484 |> assign(:user, user)
2485 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
2486 |> json_response(200)
2489 test "max pinned statuses", %{conn: conn, user: user, activity: activity_one} do
2490 {:ok, activity_two} = CommonAPI.post(user, %{"status" => "HI!!!"})
2492 id_str_one = to_string(activity_one.id)
2494 assert %{"id" => ^id_str_one, "pinned" => true} =
2496 |> assign(:user, user)
2497 |> post("/api/v1/statuses/#{id_str_one}/pin")
2498 |> json_response(200)
2500 user = refresh_record(user)
2502 assert %{"error" => "You have already pinned the maximum number of statuses"} =
2504 |> assign(:user, user)
2505 |> post("/api/v1/statuses/#{activity_two.id}/pin")
2506 |> json_response(400)
2509 test "Status rich-media Card", %{conn: conn, user: user} do
2510 Pleroma.Config.put([:rich_media, :enabled], true)
2511 {:ok, activity} = CommonAPI.post(user, %{"status" => "http://example.com/ogp"})
2515 |> get("/api/v1/statuses/#{activity.id}/card")
2516 |> json_response(200)
2518 assert response == %{
2519 "image" => "http://ia.media-imdb.com/images/rock.jpg",
2520 "provider_name" => "www.imdb.com",
2521 "provider_url" => "http://www.imdb.com",
2522 "title" => "The Rock",
2524 "url" => "http://www.imdb.com/title/tt0117500/",
2525 "description" => nil,
2528 "image" => "http://ia.media-imdb.com/images/rock.jpg",
2529 "title" => "The Rock",
2530 "type" => "video.movie",
2531 "url" => "http://www.imdb.com/title/tt0117500/"
2536 # works with private posts
2538 CommonAPI.post(user, %{"status" => "http://example.com/ogp", "visibility" => "direct"})
2542 |> assign(:user, user)
2543 |> get("/api/v1/statuses/#{activity.id}/card")
2544 |> json_response(200)
2546 assert response_two == response
2548 Pleroma.Config.put([:rich_media, :enabled], false)
2553 user = insert(:user)
2554 for_user = insert(:user)
2557 CommonAPI.post(user, %{
2558 "status" => "heweoo?"
2562 CommonAPI.post(user, %{
2563 "status" => "heweoo!"
2568 |> assign(:user, for_user)
2569 |> post("/api/v1/statuses/#{activity1.id}/bookmark")
2571 assert json_response(response1, 200)["bookmarked"] == true
2575 |> assign(:user, for_user)
2576 |> post("/api/v1/statuses/#{activity2.id}/bookmark")
2578 assert json_response(response2, 200)["bookmarked"] == true
2582 |> assign(:user, for_user)
2583 |> get("/api/v1/bookmarks")
2585 assert [json_response(response2, 200), json_response(response1, 200)] ==
2586 json_response(bookmarks, 200)
2590 |> assign(:user, for_user)
2591 |> post("/api/v1/statuses/#{activity1.id}/unbookmark")
2593 assert json_response(response1, 200)["bookmarked"] == false
2597 |> assign(:user, for_user)
2598 |> get("/api/v1/bookmarks")
2600 assert [json_response(response2, 200)] == json_response(bookmarks, 200)
2603 describe "conversation muting" do
2605 user = insert(:user)
2606 {:ok, activity} = CommonAPI.post(user, %{"status" => "HIE"})
2608 [user: user, activity: activity]
2611 test "mute conversation", %{conn: conn, user: user, activity: activity} do
2612 id_str = to_string(activity.id)
2614 assert %{"id" => ^id_str, "muted" => true} =
2616 |> assign(:user, user)
2617 |> post("/api/v1/statuses/#{activity.id}/mute")
2618 |> json_response(200)
2621 test "unmute conversation", %{conn: conn, user: user, activity: activity} do
2622 {:ok, _} = CommonAPI.add_mute(user, activity)
2624 id_str = to_string(activity.id)
2625 user = refresh_record(user)
2627 assert %{"id" => ^id_str, "muted" => false} =
2629 |> assign(:user, user)
2630 |> post("/api/v1/statuses/#{activity.id}/unmute")
2631 |> json_response(200)
2635 test "flavours switching (Pleroma Extension)", %{conn: conn} do
2636 user = insert(:user)
2640 |> assign(:user, user)
2641 |> get("/api/v1/pleroma/flavour")
2643 assert "glitch" == json_response(get_old_flavour, 200)
2647 |> assign(:user, user)
2648 |> post("/api/v1/pleroma/flavour/vanilla")
2650 assert "vanilla" == json_response(set_flavour, 200)
2654 |> assign(:user, user)
2655 |> post("/api/v1/pleroma/flavour/vanilla")
2657 assert json_response(set_flavour, 200) == json_response(get_new_flavour, 200)
2660 describe "reports" do
2662 reporter = insert(:user)
2663 target_user = insert(:user)
2665 {:ok, activity} = CommonAPI.post(target_user, %{"status" => "foobar"})
2667 [reporter: reporter, target_user: target_user, activity: activity]
2670 test "submit a basic report", %{conn: conn, reporter: reporter, target_user: target_user} do
2671 assert %{"action_taken" => false, "id" => _} =
2673 |> assign(:user, reporter)
2674 |> post("/api/v1/reports", %{"account_id" => target_user.id})
2675 |> json_response(200)
2678 test "submit a report with statuses and comment", %{
2681 target_user: target_user,
2684 assert %{"action_taken" => false, "id" => _} =
2686 |> assign(:user, reporter)
2687 |> post("/api/v1/reports", %{
2688 "account_id" => target_user.id,
2689 "status_ids" => [activity.id],
2690 "comment" => "bad status!"
2692 |> json_response(200)
2695 test "account_id is required", %{
2700 assert %{"error" => "Valid `account_id` required"} =
2702 |> assign(:user, reporter)
2703 |> post("/api/v1/reports", %{"status_ids" => [activity.id]})
2704 |> json_response(400)
2707 test "comment must be up to the size specified in the config", %{
2710 target_user: target_user
2712 max_size = Pleroma.Config.get([:instance, :max_report_comment_size], 1000)
2713 comment = String.pad_trailing("a", max_size + 1, "a")
2715 error = %{"error" => "Comment must be up to #{max_size} characters"}
2719 |> assign(:user, reporter)
2720 |> post("/api/v1/reports", %{"account_id" => target_user.id, "comment" => comment})
2721 |> json_response(400)
2725 describe "link headers" do
2726 test "preserves parameters in link headers", %{conn: conn} do
2727 user = insert(:user)
2728 other_user = insert(:user)
2731 CommonAPI.post(other_user, %{
2732 "status" => "hi @#{user.nickname}",
2733 "visibility" => "public"
2737 CommonAPI.post(other_user, %{
2738 "status" => "hi @#{user.nickname}",
2739 "visibility" => "public"
2742 notification1 = Repo.get_by(Notification, activity_id: activity1.id)
2743 notification2 = Repo.get_by(Notification, activity_id: activity2.id)
2747 |> assign(:user, user)
2748 |> get("/api/v1/notifications", %{media_only: true})
2750 assert [link_header] = get_resp_header(conn, "link")
2751 assert link_header =~ ~r/media_only=true/
2752 assert link_header =~ ~r/min_id=#{notification2.id}/
2753 assert link_header =~ ~r/max_id=#{notification1.id}/
2757 test "accounts fetches correct account for nicknames beginning with numbers", %{conn: conn} do
2758 # Need to set an old-style integer ID to reproduce the problem
2759 # (these are no longer assigned to new accounts but were preserved
2760 # for existing accounts during the migration to flakeIDs)
2761 user_one = insert(:user, %{id: 1212})
2762 user_two = insert(:user, %{nickname: "#{user_one.id}garbage"})
2766 |> get("/api/v1/accounts/#{user_one.id}")
2770 |> get("/api/v1/accounts/#{user_two.nickname}")
2774 |> get("/api/v1/accounts/#{user_two.id}")
2776 acc_one = json_response(resp_one, 200)
2777 acc_two = json_response(resp_two, 200)
2778 acc_three = json_response(resp_three, 200)
2779 refute acc_one == acc_two
2780 assert acc_two == acc_three
2783 describe "custom emoji" do
2784 test "with tags", %{conn: conn} do
2787 |> get("/api/v1/custom_emojis")
2788 |> json_response(200)
2790 assert Map.has_key?(emoji, "shortcode")
2791 assert Map.has_key?(emoji, "static_url")
2792 assert Map.has_key?(emoji, "tags")
2793 assert is_list(emoji["tags"])
2794 assert Map.has_key?(emoji, "url")
2795 assert Map.has_key?(emoji, "visible_in_picker")
2799 describe "index/2 redirections" do
2800 setup %{conn: conn} do
2804 signing_salt: "cooldude"
2809 |> Plug.Session.call(Plug.Session.init(session_opts))
2812 test_path = "/web/statuses/test"
2813 %{conn: conn, path: test_path}
2816 test "redirects not logged-in users to the login page", %{conn: conn, path: path} do
2817 conn = get(conn, path)
2819 assert conn.status == 302
2820 assert redirected_to(conn) == "/web/login"
2823 test "does not redirect logged in users to the login page", %{conn: conn, path: path} do
2824 token = insert(:oauth_token)
2828 |> assign(:user, token.user)
2829 |> put_session(:oauth_token, token.token)
2832 assert conn.status == 200
2835 test "saves referer path to session", %{conn: conn, path: path} do
2836 conn = get(conn, path)
2837 return_to = Plug.Conn.get_session(conn, :return_to)
2839 assert return_to == path
2842 test "redirects to the saved path after log in", %{conn: conn, path: path} do
2843 app = insert(:oauth_app, client_name: "Mastodon-Local", redirect_uris: ".")
2844 auth = insert(:oauth_authorization, app: app)
2848 |> put_session(:return_to, path)
2849 |> get("/web/login", %{code: auth.token})
2851 assert conn.status == 302
2852 assert redirected_to(conn) == path
2855 test "redirects to the getting-started page when referer is not present", %{conn: conn} do
2856 app = insert(:oauth_app, client_name: "Mastodon-Local", redirect_uris: ".")
2857 auth = insert(:oauth_authorization, app: app)
2859 conn = get(conn, "/web/login", %{code: auth.token})
2861 assert conn.status == 302
2862 assert redirected_to(conn) == "/web/getting-started"
2866 describe "scheduled activities" do
2867 test "creates a scheduled activity", %{conn: conn} do
2868 user = insert(:user)
2869 scheduled_at = NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond)
2873 |> assign(:user, user)
2874 |> post("/api/v1/statuses", %{
2875 "status" => "scheduled",
2876 "scheduled_at" => scheduled_at
2879 assert %{"scheduled_at" => expected_scheduled_at} = json_response(conn, 200)
2880 assert expected_scheduled_at == Pleroma.Web.CommonAPI.Utils.to_masto_date(scheduled_at)
2881 assert [] == Repo.all(Activity)
2884 test "creates a scheduled activity with a media attachment", %{conn: conn} do
2885 user = insert(:user)
2886 scheduled_at = NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond)
2888 file = %Plug.Upload{
2889 content_type: "image/jpg",
2890 path: Path.absname("test/fixtures/image.jpg"),
2891 filename: "an_image.jpg"
2894 {:ok, upload} = ActivityPub.upload(file, actor: user.ap_id)
2898 |> assign(:user, user)
2899 |> post("/api/v1/statuses", %{
2900 "media_ids" => [to_string(upload.id)],
2901 "status" => "scheduled",
2902 "scheduled_at" => scheduled_at
2905 assert %{"media_attachments" => [media_attachment]} = json_response(conn, 200)
2906 assert %{"type" => "image"} = media_attachment
2909 test "skips the scheduling and creates the activity if scheduled_at is earlier than 5 minutes from now",
2911 user = insert(:user)
2914 NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(5) - 1, :millisecond)
2918 |> assign(:user, user)
2919 |> post("/api/v1/statuses", %{
2920 "status" => "not scheduled",
2921 "scheduled_at" => scheduled_at
2924 assert %{"content" => "not scheduled"} = json_response(conn, 200)
2925 assert [] == Repo.all(ScheduledActivity)
2928 test "returns error when daily user limit is exceeded", %{conn: conn} do
2929 user = insert(:user)
2932 NaiveDateTime.utc_now()
2933 |> NaiveDateTime.add(:timer.minutes(6), :millisecond)
2934 |> NaiveDateTime.to_iso8601()
2936 attrs = %{params: %{}, scheduled_at: today}
2937 {:ok, _} = ScheduledActivity.create(user, attrs)
2938 {:ok, _} = ScheduledActivity.create(user, attrs)
2942 |> assign(:user, user)
2943 |> post("/api/v1/statuses", %{"status" => "scheduled", "scheduled_at" => today})
2945 assert %{"error" => "daily limit exceeded"} == json_response(conn, 422)
2948 test "returns error when total user limit is exceeded", %{conn: conn} do
2949 user = insert(:user)
2952 NaiveDateTime.utc_now()
2953 |> NaiveDateTime.add(:timer.minutes(6), :millisecond)
2954 |> NaiveDateTime.to_iso8601()
2957 NaiveDateTime.utc_now()
2958 |> NaiveDateTime.add(:timer.hours(36), :millisecond)
2959 |> NaiveDateTime.to_iso8601()
2961 attrs = %{params: %{}, scheduled_at: today}
2962 {:ok, _} = ScheduledActivity.create(user, attrs)
2963 {:ok, _} = ScheduledActivity.create(user, attrs)
2964 {:ok, _} = ScheduledActivity.create(user, %{params: %{}, scheduled_at: tomorrow})
2968 |> assign(:user, user)
2969 |> post("/api/v1/statuses", %{"status" => "scheduled", "scheduled_at" => tomorrow})
2971 assert %{"error" => "total limit exceeded"} == json_response(conn, 422)
2974 test "shows scheduled activities", %{conn: conn} do
2975 user = insert(:user)
2976 scheduled_activity_id1 = insert(:scheduled_activity, user: user).id |> to_string()
2977 scheduled_activity_id2 = insert(:scheduled_activity, user: user).id |> to_string()
2978 scheduled_activity_id3 = insert(:scheduled_activity, user: user).id |> to_string()
2979 scheduled_activity_id4 = insert(:scheduled_activity, user: user).id |> to_string()
2983 |> assign(:user, user)
2988 |> get("/api/v1/scheduled_statuses?limit=2&min_id=#{scheduled_activity_id1}")
2990 result = json_response(conn_res, 200)
2991 assert [%{"id" => ^scheduled_activity_id3}, %{"id" => ^scheduled_activity_id2}] = result
2996 |> get("/api/v1/scheduled_statuses?limit=2&since_id=#{scheduled_activity_id1}")
2998 result = json_response(conn_res, 200)
2999 assert [%{"id" => ^scheduled_activity_id4}, %{"id" => ^scheduled_activity_id3}] = result
3004 |> get("/api/v1/scheduled_statuses?limit=2&max_id=#{scheduled_activity_id4}")
3006 result = json_response(conn_res, 200)
3007 assert [%{"id" => ^scheduled_activity_id3}, %{"id" => ^scheduled_activity_id2}] = result
3010 test "shows a scheduled activity", %{conn: conn} do
3011 user = insert(:user)
3012 scheduled_activity = insert(:scheduled_activity, user: user)
3016 |> assign(:user, user)
3017 |> get("/api/v1/scheduled_statuses/#{scheduled_activity.id}")
3019 assert %{"id" => scheduled_activity_id} = json_response(res_conn, 200)
3020 assert scheduled_activity_id == scheduled_activity.id |> to_string()
3024 |> assign(:user, user)
3025 |> get("/api/v1/scheduled_statuses/404")
3027 assert %{"error" => "Record not found"} = json_response(res_conn, 404)
3030 test "updates a scheduled activity", %{conn: conn} do
3031 user = insert(:user)
3032 scheduled_activity = insert(:scheduled_activity, user: user)
3035 NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond)
3039 |> assign(:user, user)
3040 |> put("/api/v1/scheduled_statuses/#{scheduled_activity.id}", %{
3041 scheduled_at: new_scheduled_at
3044 assert %{"scheduled_at" => expected_scheduled_at} = json_response(res_conn, 200)
3045 assert expected_scheduled_at == Pleroma.Web.CommonAPI.Utils.to_masto_date(new_scheduled_at)
3049 |> assign(:user, user)
3050 |> put("/api/v1/scheduled_statuses/404", %{scheduled_at: new_scheduled_at})
3052 assert %{"error" => "Record not found"} = json_response(res_conn, 404)
3055 test "deletes a scheduled activity", %{conn: conn} do
3056 user = insert(:user)
3057 scheduled_activity = insert(:scheduled_activity, user: user)
3061 |> assign(:user, user)
3062 |> delete("/api/v1/scheduled_statuses/#{scheduled_activity.id}")
3064 assert %{} = json_response(res_conn, 200)
3065 assert nil == Repo.get(ScheduledActivity, scheduled_activity.id)
3069 |> assign(:user, user)
3070 |> delete("/api/v1/scheduled_statuses/#{scheduled_activity.id}")
3072 assert %{"error" => "Record not found"} = json_response(res_conn, 404)
3076 test "Repeated posts that are replies incorrectly have in_reply_to_id null", %{conn: conn} do
3077 user1 = insert(:user)
3078 user2 = insert(:user)
3079 user3 = insert(:user)
3081 {:ok, replied_to} = TwitterAPI.create_status(user1, %{"status" => "cofe"})
3083 # Reply to status from another user
3086 |> assign(:user, user2)
3087 |> post("/api/v1/statuses", %{"status" => "xD", "in_reply_to_id" => replied_to.id})
3089 assert %{"content" => "xD", "id" => id} = json_response(conn1, 200)
3091 activity = Activity.get_by_id_with_object(id)
3093 assert Object.normalize(activity).data["inReplyTo"] == Object.normalize(replied_to).data["id"]
3094 assert Activity.get_in_reply_to_activity(activity).id == replied_to.id
3096 # Reblog from the third user
3099 |> assign(:user, user3)
3100 |> post("/api/v1/statuses/#{activity.id}/reblog")
3102 assert %{"reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 1}} =
3103 json_response(conn2, 200)
3105 assert to_string(activity.id) == id
3107 # Getting third user status
3110 |> assign(:user, user3)
3111 |> get("api/v1/timelines/home")
3113 [reblogged_activity] = json_response(conn3, 200)
3115 assert reblogged_activity["reblog"]["in_reply_to_id"] == replied_to.id
3117 replied_to_user = User.get_by_ap_id(replied_to.data["actor"])
3118 assert reblogged_activity["reblog"]["in_reply_to_account_id"] == replied_to_user.id