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 default scope", %{conn: conn} do
2218 user = insert(:user)
2222 |> assign(:user, user)
2223 |> patch("/api/v1/accounts/update_credentials", %{default_scope: "cofe"})
2225 assert user = json_response(conn, 200)
2226 assert user["source"]["privacy"] == "cofe"
2229 test "updates the user's hide_followers status", %{conn: conn} do
2230 user = insert(:user)
2234 |> assign(:user, user)
2235 |> patch("/api/v1/accounts/update_credentials", %{hide_followers: "true"})
2237 assert user = json_response(conn, 200)
2238 assert user["pleroma"]["hide_followers"] == true
2241 test "updates the user's hide_follows status", %{conn: conn} do
2242 user = insert(:user)
2246 |> assign(:user, user)
2247 |> patch("/api/v1/accounts/update_credentials", %{hide_follows: "true"})
2249 assert user = json_response(conn, 200)
2250 assert user["pleroma"]["hide_follows"] == true
2253 test "updates the user's hide_favorites status", %{conn: conn} do
2254 user = insert(:user)
2258 |> assign(:user, user)
2259 |> patch("/api/v1/accounts/update_credentials", %{hide_favorites: "true"})
2261 assert user = json_response(conn, 200)
2262 assert user["pleroma"]["hide_favorites"] == true
2265 test "updates the user's show_role status", %{conn: conn} do
2266 user = insert(:user)
2270 |> assign(:user, user)
2271 |> patch("/api/v1/accounts/update_credentials", %{show_role: "false"})
2273 assert user = json_response(conn, 200)
2274 assert user["source"]["pleroma"]["show_role"] == false
2277 test "updates the user's no_rich_text status", %{conn: conn} do
2278 user = insert(:user)
2282 |> assign(:user, user)
2283 |> patch("/api/v1/accounts/update_credentials", %{no_rich_text: "true"})
2285 assert user = json_response(conn, 200)
2286 assert user["source"]["pleroma"]["no_rich_text"] == true
2289 test "updates the user's name", %{conn: conn} do
2290 user = insert(:user)
2294 |> assign(:user, user)
2295 |> patch("/api/v1/accounts/update_credentials", %{"display_name" => "markorepairs"})
2297 assert user = json_response(conn, 200)
2298 assert user["display_name"] == "markorepairs"
2301 test "updates the user's avatar", %{conn: conn} do
2302 user = insert(:user)
2304 new_avatar = %Plug.Upload{
2305 content_type: "image/jpg",
2306 path: Path.absname("test/fixtures/image.jpg"),
2307 filename: "an_image.jpg"
2312 |> assign(:user, user)
2313 |> patch("/api/v1/accounts/update_credentials", %{"avatar" => new_avatar})
2315 assert user_response = json_response(conn, 200)
2316 assert user_response["avatar"] != User.avatar_url(user)
2319 test "updates the user's banner", %{conn: conn} do
2320 user = insert(:user)
2322 new_header = %Plug.Upload{
2323 content_type: "image/jpg",
2324 path: Path.absname("test/fixtures/image.jpg"),
2325 filename: "an_image.jpg"
2330 |> assign(:user, user)
2331 |> patch("/api/v1/accounts/update_credentials", %{"header" => new_header})
2333 assert user_response = json_response(conn, 200)
2334 assert user_response["header"] != User.banner_url(user)
2337 test "requires 'write' permission", %{conn: conn} do
2338 token1 = insert(:oauth_token, scopes: ["read"])
2339 token2 = insert(:oauth_token, scopes: ["write", "follow"])
2341 for token <- [token1, token2] do
2344 |> put_req_header("authorization", "Bearer #{token.token}")
2345 |> patch("/api/v1/accounts/update_credentials", %{})
2347 if token == token1 do
2348 assert %{"error" => "Insufficient permissions: write."} == json_response(conn, 403)
2350 assert json_response(conn, 200)
2356 test "get instance information", %{conn: conn} do
2357 conn = get(conn, "/api/v1/instance")
2358 assert result = json_response(conn, 200)
2360 email = Pleroma.Config.get([:instance, :email])
2361 # Note: not checking for "max_toot_chars" since it's optional
2367 "email" => from_config_email,
2369 "streaming_api" => _
2374 "registrations" => _
2377 assert email == from_config_email
2380 test "get instance stats", %{conn: conn} do
2381 user = insert(:user, %{local: true})
2383 user2 = insert(:user, %{local: true})
2384 {:ok, _user2} = User.deactivate(user2, !user2.info.deactivated)
2386 insert(:user, %{local: false, nickname: "u@peer1.com"})
2387 insert(:user, %{local: false, nickname: "u@peer2.com"})
2389 {:ok, _} = TwitterAPI.create_status(user, %{"status" => "cofe"})
2391 # Stats should count users with missing or nil `info.deactivated` value
2392 user = User.get_cached_by_id(user.id)
2393 info_change = Changeset.change(user.info, %{deactivated: nil})
2397 |> Changeset.change()
2398 |> Changeset.put_embed(:info, info_change)
2399 |> User.update_and_set_cache()
2401 Pleroma.Stats.update_stats()
2403 conn = get(conn, "/api/v1/instance")
2405 assert result = json_response(conn, 200)
2407 stats = result["stats"]
2410 assert stats["user_count"] == 1
2411 assert stats["status_count"] == 1
2412 assert stats["domain_count"] == 2
2415 test "get peers", %{conn: conn} do
2416 insert(:user, %{local: false, nickname: "u@peer1.com"})
2417 insert(:user, %{local: false, nickname: "u@peer2.com"})
2419 Pleroma.Stats.update_stats()
2421 conn = get(conn, "/api/v1/instance/peers")
2423 assert result = json_response(conn, 200)
2425 assert ["peer1.com", "peer2.com"] == Enum.sort(result)
2428 test "put settings", %{conn: conn} do
2429 user = insert(:user)
2433 |> assign(:user, user)
2434 |> put("/api/web/settings", %{"data" => %{"programming" => "socks"}})
2436 assert _result = json_response(conn, 200)
2438 user = User.get_cached_by_ap_id(user.ap_id)
2439 assert user.info.settings == %{"programming" => "socks"}
2442 describe "pinned statuses" do
2444 Pleroma.Config.put([:instance, :max_pinned_statuses], 1)
2446 user = insert(:user)
2447 {:ok, activity} = CommonAPI.post(user, %{"status" => "HI!!!"})
2449 [user: user, activity: activity]
2452 test "returns pinned statuses", %{conn: conn, user: user, activity: activity} do
2453 {:ok, _} = CommonAPI.pin(activity.id, user)
2457 |> assign(:user, user)
2458 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
2459 |> json_response(200)
2461 id_str = to_string(activity.id)
2463 assert [%{"id" => ^id_str, "pinned" => true}] = result
2466 test "pin status", %{conn: conn, user: user, activity: activity} do
2467 id_str = to_string(activity.id)
2469 assert %{"id" => ^id_str, "pinned" => true} =
2471 |> assign(:user, user)
2472 |> post("/api/v1/statuses/#{activity.id}/pin")
2473 |> json_response(200)
2475 assert [%{"id" => ^id_str, "pinned" => true}] =
2477 |> assign(:user, user)
2478 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
2479 |> json_response(200)
2482 test "unpin status", %{conn: conn, user: user, activity: activity} do
2483 {:ok, _} = CommonAPI.pin(activity.id, user)
2485 id_str = to_string(activity.id)
2486 user = refresh_record(user)
2488 assert %{"id" => ^id_str, "pinned" => false} =
2490 |> assign(:user, user)
2491 |> post("/api/v1/statuses/#{activity.id}/unpin")
2492 |> json_response(200)
2496 |> assign(:user, user)
2497 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
2498 |> json_response(200)
2501 test "max pinned statuses", %{conn: conn, user: user, activity: activity_one} do
2502 {:ok, activity_two} = CommonAPI.post(user, %{"status" => "HI!!!"})
2504 id_str_one = to_string(activity_one.id)
2506 assert %{"id" => ^id_str_one, "pinned" => true} =
2508 |> assign(:user, user)
2509 |> post("/api/v1/statuses/#{id_str_one}/pin")
2510 |> json_response(200)
2512 user = refresh_record(user)
2514 assert %{"error" => "You have already pinned the maximum number of statuses"} =
2516 |> assign(:user, user)
2517 |> post("/api/v1/statuses/#{activity_two.id}/pin")
2518 |> json_response(400)
2521 test "Status rich-media Card", %{conn: conn, user: user} do
2522 Pleroma.Config.put([:rich_media, :enabled], true)
2523 {:ok, activity} = CommonAPI.post(user, %{"status" => "http://example.com/ogp"})
2527 |> get("/api/v1/statuses/#{activity.id}/card")
2528 |> json_response(200)
2530 assert response == %{
2531 "image" => "http://ia.media-imdb.com/images/rock.jpg",
2532 "provider_name" => "www.imdb.com",
2533 "provider_url" => "http://www.imdb.com",
2534 "title" => "The Rock",
2536 "url" => "http://www.imdb.com/title/tt0117500/",
2537 "description" => nil,
2540 "image" => "http://ia.media-imdb.com/images/rock.jpg",
2541 "title" => "The Rock",
2542 "type" => "video.movie",
2543 "url" => "http://www.imdb.com/title/tt0117500/"
2548 # works with private posts
2550 CommonAPI.post(user, %{"status" => "http://example.com/ogp", "visibility" => "direct"})
2554 |> assign(:user, user)
2555 |> get("/api/v1/statuses/#{activity.id}/card")
2556 |> json_response(200)
2558 assert response_two == response
2560 Pleroma.Config.put([:rich_media, :enabled], false)
2565 user = insert(:user)
2566 for_user = insert(:user)
2569 CommonAPI.post(user, %{
2570 "status" => "heweoo?"
2574 CommonAPI.post(user, %{
2575 "status" => "heweoo!"
2580 |> assign(:user, for_user)
2581 |> post("/api/v1/statuses/#{activity1.id}/bookmark")
2583 assert json_response(response1, 200)["bookmarked"] == true
2587 |> assign(:user, for_user)
2588 |> post("/api/v1/statuses/#{activity2.id}/bookmark")
2590 assert json_response(response2, 200)["bookmarked"] == true
2594 |> assign(:user, for_user)
2595 |> get("/api/v1/bookmarks")
2597 assert [json_response(response2, 200), json_response(response1, 200)] ==
2598 json_response(bookmarks, 200)
2602 |> assign(:user, for_user)
2603 |> post("/api/v1/statuses/#{activity1.id}/unbookmark")
2605 assert json_response(response1, 200)["bookmarked"] == false
2609 |> assign(:user, for_user)
2610 |> get("/api/v1/bookmarks")
2612 assert [json_response(response2, 200)] == json_response(bookmarks, 200)
2615 describe "conversation muting" do
2617 user = insert(:user)
2618 {:ok, activity} = CommonAPI.post(user, %{"status" => "HIE"})
2620 [user: user, activity: activity]
2623 test "mute conversation", %{conn: conn, user: user, activity: activity} do
2624 id_str = to_string(activity.id)
2626 assert %{"id" => ^id_str, "muted" => true} =
2628 |> assign(:user, user)
2629 |> post("/api/v1/statuses/#{activity.id}/mute")
2630 |> json_response(200)
2633 test "unmute conversation", %{conn: conn, user: user, activity: activity} do
2634 {:ok, _} = CommonAPI.add_mute(user, activity)
2636 id_str = to_string(activity.id)
2637 user = refresh_record(user)
2639 assert %{"id" => ^id_str, "muted" => false} =
2641 |> assign(:user, user)
2642 |> post("/api/v1/statuses/#{activity.id}/unmute")
2643 |> json_response(200)
2647 test "flavours switching (Pleroma Extension)", %{conn: conn} do
2648 user = insert(:user)
2652 |> assign(:user, user)
2653 |> get("/api/v1/pleroma/flavour")
2655 assert "glitch" == json_response(get_old_flavour, 200)
2659 |> assign(:user, user)
2660 |> post("/api/v1/pleroma/flavour/vanilla")
2662 assert "vanilla" == json_response(set_flavour, 200)
2666 |> assign(:user, user)
2667 |> post("/api/v1/pleroma/flavour/vanilla")
2669 assert json_response(set_flavour, 200) == json_response(get_new_flavour, 200)
2672 describe "reports" do
2674 reporter = insert(:user)
2675 target_user = insert(:user)
2677 {:ok, activity} = CommonAPI.post(target_user, %{"status" => "foobar"})
2679 [reporter: reporter, target_user: target_user, activity: activity]
2682 test "submit a basic report", %{conn: conn, reporter: reporter, target_user: target_user} do
2683 assert %{"action_taken" => false, "id" => _} =
2685 |> assign(:user, reporter)
2686 |> post("/api/v1/reports", %{"account_id" => target_user.id})
2687 |> json_response(200)
2690 test "submit a report with statuses and comment", %{
2693 target_user: target_user,
2696 assert %{"action_taken" => false, "id" => _} =
2698 |> assign(:user, reporter)
2699 |> post("/api/v1/reports", %{
2700 "account_id" => target_user.id,
2701 "status_ids" => [activity.id],
2702 "comment" => "bad status!"
2704 |> json_response(200)
2707 test "account_id is required", %{
2712 assert %{"error" => "Valid `account_id` required"} =
2714 |> assign(:user, reporter)
2715 |> post("/api/v1/reports", %{"status_ids" => [activity.id]})
2716 |> json_response(400)
2719 test "comment must be up to the size specified in the config", %{
2722 target_user: target_user
2724 max_size = Pleroma.Config.get([:instance, :max_report_comment_size], 1000)
2725 comment = String.pad_trailing("a", max_size + 1, "a")
2727 error = %{"error" => "Comment must be up to #{max_size} characters"}
2731 |> assign(:user, reporter)
2732 |> post("/api/v1/reports", %{"account_id" => target_user.id, "comment" => comment})
2733 |> json_response(400)
2737 describe "link headers" do
2738 test "preserves parameters in link headers", %{conn: conn} do
2739 user = insert(:user)
2740 other_user = insert(:user)
2743 CommonAPI.post(other_user, %{
2744 "status" => "hi @#{user.nickname}",
2745 "visibility" => "public"
2749 CommonAPI.post(other_user, %{
2750 "status" => "hi @#{user.nickname}",
2751 "visibility" => "public"
2754 notification1 = Repo.get_by(Notification, activity_id: activity1.id)
2755 notification2 = Repo.get_by(Notification, activity_id: activity2.id)
2759 |> assign(:user, user)
2760 |> get("/api/v1/notifications", %{media_only: true})
2762 assert [link_header] = get_resp_header(conn, "link")
2763 assert link_header =~ ~r/media_only=true/
2764 assert link_header =~ ~r/min_id=#{notification2.id}/
2765 assert link_header =~ ~r/max_id=#{notification1.id}/
2769 test "accounts fetches correct account for nicknames beginning with numbers", %{conn: conn} do
2770 # Need to set an old-style integer ID to reproduce the problem
2771 # (these are no longer assigned to new accounts but were preserved
2772 # for existing accounts during the migration to flakeIDs)
2773 user_one = insert(:user, %{id: 1212})
2774 user_two = insert(:user, %{nickname: "#{user_one.id}garbage"})
2778 |> get("/api/v1/accounts/#{user_one.id}")
2782 |> get("/api/v1/accounts/#{user_two.nickname}")
2786 |> get("/api/v1/accounts/#{user_two.id}")
2788 acc_one = json_response(resp_one, 200)
2789 acc_two = json_response(resp_two, 200)
2790 acc_three = json_response(resp_three, 200)
2791 refute acc_one == acc_two
2792 assert acc_two == acc_three
2795 describe "custom emoji" do
2796 test "with tags", %{conn: conn} do
2799 |> get("/api/v1/custom_emojis")
2800 |> json_response(200)
2802 assert Map.has_key?(emoji, "shortcode")
2803 assert Map.has_key?(emoji, "static_url")
2804 assert Map.has_key?(emoji, "tags")
2805 assert is_list(emoji["tags"])
2806 assert Map.has_key?(emoji, "url")
2807 assert Map.has_key?(emoji, "visible_in_picker")
2811 describe "index/2 redirections" do
2812 setup %{conn: conn} do
2816 signing_salt: "cooldude"
2821 |> Plug.Session.call(Plug.Session.init(session_opts))
2824 test_path = "/web/statuses/test"
2825 %{conn: conn, path: test_path}
2828 test "redirects not logged-in users to the login page", %{conn: conn, path: path} do
2829 conn = get(conn, path)
2831 assert conn.status == 302
2832 assert redirected_to(conn) == "/web/login"
2835 test "does not redirect logged in users to the login page", %{conn: conn, path: path} do
2836 token = insert(:oauth_token)
2840 |> assign(:user, token.user)
2841 |> put_session(:oauth_token, token.token)
2844 assert conn.status == 200
2847 test "saves referer path to session", %{conn: conn, path: path} do
2848 conn = get(conn, path)
2849 return_to = Plug.Conn.get_session(conn, :return_to)
2851 assert return_to == path
2854 test "redirects to the saved path after log in", %{conn: conn, path: path} do
2855 app = insert(:oauth_app, client_name: "Mastodon-Local", redirect_uris: ".")
2856 auth = insert(:oauth_authorization, app: app)
2860 |> put_session(:return_to, path)
2861 |> get("/web/login", %{code: auth.token})
2863 assert conn.status == 302
2864 assert redirected_to(conn) == path
2867 test "redirects to the getting-started page when referer is not present", %{conn: conn} do
2868 app = insert(:oauth_app, client_name: "Mastodon-Local", redirect_uris: ".")
2869 auth = insert(:oauth_authorization, app: app)
2871 conn = get(conn, "/web/login", %{code: auth.token})
2873 assert conn.status == 302
2874 assert redirected_to(conn) == "/web/getting-started"
2878 describe "scheduled activities" do
2879 test "creates a scheduled activity", %{conn: conn} do
2880 user = insert(:user)
2881 scheduled_at = NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond)
2885 |> assign(:user, user)
2886 |> post("/api/v1/statuses", %{
2887 "status" => "scheduled",
2888 "scheduled_at" => scheduled_at
2891 assert %{"scheduled_at" => expected_scheduled_at} = json_response(conn, 200)
2892 assert expected_scheduled_at == Pleroma.Web.CommonAPI.Utils.to_masto_date(scheduled_at)
2893 assert [] == Repo.all(Activity)
2896 test "creates a scheduled activity with a media attachment", %{conn: conn} do
2897 user = insert(:user)
2898 scheduled_at = NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond)
2900 file = %Plug.Upload{
2901 content_type: "image/jpg",
2902 path: Path.absname("test/fixtures/image.jpg"),
2903 filename: "an_image.jpg"
2906 {:ok, upload} = ActivityPub.upload(file, actor: user.ap_id)
2910 |> assign(:user, user)
2911 |> post("/api/v1/statuses", %{
2912 "media_ids" => [to_string(upload.id)],
2913 "status" => "scheduled",
2914 "scheduled_at" => scheduled_at
2917 assert %{"media_attachments" => [media_attachment]} = json_response(conn, 200)
2918 assert %{"type" => "image"} = media_attachment
2921 test "skips the scheduling and creates the activity if scheduled_at is earlier than 5 minutes from now",
2923 user = insert(:user)
2926 NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(5) - 1, :millisecond)
2930 |> assign(:user, user)
2931 |> post("/api/v1/statuses", %{
2932 "status" => "not scheduled",
2933 "scheduled_at" => scheduled_at
2936 assert %{"content" => "not scheduled"} = json_response(conn, 200)
2937 assert [] == Repo.all(ScheduledActivity)
2940 test "returns error when daily user limit is exceeded", %{conn: conn} do
2941 user = insert(:user)
2944 NaiveDateTime.utc_now()
2945 |> NaiveDateTime.add(:timer.minutes(6), :millisecond)
2946 |> NaiveDateTime.to_iso8601()
2948 attrs = %{params: %{}, scheduled_at: today}
2949 {:ok, _} = ScheduledActivity.create(user, attrs)
2950 {:ok, _} = ScheduledActivity.create(user, attrs)
2954 |> assign(:user, user)
2955 |> post("/api/v1/statuses", %{"status" => "scheduled", "scheduled_at" => today})
2957 assert %{"error" => "daily limit exceeded"} == json_response(conn, 422)
2960 test "returns error when total user limit is exceeded", %{conn: conn} do
2961 user = insert(:user)
2964 NaiveDateTime.utc_now()
2965 |> NaiveDateTime.add(:timer.minutes(6), :millisecond)
2966 |> NaiveDateTime.to_iso8601()
2969 NaiveDateTime.utc_now()
2970 |> NaiveDateTime.add(:timer.hours(36), :millisecond)
2971 |> NaiveDateTime.to_iso8601()
2973 attrs = %{params: %{}, scheduled_at: today}
2974 {:ok, _} = ScheduledActivity.create(user, attrs)
2975 {:ok, _} = ScheduledActivity.create(user, attrs)
2976 {:ok, _} = ScheduledActivity.create(user, %{params: %{}, scheduled_at: tomorrow})
2980 |> assign(:user, user)
2981 |> post("/api/v1/statuses", %{"status" => "scheduled", "scheduled_at" => tomorrow})
2983 assert %{"error" => "total limit exceeded"} == json_response(conn, 422)
2986 test "shows scheduled activities", %{conn: conn} do
2987 user = insert(:user)
2988 scheduled_activity_id1 = insert(:scheduled_activity, user: user).id |> to_string()
2989 scheduled_activity_id2 = insert(:scheduled_activity, user: user).id |> to_string()
2990 scheduled_activity_id3 = insert(:scheduled_activity, user: user).id |> to_string()
2991 scheduled_activity_id4 = insert(:scheduled_activity, user: user).id |> to_string()
2995 |> assign(:user, user)
3000 |> get("/api/v1/scheduled_statuses?limit=2&min_id=#{scheduled_activity_id1}")
3002 result = json_response(conn_res, 200)
3003 assert [%{"id" => ^scheduled_activity_id3}, %{"id" => ^scheduled_activity_id2}] = result
3008 |> get("/api/v1/scheduled_statuses?limit=2&since_id=#{scheduled_activity_id1}")
3010 result = json_response(conn_res, 200)
3011 assert [%{"id" => ^scheduled_activity_id4}, %{"id" => ^scheduled_activity_id3}] = result
3016 |> get("/api/v1/scheduled_statuses?limit=2&max_id=#{scheduled_activity_id4}")
3018 result = json_response(conn_res, 200)
3019 assert [%{"id" => ^scheduled_activity_id3}, %{"id" => ^scheduled_activity_id2}] = result
3022 test "shows a scheduled activity", %{conn: conn} do
3023 user = insert(:user)
3024 scheduled_activity = insert(:scheduled_activity, user: user)
3028 |> assign(:user, user)
3029 |> get("/api/v1/scheduled_statuses/#{scheduled_activity.id}")
3031 assert %{"id" => scheduled_activity_id} = json_response(res_conn, 200)
3032 assert scheduled_activity_id == scheduled_activity.id |> to_string()
3036 |> assign(:user, user)
3037 |> get("/api/v1/scheduled_statuses/404")
3039 assert %{"error" => "Record not found"} = json_response(res_conn, 404)
3042 test "updates a scheduled activity", %{conn: conn} do
3043 user = insert(:user)
3044 scheduled_activity = insert(:scheduled_activity, user: user)
3047 NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond)
3051 |> assign(:user, user)
3052 |> put("/api/v1/scheduled_statuses/#{scheduled_activity.id}", %{
3053 scheduled_at: new_scheduled_at
3056 assert %{"scheduled_at" => expected_scheduled_at} = json_response(res_conn, 200)
3057 assert expected_scheduled_at == Pleroma.Web.CommonAPI.Utils.to_masto_date(new_scheduled_at)
3061 |> assign(:user, user)
3062 |> put("/api/v1/scheduled_statuses/404", %{scheduled_at: new_scheduled_at})
3064 assert %{"error" => "Record not found"} = json_response(res_conn, 404)
3067 test "deletes a scheduled activity", %{conn: conn} do
3068 user = insert(:user)
3069 scheduled_activity = insert(:scheduled_activity, user: user)
3073 |> assign(:user, user)
3074 |> delete("/api/v1/scheduled_statuses/#{scheduled_activity.id}")
3076 assert %{} = json_response(res_conn, 200)
3077 assert nil == Repo.get(ScheduledActivity, scheduled_activity.id)
3081 |> assign(:user, user)
3082 |> delete("/api/v1/scheduled_statuses/#{scheduled_activity.id}")
3084 assert %{"error" => "Record not found"} = json_response(res_conn, 404)
3088 test "Repeated posts that are replies incorrectly have in_reply_to_id null", %{conn: conn} do
3089 user1 = insert(:user)
3090 user2 = insert(:user)
3091 user3 = insert(:user)
3093 {:ok, replied_to} = TwitterAPI.create_status(user1, %{"status" => "cofe"})
3095 # Reply to status from another user
3098 |> assign(:user, user2)
3099 |> post("/api/v1/statuses", %{"status" => "xD", "in_reply_to_id" => replied_to.id})
3101 assert %{"content" => "xD", "id" => id} = json_response(conn1, 200)
3103 activity = Activity.get_by_id_with_object(id)
3105 assert Object.normalize(activity).data["inReplyTo"] == Object.normalize(replied_to).data["id"]
3106 assert Activity.get_in_reply_to_activity(activity).id == replied_to.id
3108 # Reblog from the third user
3111 |> assign(:user, user3)
3112 |> post("/api/v1/statuses/#{activity.id}/reblog")
3114 assert %{"reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 1}} =
3115 json_response(conn2, 200)
3117 assert to_string(activity.id) == id
3119 # Getting third user status
3122 |> assign(:user, user3)
3123 |> get("api/v1/timelines/home")
3125 [reblogged_activity] = json_response(conn3, 200)
3127 assert reblogged_activity["reblog"]["in_reply_to_id"] == replied_to.id
3129 replied_to_user = User.get_by_ap_id(replied_to.data["actor"])
3130 assert reblogged_activity["reblog"]["in_reply_to_account_id"] == replied_to_user.id