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 "Conversations", %{conn: conn} do
304 user_one = insert(:user)
305 user_two = insert(:user)
307 {:ok, user_two} = User.follow(user_two, user_one)
310 CommonAPI.post(user_one, %{
311 "status" => "Hi @#{user_two.nickname}!",
312 "visibility" => "direct"
315 {:ok, _follower_only} =
316 CommonAPI.post(user_one, %{
317 "status" => "Hi @#{user_two.nickname}!",
318 "visibility" => "private"
323 |> assign(:user, user_one)
324 |> get("/api/v1/conversations")
326 assert response = json_response(res_conn, 200)
331 "accounts" => res_accounts,
332 "last_status" => res_last_status,
337 assert length(res_accounts) == 2
338 assert is_binary(res_id)
339 assert unread == true
340 assert res_last_status["id"] == direct.id
342 # Apparently undocumented API endpoint
345 |> assign(:user, user_one)
346 |> post("/api/v1/conversations/#{res_id}/read")
348 assert response = json_response(res_conn, 200)
349 assert length(response["accounts"]) == 2
350 assert response["last_status"]["id"] == direct.id
351 assert response["unread"] == false
353 # (vanilla) Mastodon frontend behaviour
356 |> assign(:user, user_one)
357 |> get("/api/v1/statuses/#{res_last_status["id"]}/context")
359 assert %{"ancestors" => [], "descendants" => []} == json_response(res_conn, 200)
362 test "doesn't include DMs from blocked users", %{conn: conn} do
363 blocker = insert(:user)
364 blocked = insert(:user)
366 {:ok, blocker} = User.block(blocker, blocked)
368 {:ok, _blocked_direct} =
369 CommonAPI.post(blocked, %{
370 "status" => "Hi @#{blocker.nickname}!",
371 "visibility" => "direct"
375 CommonAPI.post(user, %{
376 "status" => "Hi @#{blocker.nickname}!",
377 "visibility" => "direct"
382 |> assign(:user, user)
383 |> get("api/v1/timelines/direct")
385 [status] = json_response(res_conn, 200)
386 assert status["id"] == direct.id
389 test "replying to a status", %{conn: conn} do
392 {:ok, replied_to} = TwitterAPI.create_status(user, %{"status" => "cofe"})
396 |> assign(:user, user)
397 |> post("/api/v1/statuses", %{"status" => "xD", "in_reply_to_id" => replied_to.id})
399 assert %{"content" => "xD", "id" => id} = json_response(conn, 200)
401 activity = Activity.get_by_id(id)
403 assert activity.data["context"] == replied_to.data["context"]
404 assert Activity.get_in_reply_to_activity(activity).id == replied_to.id
407 test "posting a status with an invalid in_reply_to_id", %{conn: conn} do
412 |> assign(:user, user)
413 |> post("/api/v1/statuses", %{"status" => "xD", "in_reply_to_id" => ""})
415 assert %{"content" => "xD", "id" => id} = json_response(conn, 200)
417 activity = Activity.get_by_id(id)
422 test "verify_credentials", %{conn: conn} do
427 |> assign(:user, user)
428 |> get("/api/v1/accounts/verify_credentials")
430 assert %{"id" => id, "source" => %{"privacy" => "public"}} = json_response(conn, 200)
431 assert id == to_string(user.id)
434 test "verify_credentials default scope unlisted", %{conn: conn} do
435 user = insert(:user, %{info: %Pleroma.User.Info{default_scope: "unlisted"}})
439 |> assign(:user, user)
440 |> get("/api/v1/accounts/verify_credentials")
442 assert %{"id" => id, "source" => %{"privacy" => "unlisted"}} = json_response(conn, 200)
443 assert id == to_string(user.id)
446 test "apps/verify_credentials", %{conn: conn} do
447 token = insert(:oauth_token)
451 |> assign(:user, token.user)
452 |> assign(:token, token)
453 |> get("/api/v1/apps/verify_credentials")
455 app = Repo.preload(token, :app).app
458 "name" => app.client_name,
459 "website" => app.website,
460 "vapid_key" => Push.vapid_config() |> Keyword.get(:public_key)
463 assert expected == json_response(conn, 200)
466 test "creates an oauth app", %{conn: conn} do
468 app_attrs = build(:oauth_app)
472 |> assign(:user, user)
473 |> post("/api/v1/apps", %{
474 client_name: app_attrs.client_name,
475 redirect_uris: app_attrs.redirect_uris
478 [app] = Repo.all(App)
481 "name" => app.client_name,
482 "website" => app.website,
483 "client_id" => app.client_id,
484 "client_secret" => app.client_secret,
485 "id" => app.id |> to_string(),
486 "redirect_uri" => app.redirect_uris,
487 "vapid_key" => Push.vapid_config() |> Keyword.get(:public_key)
490 assert expected == json_response(conn, 200)
493 test "get a status", %{conn: conn} do
494 activity = insert(:note_activity)
498 |> get("/api/v1/statuses/#{activity.id}")
500 assert %{"id" => id} = json_response(conn, 200)
501 assert id == to_string(activity.id)
504 describe "deleting a status" do
505 test "when you created it", %{conn: conn} do
506 activity = insert(:note_activity)
507 author = User.get_cached_by_ap_id(activity.data["actor"])
511 |> assign(:user, author)
512 |> delete("/api/v1/statuses/#{activity.id}")
514 assert %{} = json_response(conn, 200)
516 refute Activity.get_by_id(activity.id)
519 test "when you didn't create it", %{conn: conn} do
520 activity = insert(:note_activity)
525 |> assign(:user, user)
526 |> delete("/api/v1/statuses/#{activity.id}")
528 assert %{"error" => _} = json_response(conn, 403)
530 assert Activity.get_by_id(activity.id) == activity
533 test "when you're an admin or moderator", %{conn: conn} do
534 activity1 = insert(:note_activity)
535 activity2 = insert(:note_activity)
536 admin = insert(:user, info: %{is_admin: true})
537 moderator = insert(:user, info: %{is_moderator: true})
541 |> assign(:user, admin)
542 |> delete("/api/v1/statuses/#{activity1.id}")
544 assert %{} = json_response(res_conn, 200)
548 |> assign(:user, moderator)
549 |> delete("/api/v1/statuses/#{activity2.id}")
551 assert %{} = json_response(res_conn, 200)
553 refute Activity.get_by_id(activity1.id)
554 refute Activity.get_by_id(activity2.id)
558 describe "filters" do
559 test "creating a filter", %{conn: conn} do
562 filter = %Pleroma.Filter{
569 |> assign(:user, user)
570 |> post("/api/v1/filters", %{"phrase" => filter.phrase, context: filter.context})
572 assert response = json_response(conn, 200)
573 assert response["phrase"] == filter.phrase
574 assert response["context"] == filter.context
575 assert response["id"] != nil
576 assert response["id"] != ""
579 test "fetching a list of filters", %{conn: conn} do
582 query_one = %Pleroma.Filter{
589 query_two = %Pleroma.Filter{
596 {:ok, filter_one} = Pleroma.Filter.create(query_one)
597 {:ok, filter_two} = Pleroma.Filter.create(query_two)
601 |> assign(:user, user)
602 |> get("/api/v1/filters")
603 |> json_response(200)
609 filters: [filter_two, filter_one]
613 test "get a filter", %{conn: conn} do
616 query = %Pleroma.Filter{
623 {:ok, filter} = Pleroma.Filter.create(query)
627 |> assign(:user, user)
628 |> get("/api/v1/filters/#{filter.filter_id}")
630 assert _response = json_response(conn, 200)
633 test "update a filter", %{conn: conn} do
636 query = %Pleroma.Filter{
643 {:ok, _filter} = Pleroma.Filter.create(query)
645 new = %Pleroma.Filter{
652 |> assign(:user, user)
653 |> put("/api/v1/filters/#{query.filter_id}", %{
658 assert response = json_response(conn, 200)
659 assert response["phrase"] == new.phrase
660 assert response["context"] == new.context
663 test "delete a filter", %{conn: conn} do
666 query = %Pleroma.Filter{
673 {:ok, filter} = Pleroma.Filter.create(query)
677 |> assign(:user, user)
678 |> delete("/api/v1/filters/#{filter.filter_id}")
680 assert response = json_response(conn, 200)
681 assert response == %{}
686 test "creating a list", %{conn: conn} do
691 |> assign(:user, user)
692 |> post("/api/v1/lists", %{"title" => "cuties"})
694 assert %{"title" => title} = json_response(conn, 200)
695 assert title == "cuties"
698 test "adding users to a list", %{conn: conn} do
700 other_user = insert(:user)
701 {:ok, list} = Pleroma.List.create("name", user)
705 |> assign(:user, user)
706 |> post("/api/v1/lists/#{list.id}/accounts", %{"account_ids" => [other_user.id]})
708 assert %{} == json_response(conn, 200)
709 %Pleroma.List{following: following} = Pleroma.List.get(list.id, user)
710 assert following == [other_user.follower_address]
713 test "removing users from a list", %{conn: conn} do
715 other_user = insert(:user)
716 third_user = insert(:user)
717 {:ok, list} = Pleroma.List.create("name", user)
718 {:ok, list} = Pleroma.List.follow(list, other_user)
719 {:ok, list} = Pleroma.List.follow(list, third_user)
723 |> assign(:user, user)
724 |> delete("/api/v1/lists/#{list.id}/accounts", %{"account_ids" => [other_user.id]})
726 assert %{} == json_response(conn, 200)
727 %Pleroma.List{following: following} = Pleroma.List.get(list.id, user)
728 assert following == [third_user.follower_address]
731 test "listing users in a list", %{conn: conn} do
733 other_user = insert(:user)
734 {:ok, list} = Pleroma.List.create("name", user)
735 {:ok, list} = Pleroma.List.follow(list, other_user)
739 |> assign(:user, user)
740 |> get("/api/v1/lists/#{list.id}/accounts", %{"account_ids" => [other_user.id]})
742 assert [%{"id" => id}] = json_response(conn, 200)
743 assert id == to_string(other_user.id)
746 test "retrieving a list", %{conn: conn} do
748 {:ok, list} = Pleroma.List.create("name", user)
752 |> assign(:user, user)
753 |> get("/api/v1/lists/#{list.id}")
755 assert %{"id" => id} = json_response(conn, 200)
756 assert id == to_string(list.id)
759 test "renaming a list", %{conn: conn} do
761 {:ok, list} = Pleroma.List.create("name", user)
765 |> assign(:user, user)
766 |> put("/api/v1/lists/#{list.id}", %{"title" => "newname"})
768 assert %{"title" => name} = json_response(conn, 200)
769 assert name == "newname"
772 test "deleting a list", %{conn: conn} do
774 {:ok, list} = Pleroma.List.create("name", user)
778 |> assign(:user, user)
779 |> delete("/api/v1/lists/#{list.id}")
781 assert %{} = json_response(conn, 200)
782 assert is_nil(Repo.get(Pleroma.List, list.id))
785 test "list timeline", %{conn: conn} do
787 other_user = insert(:user)
788 {:ok, _activity_one} = TwitterAPI.create_status(user, %{"status" => "Marisa is cute."})
789 {:ok, activity_two} = TwitterAPI.create_status(other_user, %{"status" => "Marisa is cute."})
790 {:ok, list} = Pleroma.List.create("name", user)
791 {:ok, list} = Pleroma.List.follow(list, other_user)
795 |> assign(:user, user)
796 |> get("/api/v1/timelines/list/#{list.id}")
798 assert [%{"id" => id}] = json_response(conn, 200)
800 assert id == to_string(activity_two.id)
803 test "list timeline does not leak non-public statuses for unfollowed users", %{conn: conn} do
805 other_user = insert(:user)
806 {:ok, activity_one} = TwitterAPI.create_status(other_user, %{"status" => "Marisa is cute."})
808 {:ok, _activity_two} =
809 TwitterAPI.create_status(other_user, %{
810 "status" => "Marisa is cute.",
811 "visibility" => "private"
814 {:ok, list} = Pleroma.List.create("name", user)
815 {:ok, list} = Pleroma.List.follow(list, other_user)
819 |> assign(:user, user)
820 |> get("/api/v1/timelines/list/#{list.id}")
822 assert [%{"id" => id}] = json_response(conn, 200)
824 assert id == to_string(activity_one.id)
828 describe "notifications" do
829 test "list of notifications", %{conn: conn} do
831 other_user = insert(:user)
834 TwitterAPI.create_status(other_user, %{"status" => "hi @#{user.nickname}"})
836 {:ok, [_notification]} = Notification.create_notifications(activity)
840 |> assign(:user, user)
841 |> get("/api/v1/notifications")
844 "hi <span class=\"h-card\"><a data-user=\"#{user.id}\" class=\"u-url mention\" href=\"#{
846 }\">@<span>#{user.nickname}</span></a></span>"
848 assert [%{"status" => %{"content" => response}} | _rest] = json_response(conn, 200)
849 assert response == expected_response
852 test "getting a single notification", %{conn: conn} do
854 other_user = insert(:user)
857 TwitterAPI.create_status(other_user, %{"status" => "hi @#{user.nickname}"})
859 {:ok, [notification]} = Notification.create_notifications(activity)
863 |> assign(:user, user)
864 |> get("/api/v1/notifications/#{notification.id}")
867 "hi <span class=\"h-card\"><a data-user=\"#{user.id}\" class=\"u-url mention\" href=\"#{
869 }\">@<span>#{user.nickname}</span></a></span>"
871 assert %{"status" => %{"content" => response}} = json_response(conn, 200)
872 assert response == expected_response
875 test "dismissing a single notification", %{conn: conn} do
877 other_user = insert(:user)
880 TwitterAPI.create_status(other_user, %{"status" => "hi @#{user.nickname}"})
882 {:ok, [notification]} = Notification.create_notifications(activity)
886 |> assign(:user, user)
887 |> post("/api/v1/notifications/dismiss", %{"id" => notification.id})
889 assert %{} = json_response(conn, 200)
892 test "clearing all notifications", %{conn: conn} do
894 other_user = insert(:user)
897 TwitterAPI.create_status(other_user, %{"status" => "hi @#{user.nickname}"})
899 {:ok, [_notification]} = Notification.create_notifications(activity)
903 |> assign(:user, user)
904 |> post("/api/v1/notifications/clear")
906 assert %{} = json_response(conn, 200)
910 |> assign(:user, user)
911 |> get("/api/v1/notifications")
913 assert all = json_response(conn, 200)
917 test "paginates notifications using min_id, since_id, max_id, and limit", %{conn: conn} do
919 other_user = insert(:user)
921 {:ok, activity1} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
922 {:ok, activity2} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
923 {:ok, activity3} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
924 {:ok, activity4} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
926 notification1_id = Repo.get_by(Notification, activity_id: activity1.id).id |> to_string()
927 notification2_id = Repo.get_by(Notification, activity_id: activity2.id).id |> to_string()
928 notification3_id = Repo.get_by(Notification, activity_id: activity3.id).id |> to_string()
929 notification4_id = Repo.get_by(Notification, activity_id: activity4.id).id |> to_string()
933 |> assign(:user, user)
938 |> get("/api/v1/notifications?limit=2&min_id=#{notification1_id}")
940 result = json_response(conn_res, 200)
941 assert [%{"id" => ^notification3_id}, %{"id" => ^notification2_id}] = result
946 |> get("/api/v1/notifications?limit=2&since_id=#{notification1_id}")
948 result = json_response(conn_res, 200)
949 assert [%{"id" => ^notification4_id}, %{"id" => ^notification3_id}] = result
954 |> get("/api/v1/notifications?limit=2&max_id=#{notification4_id}")
956 result = json_response(conn_res, 200)
957 assert [%{"id" => ^notification3_id}, %{"id" => ^notification2_id}] = result
960 test "filters notifications using exclude_types", %{conn: conn} do
962 other_user = insert(:user)
964 {:ok, mention_activity} = CommonAPI.post(other_user, %{"status" => "hey @#{user.nickname}"})
965 {:ok, create_activity} = CommonAPI.post(user, %{"status" => "hey"})
966 {:ok, favorite_activity, _} = CommonAPI.favorite(create_activity.id, other_user)
967 {:ok, reblog_activity, _} = CommonAPI.repeat(create_activity.id, other_user)
968 {:ok, _, _, follow_activity} = CommonAPI.follow(other_user, user)
970 mention_notification_id =
971 Repo.get_by(Notification, activity_id: mention_activity.id).id |> to_string()
973 favorite_notification_id =
974 Repo.get_by(Notification, activity_id: favorite_activity.id).id |> to_string()
976 reblog_notification_id =
977 Repo.get_by(Notification, activity_id: reblog_activity.id).id |> to_string()
979 follow_notification_id =
980 Repo.get_by(Notification, activity_id: follow_activity.id).id |> to_string()
984 |> assign(:user, user)
987 get(conn, "/api/v1/notifications", %{exclude_types: ["mention", "favourite", "reblog"]})
989 assert [%{"id" => ^follow_notification_id}] = json_response(conn_res, 200)
992 get(conn, "/api/v1/notifications", %{exclude_types: ["favourite", "reblog", "follow"]})
994 assert [%{"id" => ^mention_notification_id}] = json_response(conn_res, 200)
997 get(conn, "/api/v1/notifications", %{exclude_types: ["reblog", "follow", "mention"]})
999 assert [%{"id" => ^favorite_notification_id}] = json_response(conn_res, 200)
1002 get(conn, "/api/v1/notifications", %{exclude_types: ["follow", "mention", "favourite"]})
1004 assert [%{"id" => ^reblog_notification_id}] = json_response(conn_res, 200)
1007 test "destroy multiple", %{conn: conn} do
1008 user = insert(:user)
1009 other_user = insert(:user)
1011 {:ok, activity1} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
1012 {:ok, activity2} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
1013 {:ok, activity3} = CommonAPI.post(user, %{"status" => "hi @#{other_user.nickname}"})
1014 {:ok, activity4} = CommonAPI.post(user, %{"status" => "hi @#{other_user.nickname}"})
1016 notification1_id = Repo.get_by(Notification, activity_id: activity1.id).id |> to_string()
1017 notification2_id = Repo.get_by(Notification, activity_id: activity2.id).id |> to_string()
1018 notification3_id = Repo.get_by(Notification, activity_id: activity3.id).id |> to_string()
1019 notification4_id = Repo.get_by(Notification, activity_id: activity4.id).id |> to_string()
1023 |> assign(:user, user)
1027 |> get("/api/v1/notifications")
1029 result = json_response(conn_res, 200)
1030 assert [%{"id" => ^notification2_id}, %{"id" => ^notification1_id}] = result
1034 |> assign(:user, other_user)
1038 |> get("/api/v1/notifications")
1040 result = json_response(conn_res, 200)
1041 assert [%{"id" => ^notification4_id}, %{"id" => ^notification3_id}] = result
1045 |> delete("/api/v1/notifications/destroy_multiple", %{
1046 "ids" => [notification1_id, notification2_id]
1049 assert json_response(conn_destroy, 200) == %{}
1053 |> get("/api/v1/notifications")
1055 result = json_response(conn_res, 200)
1056 assert [%{"id" => ^notification4_id}, %{"id" => ^notification3_id}] = result
1060 describe "reblogging" do
1061 test "reblogs and returns the reblogged status", %{conn: conn} do
1062 activity = insert(:note_activity)
1063 user = insert(:user)
1067 |> assign(:user, user)
1068 |> post("/api/v1/statuses/#{activity.id}/reblog")
1071 "reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 1},
1073 } = json_response(conn, 200)
1075 assert to_string(activity.id) == id
1078 test "reblogged status for another user", %{conn: conn} do
1079 activity = insert(:note_activity)
1080 user1 = insert(:user)
1081 user2 = insert(:user)
1082 user3 = insert(:user)
1083 CommonAPI.favorite(activity.id, user2)
1084 {:ok, _bookmark} = Pleroma.Bookmark.create(user2.id, activity.id)
1085 {:ok, reblog_activity1, _object} = CommonAPI.repeat(activity.id, user1)
1086 {:ok, _, _object} = CommonAPI.repeat(activity.id, user2)
1090 |> assign(:user, user3)
1091 |> get("/api/v1/statuses/#{reblog_activity1.id}")
1094 "reblog" => %{"id" => id, "reblogged" => false, "reblogs_count" => 2},
1095 "reblogged" => false,
1096 "favourited" => false,
1097 "bookmarked" => false
1098 } = json_response(conn_res, 200)
1102 |> assign(:user, user2)
1103 |> get("/api/v1/statuses/#{reblog_activity1.id}")
1106 "reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 2},
1107 "reblogged" => true,
1108 "favourited" => true,
1109 "bookmarked" => true
1110 } = json_response(conn_res, 200)
1112 assert to_string(activity.id) == id
1116 describe "unreblogging" do
1117 test "unreblogs and returns the unreblogged status", %{conn: conn} do
1118 activity = insert(:note_activity)
1119 user = insert(:user)
1121 {:ok, _, _} = CommonAPI.repeat(activity.id, user)
1125 |> assign(:user, user)
1126 |> post("/api/v1/statuses/#{activity.id}/unreblog")
1128 assert %{"id" => id, "reblogged" => false, "reblogs_count" => 0} = json_response(conn, 200)
1130 assert to_string(activity.id) == id
1134 describe "favoriting" do
1135 test "favs a status and returns it", %{conn: conn} do
1136 activity = insert(:note_activity)
1137 user = insert(:user)
1141 |> assign(:user, user)
1142 |> post("/api/v1/statuses/#{activity.id}/favourite")
1144 assert %{"id" => id, "favourites_count" => 1, "favourited" => true} =
1145 json_response(conn, 200)
1147 assert to_string(activity.id) == id
1150 test "returns 500 for a wrong id", %{conn: conn} do
1151 user = insert(:user)
1155 |> assign(:user, user)
1156 |> post("/api/v1/statuses/1/favourite")
1157 |> json_response(500)
1159 assert resp == "Something went wrong"
1163 describe "unfavoriting" do
1164 test "unfavorites a status and returns it", %{conn: conn} do
1165 activity = insert(:note_activity)
1166 user = insert(:user)
1168 {:ok, _, _} = CommonAPI.favorite(activity.id, user)
1172 |> assign(:user, user)
1173 |> post("/api/v1/statuses/#{activity.id}/unfavourite")
1175 assert %{"id" => id, "favourites_count" => 0, "favourited" => false} =
1176 json_response(conn, 200)
1178 assert to_string(activity.id) == id
1182 describe "user timelines" do
1183 test "gets a users statuses", %{conn: conn} do
1184 user_one = insert(:user)
1185 user_two = insert(:user)
1186 user_three = insert(:user)
1188 {:ok, user_three} = User.follow(user_three, user_one)
1190 {:ok, activity} = CommonAPI.post(user_one, %{"status" => "HI!!!"})
1192 {:ok, direct_activity} =
1193 CommonAPI.post(user_one, %{
1194 "status" => "Hi, @#{user_two.nickname}.",
1195 "visibility" => "direct"
1198 {:ok, private_activity} =
1199 CommonAPI.post(user_one, %{"status" => "private", "visibility" => "private"})
1203 |> get("/api/v1/accounts/#{user_one.id}/statuses")
1205 assert [%{"id" => id}] = json_response(resp, 200)
1206 assert id == to_string(activity.id)
1210 |> assign(:user, user_two)
1211 |> get("/api/v1/accounts/#{user_one.id}/statuses")
1213 assert [%{"id" => id_one}, %{"id" => id_two}] = json_response(resp, 200)
1214 assert id_one == to_string(direct_activity.id)
1215 assert id_two == to_string(activity.id)
1219 |> assign(:user, user_three)
1220 |> get("/api/v1/accounts/#{user_one.id}/statuses")
1222 assert [%{"id" => id_one}, %{"id" => id_two}] = json_response(resp, 200)
1223 assert id_one == to_string(private_activity.id)
1224 assert id_two == to_string(activity.id)
1227 test "unimplemented pinned statuses feature", %{conn: conn} do
1228 note = insert(:note_activity)
1229 user = User.get_cached_by_ap_id(note.data["actor"])
1233 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
1235 assert json_response(conn, 200) == []
1238 test "gets an users media", %{conn: conn} do
1239 note = insert(:note_activity)
1240 user = User.get_cached_by_ap_id(note.data["actor"])
1242 file = %Plug.Upload{
1243 content_type: "image/jpg",
1244 path: Path.absname("test/fixtures/image.jpg"),
1245 filename: "an_image.jpg"
1249 TwitterAPI.upload(file, user, "json")
1253 TwitterAPI.create_status(user, %{"status" => "cofe", "media_ids" => [media["media_id"]]})
1257 |> get("/api/v1/accounts/#{user.id}/statuses", %{"only_media" => "true"})
1259 assert [%{"id" => id}] = json_response(conn, 200)
1260 assert id == to_string(image_post.id)
1264 |> get("/api/v1/accounts/#{user.id}/statuses", %{"only_media" => "1"})
1266 assert [%{"id" => id}] = json_response(conn, 200)
1267 assert id == to_string(image_post.id)
1270 test "gets a user's statuses without reblogs", %{conn: conn} do
1271 user = insert(:user)
1272 {:ok, post} = CommonAPI.post(user, %{"status" => "HI!!!"})
1273 {:ok, _, _} = CommonAPI.repeat(post.id, user)
1277 |> get("/api/v1/accounts/#{user.id}/statuses", %{"exclude_reblogs" => "true"})
1279 assert [%{"id" => id}] = json_response(conn, 200)
1280 assert id == to_string(post.id)
1284 |> get("/api/v1/accounts/#{user.id}/statuses", %{"exclude_reblogs" => "1"})
1286 assert [%{"id" => id}] = json_response(conn, 200)
1287 assert id == to_string(post.id)
1291 describe "user relationships" do
1292 test "returns the relationships for the current user", %{conn: conn} do
1293 user = insert(:user)
1294 other_user = insert(:user)
1295 {:ok, user} = User.follow(user, other_user)
1299 |> assign(:user, user)
1300 |> get("/api/v1/accounts/relationships", %{"id" => [other_user.id]})
1302 assert [relationship] = json_response(conn, 200)
1304 assert to_string(other_user.id) == relationship["id"]
1308 describe "locked accounts" do
1309 test "/api/v1/follow_requests works" do
1310 user = insert(:user, %{info: %Pleroma.User.Info{locked: true}})
1311 other_user = insert(:user)
1313 {:ok, _activity} = ActivityPub.follow(other_user, user)
1315 user = User.get_cached_by_id(user.id)
1316 other_user = User.get_cached_by_id(other_user.id)
1318 assert User.following?(other_user, user) == false
1322 |> assign(:user, user)
1323 |> get("/api/v1/follow_requests")
1325 assert [relationship] = json_response(conn, 200)
1326 assert to_string(other_user.id) == relationship["id"]
1329 test "/api/v1/follow_requests/:id/authorize works" do
1330 user = insert(:user, %{info: %User.Info{locked: true}})
1331 other_user = insert(:user)
1333 {:ok, _activity} = ActivityPub.follow(other_user, user)
1335 user = User.get_cached_by_id(user.id)
1336 other_user = User.get_cached_by_id(other_user.id)
1338 assert User.following?(other_user, user) == false
1342 |> assign(:user, user)
1343 |> post("/api/v1/follow_requests/#{other_user.id}/authorize")
1345 assert relationship = json_response(conn, 200)
1346 assert to_string(other_user.id) == relationship["id"]
1348 user = User.get_cached_by_id(user.id)
1349 other_user = User.get_cached_by_id(other_user.id)
1351 assert User.following?(other_user, user) == true
1354 test "verify_credentials", %{conn: conn} do
1355 user = insert(:user, %{info: %Pleroma.User.Info{default_scope: "private"}})
1359 |> assign(:user, user)
1360 |> get("/api/v1/accounts/verify_credentials")
1362 assert %{"id" => id, "source" => %{"privacy" => "private"}} = json_response(conn, 200)
1363 assert id == to_string(user.id)
1366 test "/api/v1/follow_requests/:id/reject works" do
1367 user = insert(:user, %{info: %Pleroma.User.Info{locked: true}})
1368 other_user = insert(:user)
1370 {:ok, _activity} = ActivityPub.follow(other_user, user)
1372 user = User.get_cached_by_id(user.id)
1376 |> assign(:user, user)
1377 |> post("/api/v1/follow_requests/#{other_user.id}/reject")
1379 assert relationship = json_response(conn, 200)
1380 assert to_string(other_user.id) == relationship["id"]
1382 user = User.get_cached_by_id(user.id)
1383 other_user = User.get_cached_by_id(other_user.id)
1385 assert User.following?(other_user, user) == false
1389 test "account fetching", %{conn: conn} do
1390 user = insert(:user)
1394 |> get("/api/v1/accounts/#{user.id}")
1396 assert %{"id" => id} = json_response(conn, 200)
1397 assert id == to_string(user.id)
1401 |> get("/api/v1/accounts/-1")
1403 assert %{"error" => "Can't find user"} = json_response(conn, 404)
1406 test "account fetching also works nickname", %{conn: conn} do
1407 user = insert(:user)
1411 |> get("/api/v1/accounts/#{user.nickname}")
1413 assert %{"id" => id} = json_response(conn, 200)
1414 assert id == user.id
1417 test "media upload", %{conn: conn} do
1418 file = %Plug.Upload{
1419 content_type: "image/jpg",
1420 path: Path.absname("test/fixtures/image.jpg"),
1421 filename: "an_image.jpg"
1424 desc = "Description of the image"
1426 user = insert(:user)
1430 |> assign(:user, user)
1431 |> post("/api/v1/media", %{"file" => file, "description" => desc})
1433 assert media = json_response(conn, 200)
1435 assert media["type"] == "image"
1436 assert media["description"] == desc
1439 object = Repo.get(Object, media["id"])
1440 assert object.data["actor"] == User.ap_id(user)
1443 test "hashtag timeline", %{conn: conn} do
1444 following = insert(:user)
1447 {:ok, activity} = TwitterAPI.create_status(following, %{"status" => "test #2hu"})
1449 {:ok, [_activity]} =
1450 OStatus.fetch_activity_from_url("https://shitposter.club/notice/2827873")
1454 |> get("/api/v1/timelines/tag/2hu")
1456 assert [%{"id" => id}] = json_response(nconn, 200)
1458 assert id == to_string(activity.id)
1460 # works for different capitalization too
1463 |> get("/api/v1/timelines/tag/2HU")
1465 assert [%{"id" => id}] = json_response(nconn, 200)
1467 assert id == to_string(activity.id)
1471 test "multi-hashtag timeline", %{conn: conn} do
1472 user = insert(:user)
1474 {:ok, activity_test} = CommonAPI.post(user, %{"status" => "#test"})
1475 {:ok, activity_test1} = CommonAPI.post(user, %{"status" => "#test #test1"})
1476 {:ok, activity_none} = CommonAPI.post(user, %{"status" => "#test #none"})
1480 |> get("/api/v1/timelines/tag/test", %{"any" => ["test1"]})
1482 [status_none, status_test1, status_test] = json_response(any_test, 200)
1484 assert to_string(activity_test.id) == status_test["id"]
1485 assert to_string(activity_test1.id) == status_test1["id"]
1486 assert to_string(activity_none.id) == status_none["id"]
1490 |> get("/api/v1/timelines/tag/test", %{"all" => ["test1"], "none" => ["none"]})
1492 assert [status_test1] == json_response(restricted_test, 200)
1494 all_test = conn |> get("/api/v1/timelines/tag/test", %{"all" => ["none"]})
1496 assert [status_none] == json_response(all_test, 200)
1499 test "getting followers", %{conn: conn} do
1500 user = insert(:user)
1501 other_user = insert(:user)
1502 {:ok, user} = User.follow(user, other_user)
1506 |> get("/api/v1/accounts/#{other_user.id}/followers")
1508 assert [%{"id" => id}] = json_response(conn, 200)
1509 assert id == to_string(user.id)
1512 test "getting followers, hide_followers", %{conn: conn} do
1513 user = insert(:user)
1514 other_user = insert(:user, %{info: %{hide_followers: true}})
1515 {:ok, _user} = User.follow(user, other_user)
1519 |> get("/api/v1/accounts/#{other_user.id}/followers")
1521 assert [] == json_response(conn, 200)
1524 test "getting followers, hide_followers, same user requesting", %{conn: conn} do
1525 user = insert(:user)
1526 other_user = insert(:user, %{info: %{hide_followers: true}})
1527 {:ok, _user} = User.follow(user, other_user)
1531 |> assign(:user, other_user)
1532 |> get("/api/v1/accounts/#{other_user.id}/followers")
1534 refute [] == json_response(conn, 200)
1537 test "getting followers, pagination", %{conn: conn} do
1538 user = insert(:user)
1539 follower1 = insert(:user)
1540 follower2 = insert(:user)
1541 follower3 = insert(:user)
1542 {:ok, _} = User.follow(follower1, user)
1543 {:ok, _} = User.follow(follower2, user)
1544 {:ok, _} = User.follow(follower3, user)
1548 |> assign(:user, user)
1552 |> get("/api/v1/accounts/#{user.id}/followers?since_id=#{follower1.id}")
1554 assert [%{"id" => id3}, %{"id" => id2}] = json_response(res_conn, 200)
1555 assert id3 == follower3.id
1556 assert id2 == follower2.id
1560 |> get("/api/v1/accounts/#{user.id}/followers?max_id=#{follower3.id}")
1562 assert [%{"id" => id2}, %{"id" => id1}] = json_response(res_conn, 200)
1563 assert id2 == follower2.id
1564 assert id1 == follower1.id
1568 |> get("/api/v1/accounts/#{user.id}/followers?limit=1&max_id=#{follower3.id}")
1570 assert [%{"id" => id2}] = json_response(res_conn, 200)
1571 assert id2 == follower2.id
1573 assert [link_header] = get_resp_header(res_conn, "link")
1574 assert link_header =~ ~r/min_id=#{follower2.id}/
1575 assert link_header =~ ~r/max_id=#{follower2.id}/
1578 test "getting following", %{conn: conn} do
1579 user = insert(:user)
1580 other_user = insert(:user)
1581 {:ok, user} = User.follow(user, other_user)
1585 |> get("/api/v1/accounts/#{user.id}/following")
1587 assert [%{"id" => id}] = json_response(conn, 200)
1588 assert id == to_string(other_user.id)
1591 test "getting following, hide_follows", %{conn: conn} do
1592 user = insert(:user, %{info: %{hide_follows: true}})
1593 other_user = insert(:user)
1594 {:ok, user} = User.follow(user, other_user)
1598 |> get("/api/v1/accounts/#{user.id}/following")
1600 assert [] == json_response(conn, 200)
1603 test "getting following, hide_follows, same user requesting", %{conn: conn} do
1604 user = insert(:user, %{info: %{hide_follows: true}})
1605 other_user = insert(:user)
1606 {:ok, user} = User.follow(user, other_user)
1610 |> assign(:user, user)
1611 |> get("/api/v1/accounts/#{user.id}/following")
1613 refute [] == json_response(conn, 200)
1616 test "getting following, pagination", %{conn: conn} do
1617 user = insert(:user)
1618 following1 = insert(:user)
1619 following2 = insert(:user)
1620 following3 = insert(:user)
1621 {:ok, _} = User.follow(user, following1)
1622 {:ok, _} = User.follow(user, following2)
1623 {:ok, _} = User.follow(user, following3)
1627 |> assign(:user, user)
1631 |> get("/api/v1/accounts/#{user.id}/following?since_id=#{following1.id}")
1633 assert [%{"id" => id3}, %{"id" => id2}] = json_response(res_conn, 200)
1634 assert id3 == following3.id
1635 assert id2 == following2.id
1639 |> get("/api/v1/accounts/#{user.id}/following?max_id=#{following3.id}")
1641 assert [%{"id" => id2}, %{"id" => id1}] = json_response(res_conn, 200)
1642 assert id2 == following2.id
1643 assert id1 == following1.id
1647 |> get("/api/v1/accounts/#{user.id}/following?limit=1&max_id=#{following3.id}")
1649 assert [%{"id" => id2}] = json_response(res_conn, 200)
1650 assert id2 == following2.id
1652 assert [link_header] = get_resp_header(res_conn, "link")
1653 assert link_header =~ ~r/min_id=#{following2.id}/
1654 assert link_header =~ ~r/max_id=#{following2.id}/
1657 test "following / unfollowing a user", %{conn: conn} do
1658 user = insert(:user)
1659 other_user = insert(:user)
1663 |> assign(:user, user)
1664 |> post("/api/v1/accounts/#{other_user.id}/follow")
1666 assert %{"id" => _id, "following" => true} = json_response(conn, 200)
1668 user = User.get_cached_by_id(user.id)
1672 |> assign(:user, user)
1673 |> post("/api/v1/accounts/#{other_user.id}/unfollow")
1675 assert %{"id" => _id, "following" => false} = json_response(conn, 200)
1677 user = User.get_cached_by_id(user.id)
1681 |> assign(:user, user)
1682 |> post("/api/v1/follows", %{"uri" => other_user.nickname})
1684 assert %{"id" => id} = json_response(conn, 200)
1685 assert id == to_string(other_user.id)
1688 test "following without reblogs" do
1689 follower = insert(:user)
1690 followed = insert(:user)
1691 other_user = insert(:user)
1695 |> assign(:user, follower)
1696 |> post("/api/v1/accounts/#{followed.id}/follow?reblogs=false")
1698 assert %{"showing_reblogs" => false} = json_response(conn, 200)
1700 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "hey"})
1701 {:ok, reblog, _} = CommonAPI.repeat(activity.id, followed)
1705 |> assign(:user, User.get_cached_by_id(follower.id))
1706 |> get("/api/v1/timelines/home")
1708 assert [] == json_response(conn, 200)
1712 |> assign(:user, follower)
1713 |> post("/api/v1/accounts/#{followed.id}/follow?reblogs=true")
1715 assert %{"showing_reblogs" => true} = json_response(conn, 200)
1719 |> assign(:user, User.get_cached_by_id(follower.id))
1720 |> get("/api/v1/timelines/home")
1722 expected_activity_id = reblog.id
1723 assert [%{"id" => ^expected_activity_id}] = json_response(conn, 200)
1726 test "following / unfollowing errors" do
1727 user = insert(:user)
1731 |> assign(:user, user)
1734 conn_res = post(conn, "/api/v1/accounts/#{user.id}/follow")
1735 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
1738 user = User.get_cached_by_id(user.id)
1739 conn_res = post(conn, "/api/v1/accounts/#{user.id}/unfollow")
1740 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
1742 # self follow via uri
1743 user = User.get_cached_by_id(user.id)
1744 conn_res = post(conn, "/api/v1/follows", %{"uri" => user.nickname})
1745 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
1747 # follow non existing user
1748 conn_res = post(conn, "/api/v1/accounts/doesntexist/follow")
1749 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
1751 # follow non existing user via uri
1752 conn_res = post(conn, "/api/v1/follows", %{"uri" => "doesntexist"})
1753 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
1755 # unfollow non existing user
1756 conn_res = post(conn, "/api/v1/accounts/doesntexist/unfollow")
1757 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
1760 test "muting / unmuting a user", %{conn: conn} do
1761 user = insert(:user)
1762 other_user = insert(:user)
1766 |> assign(:user, user)
1767 |> post("/api/v1/accounts/#{other_user.id}/mute")
1769 assert %{"id" => _id, "muting" => true} = json_response(conn, 200)
1771 user = User.get_cached_by_id(user.id)
1775 |> assign(:user, user)
1776 |> post("/api/v1/accounts/#{other_user.id}/unmute")
1778 assert %{"id" => _id, "muting" => false} = json_response(conn, 200)
1781 test "subscribing / unsubscribing to a user", %{conn: conn} do
1782 user = insert(:user)
1783 subscription_target = insert(:user)
1787 |> assign(:user, user)
1788 |> post("/api/v1/pleroma/accounts/#{subscription_target.id}/subscribe")
1790 assert %{"id" => _id, "subscribing" => true} = json_response(conn, 200)
1794 |> assign(:user, user)
1795 |> post("/api/v1/pleroma/accounts/#{subscription_target.id}/unsubscribe")
1797 assert %{"id" => _id, "subscribing" => false} = json_response(conn, 200)
1800 test "getting a list of mutes", %{conn: conn} do
1801 user = insert(:user)
1802 other_user = insert(:user)
1804 {:ok, user} = User.mute(user, other_user)
1808 |> assign(:user, user)
1809 |> get("/api/v1/mutes")
1811 other_user_id = to_string(other_user.id)
1812 assert [%{"id" => ^other_user_id}] = json_response(conn, 200)
1815 test "blocking / unblocking a user", %{conn: conn} do
1816 user = insert(:user)
1817 other_user = insert(:user)
1821 |> assign(:user, user)
1822 |> post("/api/v1/accounts/#{other_user.id}/block")
1824 assert %{"id" => _id, "blocking" => true} = json_response(conn, 200)
1826 user = User.get_cached_by_id(user.id)
1830 |> assign(:user, user)
1831 |> post("/api/v1/accounts/#{other_user.id}/unblock")
1833 assert %{"id" => _id, "blocking" => false} = json_response(conn, 200)
1836 test "getting a list of blocks", %{conn: conn} do
1837 user = insert(:user)
1838 other_user = insert(:user)
1840 {:ok, user} = User.block(user, other_user)
1844 |> assign(:user, user)
1845 |> get("/api/v1/blocks")
1847 other_user_id = to_string(other_user.id)
1848 assert [%{"id" => ^other_user_id}] = json_response(conn, 200)
1851 test "blocking / unblocking a domain", %{conn: conn} do
1852 user = insert(:user)
1853 other_user = insert(:user, %{ap_id: "https://dogwhistle.zone/@pundit"})
1857 |> assign(:user, user)
1858 |> post("/api/v1/domain_blocks", %{"domain" => "dogwhistle.zone"})
1860 assert %{} = json_response(conn, 200)
1861 user = User.get_cached_by_ap_id(user.ap_id)
1862 assert User.blocks?(user, other_user)
1866 |> assign(:user, user)
1867 |> delete("/api/v1/domain_blocks", %{"domain" => "dogwhistle.zone"})
1869 assert %{} = json_response(conn, 200)
1870 user = User.get_cached_by_ap_id(user.ap_id)
1871 refute User.blocks?(user, other_user)
1874 test "getting a list of domain blocks", %{conn: conn} do
1875 user = insert(:user)
1877 {:ok, user} = User.block_domain(user, "bad.site")
1878 {:ok, user} = User.block_domain(user, "even.worse.site")
1882 |> assign(:user, user)
1883 |> get("/api/v1/domain_blocks")
1885 domain_blocks = json_response(conn, 200)
1887 assert "bad.site" in domain_blocks
1888 assert "even.worse.site" in domain_blocks
1891 test "unimplemented follow_requests, blocks, domain blocks" do
1892 user = insert(:user)
1894 ["blocks", "domain_blocks", "follow_requests"]
1895 |> Enum.each(fn endpoint ->
1898 |> assign(:user, user)
1899 |> get("/api/v1/#{endpoint}")
1901 assert [] = json_response(conn, 200)
1905 test "account search", %{conn: conn} do
1906 user = insert(:user)
1907 user_two = insert(:user, %{nickname: "shp@shitposter.club"})
1908 user_three = insert(:user, %{nickname: "shp@heldscal.la", name: "I love 2hu"})
1912 |> assign(:user, user)
1913 |> get("/api/v1/accounts/search", %{"q" => "shp"})
1914 |> json_response(200)
1916 result_ids = for result <- results, do: result["acct"]
1918 assert user_two.nickname in result_ids
1919 assert user_three.nickname in result_ids
1923 |> assign(:user, user)
1924 |> get("/api/v1/accounts/search", %{"q" => "2hu"})
1925 |> json_response(200)
1927 result_ids = for result <- results, do: result["acct"]
1929 assert user_three.nickname in result_ids
1932 test "search", %{conn: conn} do
1933 user = insert(:user)
1934 user_two = insert(:user, %{nickname: "shp@shitposter.club"})
1935 user_three = insert(:user, %{nickname: "shp@heldscal.la", name: "I love 2hu"})
1937 {:ok, activity} = CommonAPI.post(user, %{"status" => "This is about 2hu"})
1940 CommonAPI.post(user, %{
1941 "status" => "This is about 2hu, but private",
1942 "visibility" => "private"
1945 {:ok, _} = CommonAPI.post(user_two, %{"status" => "This isn't"})
1949 |> get("/api/v1/search", %{"q" => "2hu"})
1951 assert results = json_response(conn, 200)
1953 [account | _] = results["accounts"]
1954 assert account["id"] == to_string(user_three.id)
1956 assert results["hashtags"] == []
1958 [status] = results["statuses"]
1959 assert status["id"] == to_string(activity.id)
1962 test "search fetches remote statuses", %{conn: conn} do
1966 |> get("/api/v1/search", %{"q" => "https://shitposter.club/notice/2827873"})
1968 assert results = json_response(conn, 200)
1970 [status] = results["statuses"]
1971 assert status["uri"] == "tag:shitposter.club,2017-05-05:noticeId=2827873:objectType=comment"
1975 test "search doesn't show statuses that it shouldn't", %{conn: conn} do
1977 CommonAPI.post(insert(:user), %{
1978 "status" => "This is about 2hu, but private",
1979 "visibility" => "private"
1985 |> get("/api/v1/search", %{"q" => Object.normalize(activity).data["id"]})
1987 assert results = json_response(conn, 200)
1989 [] = results["statuses"]
1993 test "search fetches remote accounts", %{conn: conn} do
1996 |> get("/api/v1/search", %{"q" => "shp@social.heldscal.la", "resolve" => "true"})
1998 assert results = json_response(conn, 200)
1999 [account] = results["accounts"]
2000 assert account["acct"] == "shp@social.heldscal.la"
2003 test "returns the favorites of a user", %{conn: conn} do
2004 user = insert(:user)
2005 other_user = insert(:user)
2007 {:ok, _} = CommonAPI.post(other_user, %{"status" => "bla"})
2008 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "traps are happy"})
2010 {:ok, _, _} = CommonAPI.favorite(activity.id, user)
2014 |> assign(:user, user)
2015 |> get("/api/v1/favourites")
2017 assert [status] = json_response(first_conn, 200)
2018 assert status["id"] == to_string(activity.id)
2020 assert [{"link", _link_header}] =
2021 Enum.filter(first_conn.resp_headers, fn element -> match?({"link", _}, element) end)
2023 # Honours query params
2024 {:ok, second_activity} =
2025 CommonAPI.post(other_user, %{
2027 "Trees Are Never Sad Look At Them Every Once In Awhile They're Quite Beautiful."
2030 {:ok, _, _} = CommonAPI.favorite(second_activity.id, user)
2032 last_like = status["id"]
2036 |> assign(:user, user)
2037 |> get("/api/v1/favourites?since_id=#{last_like}")
2039 assert [second_status] = json_response(second_conn, 200)
2040 assert second_status["id"] == to_string(second_activity.id)
2044 |> assign(:user, user)
2045 |> get("/api/v1/favourites?limit=0")
2047 assert [] = json_response(third_conn, 200)
2050 describe "getting favorites timeline of specified user" do
2052 [current_user, user] = insert_pair(:user, %{info: %{hide_favorites: false}})
2053 [current_user: current_user, user: user]
2056 test "returns list of statuses favorited by specified user", %{
2058 current_user: current_user,
2061 [activity | _] = insert_pair(:note_activity)
2062 CommonAPI.favorite(activity.id, user)
2066 |> assign(:user, current_user)
2067 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2068 |> json_response(:ok)
2072 assert length(response) == 1
2073 assert like["id"] == activity.id
2076 test "returns favorites for specified user_id when user is not logged in", %{
2080 activity = insert(:note_activity)
2081 CommonAPI.favorite(activity.id, user)
2085 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2086 |> json_response(:ok)
2088 assert length(response) == 1
2091 test "returns favorited DM only when user is logged in and he is one of recipients", %{
2093 current_user: current_user,
2097 CommonAPI.post(current_user, %{
2098 "status" => "Hi @#{user.nickname}!",
2099 "visibility" => "direct"
2102 CommonAPI.favorite(direct.id, user)
2106 |> assign(:user, current_user)
2107 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2108 |> json_response(:ok)
2110 assert length(response) == 1
2112 anonymous_response =
2114 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2115 |> json_response(:ok)
2117 assert length(anonymous_response) == 0
2120 test "does not return others' favorited DM when user is not one of recipients", %{
2122 current_user: current_user,
2125 user_two = insert(:user)
2128 CommonAPI.post(user_two, %{
2129 "status" => "Hi @#{user.nickname}!",
2130 "visibility" => "direct"
2133 CommonAPI.favorite(direct.id, user)
2137 |> assign(:user, current_user)
2138 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2139 |> json_response(:ok)
2141 assert length(response) == 0
2144 test "paginates favorites using since_id and max_id", %{
2146 current_user: current_user,
2149 activities = insert_list(10, :note_activity)
2151 Enum.each(activities, fn activity ->
2152 CommonAPI.favorite(activity.id, user)
2155 third_activity = Enum.at(activities, 2)
2156 seventh_activity = Enum.at(activities, 6)
2160 |> assign(:user, current_user)
2161 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites", %{
2162 since_id: third_activity.id,
2163 max_id: seventh_activity.id
2165 |> json_response(:ok)
2167 assert length(response) == 3
2168 refute third_activity in response
2169 refute seventh_activity in response
2172 test "limits favorites using limit parameter", %{
2174 current_user: current_user,
2178 |> insert_list(:note_activity)
2179 |> Enum.each(fn activity ->
2180 CommonAPI.favorite(activity.id, user)
2185 |> assign(:user, current_user)
2186 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites", %{limit: "3"})
2187 |> json_response(:ok)
2189 assert length(response) == 3
2192 test "returns empty response when user does not have any favorited statuses", %{
2194 current_user: current_user,
2199 |> assign(:user, current_user)
2200 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2201 |> json_response(:ok)
2203 assert Enum.empty?(response)
2206 test "returns 404 error when specified user is not exist", %{conn: conn} do
2207 conn = get(conn, "/api/v1/pleroma/accounts/test/favourites")
2209 assert json_response(conn, 404) == %{"error" => "Record not found"}
2212 test "returns 403 error when user has hidden own favorites", %{
2214 current_user: current_user
2216 user = insert(:user, %{info: %{hide_favorites: true}})
2217 activity = insert(:note_activity)
2218 CommonAPI.favorite(activity.id, user)
2222 |> assign(:user, current_user)
2223 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2225 assert json_response(conn, 403) == %{"error" => "Can't get favorites"}
2228 test "hides favorites for new users by default", %{conn: conn, current_user: current_user} do
2229 user = insert(:user)
2230 activity = insert(:note_activity)
2231 CommonAPI.favorite(activity.id, user)
2235 |> assign(:user, current_user)
2236 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2238 assert user.info.hide_favorites
2239 assert json_response(conn, 403) == %{"error" => "Can't get favorites"}
2243 describe "updating credentials" do
2244 test "updates the user's bio", %{conn: conn} do
2245 user = insert(:user)
2246 user2 = insert(:user)
2250 |> assign(:user, user)
2251 |> patch("/api/v1/accounts/update_credentials", %{
2252 "note" => "I drink #cofe with @#{user2.nickname}"
2255 assert user = json_response(conn, 200)
2257 assert user["note"] ==
2258 ~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=") <>
2260 ~s(" class="u-url mention" href=") <>
2261 user2.ap_id <> ~s(">@<span>) <> user2.nickname <> ~s(</span></a></span>)
2264 test "updates the user's locking status", %{conn: conn} do
2265 user = insert(:user)
2269 |> assign(:user, user)
2270 |> patch("/api/v1/accounts/update_credentials", %{locked: "true"})
2272 assert user = json_response(conn, 200)
2273 assert user["locked"] == true
2276 test "updates the user's default scope", %{conn: conn} do
2277 user = insert(:user)
2281 |> assign(:user, user)
2282 |> patch("/api/v1/accounts/update_credentials", %{default_scope: "cofe"})
2284 assert user = json_response(conn, 200)
2285 assert user["source"]["privacy"] == "cofe"
2288 test "updates the user's hide_followers status", %{conn: conn} do
2289 user = insert(:user)
2293 |> assign(:user, user)
2294 |> patch("/api/v1/accounts/update_credentials", %{hide_followers: "true"})
2296 assert user = json_response(conn, 200)
2297 assert user["pleroma"]["hide_followers"] == true
2300 test "updates the user's hide_follows status", %{conn: conn} do
2301 user = insert(:user)
2305 |> assign(:user, user)
2306 |> patch("/api/v1/accounts/update_credentials", %{hide_follows: "true"})
2308 assert user = json_response(conn, 200)
2309 assert user["pleroma"]["hide_follows"] == true
2312 test "updates the user's hide_favorites status", %{conn: conn} do
2313 user = insert(:user)
2317 |> assign(:user, user)
2318 |> patch("/api/v1/accounts/update_credentials", %{hide_favorites: "true"})
2320 assert user = json_response(conn, 200)
2321 assert user["pleroma"]["hide_favorites"] == true
2324 test "updates the user's show_role status", %{conn: conn} do
2325 user = insert(:user)
2329 |> assign(:user, user)
2330 |> patch("/api/v1/accounts/update_credentials", %{show_role: "false"})
2332 assert user = json_response(conn, 200)
2333 assert user["source"]["pleroma"]["show_role"] == false
2336 test "updates the user's no_rich_text status", %{conn: conn} do
2337 user = insert(:user)
2341 |> assign(:user, user)
2342 |> patch("/api/v1/accounts/update_credentials", %{no_rich_text: "true"})
2344 assert user = json_response(conn, 200)
2345 assert user["source"]["pleroma"]["no_rich_text"] == true
2348 test "updates the user's name", %{conn: conn} do
2349 user = insert(:user)
2353 |> assign(:user, user)
2354 |> patch("/api/v1/accounts/update_credentials", %{"display_name" => "markorepairs"})
2356 assert user = json_response(conn, 200)
2357 assert user["display_name"] == "markorepairs"
2360 test "updates the user's avatar", %{conn: conn} do
2361 user = insert(:user)
2363 new_avatar = %Plug.Upload{
2364 content_type: "image/jpg",
2365 path: Path.absname("test/fixtures/image.jpg"),
2366 filename: "an_image.jpg"
2371 |> assign(:user, user)
2372 |> patch("/api/v1/accounts/update_credentials", %{"avatar" => new_avatar})
2374 assert user_response = json_response(conn, 200)
2375 assert user_response["avatar"] != User.avatar_url(user)
2378 test "updates the user's banner", %{conn: conn} do
2379 user = insert(:user)
2381 new_header = %Plug.Upload{
2382 content_type: "image/jpg",
2383 path: Path.absname("test/fixtures/image.jpg"),
2384 filename: "an_image.jpg"
2389 |> assign(:user, user)
2390 |> patch("/api/v1/accounts/update_credentials", %{"header" => new_header})
2392 assert user_response = json_response(conn, 200)
2393 assert user_response["header"] != User.banner_url(user)
2396 test "requires 'write' permission", %{conn: conn} do
2397 token1 = insert(:oauth_token, scopes: ["read"])
2398 token2 = insert(:oauth_token, scopes: ["write", "follow"])
2400 for token <- [token1, token2] do
2403 |> put_req_header("authorization", "Bearer #{token.token}")
2404 |> patch("/api/v1/accounts/update_credentials", %{})
2406 if token == token1 do
2407 assert %{"error" => "Insufficient permissions: write."} == json_response(conn, 403)
2409 assert json_response(conn, 200)
2415 test "get instance information", %{conn: conn} do
2416 conn = get(conn, "/api/v1/instance")
2417 assert result = json_response(conn, 200)
2419 email = Pleroma.Config.get([:instance, :email])
2420 # Note: not checking for "max_toot_chars" since it's optional
2426 "email" => from_config_email,
2428 "streaming_api" => _
2433 "registrations" => _
2436 assert email == from_config_email
2439 test "get instance stats", %{conn: conn} do
2440 user = insert(:user, %{local: true})
2442 user2 = insert(:user, %{local: true})
2443 {:ok, _user2} = User.deactivate(user2, !user2.info.deactivated)
2445 insert(:user, %{local: false, nickname: "u@peer1.com"})
2446 insert(:user, %{local: false, nickname: "u@peer2.com"})
2448 {:ok, _} = TwitterAPI.create_status(user, %{"status" => "cofe"})
2450 # Stats should count users with missing or nil `info.deactivated` value
2451 user = User.get_cached_by_id(user.id)
2452 info_change = Changeset.change(user.info, %{deactivated: nil})
2456 |> Changeset.change()
2457 |> Changeset.put_embed(:info, info_change)
2458 |> User.update_and_set_cache()
2460 Pleroma.Stats.update_stats()
2462 conn = get(conn, "/api/v1/instance")
2464 assert result = json_response(conn, 200)
2466 stats = result["stats"]
2469 assert stats["user_count"] == 1
2470 assert stats["status_count"] == 1
2471 assert stats["domain_count"] == 2
2474 test "get peers", %{conn: conn} do
2475 insert(:user, %{local: false, nickname: "u@peer1.com"})
2476 insert(:user, %{local: false, nickname: "u@peer2.com"})
2478 Pleroma.Stats.update_stats()
2480 conn = get(conn, "/api/v1/instance/peers")
2482 assert result = json_response(conn, 200)
2484 assert ["peer1.com", "peer2.com"] == Enum.sort(result)
2487 test "put settings", %{conn: conn} do
2488 user = insert(:user)
2492 |> assign(:user, user)
2493 |> put("/api/web/settings", %{"data" => %{"programming" => "socks"}})
2495 assert _result = json_response(conn, 200)
2497 user = User.get_cached_by_ap_id(user.ap_id)
2498 assert user.info.settings == %{"programming" => "socks"}
2501 describe "pinned statuses" do
2503 Pleroma.Config.put([:instance, :max_pinned_statuses], 1)
2505 user = insert(:user)
2506 {:ok, activity} = CommonAPI.post(user, %{"status" => "HI!!!"})
2508 [user: user, activity: activity]
2511 test "returns pinned statuses", %{conn: conn, user: user, activity: activity} do
2512 {:ok, _} = CommonAPI.pin(activity.id, user)
2516 |> assign(:user, user)
2517 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
2518 |> json_response(200)
2520 id_str = to_string(activity.id)
2522 assert [%{"id" => ^id_str, "pinned" => true}] = result
2525 test "pin status", %{conn: conn, user: user, activity: activity} do
2526 id_str = to_string(activity.id)
2528 assert %{"id" => ^id_str, "pinned" => true} =
2530 |> assign(:user, user)
2531 |> post("/api/v1/statuses/#{activity.id}/pin")
2532 |> json_response(200)
2534 assert [%{"id" => ^id_str, "pinned" => true}] =
2536 |> assign(:user, user)
2537 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
2538 |> json_response(200)
2541 test "unpin status", %{conn: conn, user: user, activity: activity} do
2542 {:ok, _} = CommonAPI.pin(activity.id, user)
2544 id_str = to_string(activity.id)
2545 user = refresh_record(user)
2547 assert %{"id" => ^id_str, "pinned" => false} =
2549 |> assign(:user, user)
2550 |> post("/api/v1/statuses/#{activity.id}/unpin")
2551 |> json_response(200)
2555 |> assign(:user, user)
2556 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
2557 |> json_response(200)
2560 test "max pinned statuses", %{conn: conn, user: user, activity: activity_one} do
2561 {:ok, activity_two} = CommonAPI.post(user, %{"status" => "HI!!!"})
2563 id_str_one = to_string(activity_one.id)
2565 assert %{"id" => ^id_str_one, "pinned" => true} =
2567 |> assign(:user, user)
2568 |> post("/api/v1/statuses/#{id_str_one}/pin")
2569 |> json_response(200)
2571 user = refresh_record(user)
2573 assert %{"error" => "You have already pinned the maximum number of statuses"} =
2575 |> assign(:user, user)
2576 |> post("/api/v1/statuses/#{activity_two.id}/pin")
2577 |> json_response(400)
2580 test "Status rich-media Card", %{conn: conn, user: user} do
2581 Pleroma.Config.put([:rich_media, :enabled], true)
2582 {:ok, activity} = CommonAPI.post(user, %{"status" => "http://example.com/ogp"})
2586 |> get("/api/v1/statuses/#{activity.id}/card")
2587 |> json_response(200)
2589 assert response == %{
2590 "image" => "http://ia.media-imdb.com/images/rock.jpg",
2591 "provider_name" => "www.imdb.com",
2592 "provider_url" => "http://www.imdb.com",
2593 "title" => "The Rock",
2595 "url" => "http://www.imdb.com/title/tt0117500/",
2596 "description" => nil,
2599 "image" => "http://ia.media-imdb.com/images/rock.jpg",
2600 "title" => "The Rock",
2601 "type" => "video.movie",
2602 "url" => "http://www.imdb.com/title/tt0117500/"
2607 # works with private posts
2609 CommonAPI.post(user, %{"status" => "http://example.com/ogp", "visibility" => "direct"})
2613 |> assign(:user, user)
2614 |> get("/api/v1/statuses/#{activity.id}/card")
2615 |> json_response(200)
2617 assert response_two == response
2619 Pleroma.Config.put([:rich_media, :enabled], false)
2624 user = insert(:user)
2625 for_user = insert(:user)
2628 CommonAPI.post(user, %{
2629 "status" => "heweoo?"
2633 CommonAPI.post(user, %{
2634 "status" => "heweoo!"
2639 |> assign(:user, for_user)
2640 |> post("/api/v1/statuses/#{activity1.id}/bookmark")
2642 assert json_response(response1, 200)["bookmarked"] == true
2646 |> assign(:user, for_user)
2647 |> post("/api/v1/statuses/#{activity2.id}/bookmark")
2649 assert json_response(response2, 200)["bookmarked"] == true
2653 |> assign(:user, for_user)
2654 |> get("/api/v1/bookmarks")
2656 assert [json_response(response2, 200), json_response(response1, 200)] ==
2657 json_response(bookmarks, 200)
2661 |> assign(:user, for_user)
2662 |> post("/api/v1/statuses/#{activity1.id}/unbookmark")
2664 assert json_response(response1, 200)["bookmarked"] == false
2668 |> assign(:user, for_user)
2669 |> get("/api/v1/bookmarks")
2671 assert [json_response(response2, 200)] == json_response(bookmarks, 200)
2674 describe "conversation muting" do
2676 user = insert(:user)
2677 {:ok, activity} = CommonAPI.post(user, %{"status" => "HIE"})
2679 [user: user, activity: activity]
2682 test "mute conversation", %{conn: conn, user: user, activity: activity} do
2683 id_str = to_string(activity.id)
2685 assert %{"id" => ^id_str, "muted" => true} =
2687 |> assign(:user, user)
2688 |> post("/api/v1/statuses/#{activity.id}/mute")
2689 |> json_response(200)
2692 test "unmute conversation", %{conn: conn, user: user, activity: activity} do
2693 {:ok, _} = CommonAPI.add_mute(user, activity)
2695 id_str = to_string(activity.id)
2696 user = refresh_record(user)
2698 assert %{"id" => ^id_str, "muted" => false} =
2700 |> assign(:user, user)
2701 |> post("/api/v1/statuses/#{activity.id}/unmute")
2702 |> json_response(200)
2706 test "flavours switching (Pleroma Extension)", %{conn: conn} do
2707 user = insert(:user)
2711 |> assign(:user, user)
2712 |> get("/api/v1/pleroma/flavour")
2714 assert "glitch" == json_response(get_old_flavour, 200)
2718 |> assign(:user, user)
2719 |> post("/api/v1/pleroma/flavour/vanilla")
2721 assert "vanilla" == json_response(set_flavour, 200)
2725 |> assign(:user, user)
2726 |> post("/api/v1/pleroma/flavour/vanilla")
2728 assert json_response(set_flavour, 200) == json_response(get_new_flavour, 200)
2731 describe "reports" do
2733 reporter = insert(:user)
2734 target_user = insert(:user)
2736 {:ok, activity} = CommonAPI.post(target_user, %{"status" => "foobar"})
2738 [reporter: reporter, target_user: target_user, activity: activity]
2741 test "submit a basic report", %{conn: conn, reporter: reporter, target_user: target_user} do
2742 assert %{"action_taken" => false, "id" => _} =
2744 |> assign(:user, reporter)
2745 |> post("/api/v1/reports", %{"account_id" => target_user.id})
2746 |> json_response(200)
2749 test "submit a report with statuses and comment", %{
2752 target_user: target_user,
2755 assert %{"action_taken" => false, "id" => _} =
2757 |> assign(:user, reporter)
2758 |> post("/api/v1/reports", %{
2759 "account_id" => target_user.id,
2760 "status_ids" => [activity.id],
2761 "comment" => "bad status!"
2763 |> json_response(200)
2766 test "account_id is required", %{
2771 assert %{"error" => "Valid `account_id` required"} =
2773 |> assign(:user, reporter)
2774 |> post("/api/v1/reports", %{"status_ids" => [activity.id]})
2775 |> json_response(400)
2778 test "comment must be up to the size specified in the config", %{
2781 target_user: target_user
2783 max_size = Pleroma.Config.get([:instance, :max_report_comment_size], 1000)
2784 comment = String.pad_trailing("a", max_size + 1, "a")
2786 error = %{"error" => "Comment must be up to #{max_size} characters"}
2790 |> assign(:user, reporter)
2791 |> post("/api/v1/reports", %{"account_id" => target_user.id, "comment" => comment})
2792 |> json_response(400)
2796 describe "link headers" do
2797 test "preserves parameters in link headers", %{conn: conn} do
2798 user = insert(:user)
2799 other_user = insert(:user)
2802 CommonAPI.post(other_user, %{
2803 "status" => "hi @#{user.nickname}",
2804 "visibility" => "public"
2808 CommonAPI.post(other_user, %{
2809 "status" => "hi @#{user.nickname}",
2810 "visibility" => "public"
2813 notification1 = Repo.get_by(Notification, activity_id: activity1.id)
2814 notification2 = Repo.get_by(Notification, activity_id: activity2.id)
2818 |> assign(:user, user)
2819 |> get("/api/v1/notifications", %{media_only: true})
2821 assert [link_header] = get_resp_header(conn, "link")
2822 assert link_header =~ ~r/media_only=true/
2823 assert link_header =~ ~r/min_id=#{notification2.id}/
2824 assert link_header =~ ~r/max_id=#{notification1.id}/
2828 test "accounts fetches correct account for nicknames beginning with numbers", %{conn: conn} do
2829 # Need to set an old-style integer ID to reproduce the problem
2830 # (these are no longer assigned to new accounts but were preserved
2831 # for existing accounts during the migration to flakeIDs)
2832 user_one = insert(:user, %{id: 1212})
2833 user_two = insert(:user, %{nickname: "#{user_one.id}garbage"})
2837 |> get("/api/v1/accounts/#{user_one.id}")
2841 |> get("/api/v1/accounts/#{user_two.nickname}")
2845 |> get("/api/v1/accounts/#{user_two.id}")
2847 acc_one = json_response(resp_one, 200)
2848 acc_two = json_response(resp_two, 200)
2849 acc_three = json_response(resp_three, 200)
2850 refute acc_one == acc_two
2851 assert acc_two == acc_three
2854 describe "custom emoji" do
2855 test "with tags", %{conn: conn} do
2858 |> get("/api/v1/custom_emojis")
2859 |> json_response(200)
2861 assert Map.has_key?(emoji, "shortcode")
2862 assert Map.has_key?(emoji, "static_url")
2863 assert Map.has_key?(emoji, "tags")
2864 assert is_list(emoji["tags"])
2865 assert Map.has_key?(emoji, "url")
2866 assert Map.has_key?(emoji, "visible_in_picker")
2870 describe "index/2 redirections" do
2871 setup %{conn: conn} do
2875 signing_salt: "cooldude"
2880 |> Plug.Session.call(Plug.Session.init(session_opts))
2883 test_path = "/web/statuses/test"
2884 %{conn: conn, path: test_path}
2887 test "redirects not logged-in users to the login page", %{conn: conn, path: path} do
2888 conn = get(conn, path)
2890 assert conn.status == 302
2891 assert redirected_to(conn) == "/web/login"
2894 test "does not redirect logged in users to the login page", %{conn: conn, path: path} do
2895 token = insert(:oauth_token)
2899 |> assign(:user, token.user)
2900 |> put_session(:oauth_token, token.token)
2903 assert conn.status == 200
2906 test "saves referer path to session", %{conn: conn, path: path} do
2907 conn = get(conn, path)
2908 return_to = Plug.Conn.get_session(conn, :return_to)
2910 assert return_to == path
2913 test "redirects to the saved path after log in", %{conn: conn, path: path} do
2914 app = insert(:oauth_app, client_name: "Mastodon-Local", redirect_uris: ".")
2915 auth = insert(:oauth_authorization, app: app)
2919 |> put_session(:return_to, path)
2920 |> get("/web/login", %{code: auth.token})
2922 assert conn.status == 302
2923 assert redirected_to(conn) == path
2926 test "redirects to the getting-started page when referer is not present", %{conn: conn} do
2927 app = insert(:oauth_app, client_name: "Mastodon-Local", redirect_uris: ".")
2928 auth = insert(:oauth_authorization, app: app)
2930 conn = get(conn, "/web/login", %{code: auth.token})
2932 assert conn.status == 302
2933 assert redirected_to(conn) == "/web/getting-started"
2937 describe "scheduled activities" do
2938 test "creates a scheduled activity", %{conn: conn} do
2939 user = insert(:user)
2940 scheduled_at = NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond)
2944 |> assign(:user, user)
2945 |> post("/api/v1/statuses", %{
2946 "status" => "scheduled",
2947 "scheduled_at" => scheduled_at
2950 assert %{"scheduled_at" => expected_scheduled_at} = json_response(conn, 200)
2951 assert expected_scheduled_at == Pleroma.Web.CommonAPI.Utils.to_masto_date(scheduled_at)
2952 assert [] == Repo.all(Activity)
2955 test "creates a scheduled activity with a media attachment", %{conn: conn} do
2956 user = insert(:user)
2957 scheduled_at = NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond)
2959 file = %Plug.Upload{
2960 content_type: "image/jpg",
2961 path: Path.absname("test/fixtures/image.jpg"),
2962 filename: "an_image.jpg"
2965 {:ok, upload} = ActivityPub.upload(file, actor: user.ap_id)
2969 |> assign(:user, user)
2970 |> post("/api/v1/statuses", %{
2971 "media_ids" => [to_string(upload.id)],
2972 "status" => "scheduled",
2973 "scheduled_at" => scheduled_at
2976 assert %{"media_attachments" => [media_attachment]} = json_response(conn, 200)
2977 assert %{"type" => "image"} = media_attachment
2980 test "skips the scheduling and creates the activity if scheduled_at is earlier than 5 minutes from now",
2982 user = insert(:user)
2985 NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(5) - 1, :millisecond)
2989 |> assign(:user, user)
2990 |> post("/api/v1/statuses", %{
2991 "status" => "not scheduled",
2992 "scheduled_at" => scheduled_at
2995 assert %{"content" => "not scheduled"} = json_response(conn, 200)
2996 assert [] == Repo.all(ScheduledActivity)
2999 test "returns error when daily user limit is exceeded", %{conn: conn} do
3000 user = insert(:user)
3003 NaiveDateTime.utc_now()
3004 |> NaiveDateTime.add(:timer.minutes(6), :millisecond)
3005 |> NaiveDateTime.to_iso8601()
3007 attrs = %{params: %{}, scheduled_at: today}
3008 {:ok, _} = ScheduledActivity.create(user, attrs)
3009 {:ok, _} = ScheduledActivity.create(user, attrs)
3013 |> assign(:user, user)
3014 |> post("/api/v1/statuses", %{"status" => "scheduled", "scheduled_at" => today})
3016 assert %{"error" => "daily limit exceeded"} == json_response(conn, 422)
3019 test "returns error when total user limit is exceeded", %{conn: conn} do
3020 user = insert(:user)
3023 NaiveDateTime.utc_now()
3024 |> NaiveDateTime.add(:timer.minutes(6), :millisecond)
3025 |> NaiveDateTime.to_iso8601()
3028 NaiveDateTime.utc_now()
3029 |> NaiveDateTime.add(:timer.hours(36), :millisecond)
3030 |> NaiveDateTime.to_iso8601()
3032 attrs = %{params: %{}, scheduled_at: today}
3033 {:ok, _} = ScheduledActivity.create(user, attrs)
3034 {:ok, _} = ScheduledActivity.create(user, attrs)
3035 {:ok, _} = ScheduledActivity.create(user, %{params: %{}, scheduled_at: tomorrow})
3039 |> assign(:user, user)
3040 |> post("/api/v1/statuses", %{"status" => "scheduled", "scheduled_at" => tomorrow})
3042 assert %{"error" => "total limit exceeded"} == json_response(conn, 422)
3045 test "shows scheduled activities", %{conn: conn} do
3046 user = insert(:user)
3047 scheduled_activity_id1 = insert(:scheduled_activity, user: user).id |> to_string()
3048 scheduled_activity_id2 = insert(:scheduled_activity, user: user).id |> to_string()
3049 scheduled_activity_id3 = insert(:scheduled_activity, user: user).id |> to_string()
3050 scheduled_activity_id4 = insert(:scheduled_activity, user: user).id |> to_string()
3054 |> assign(:user, user)
3059 |> get("/api/v1/scheduled_statuses?limit=2&min_id=#{scheduled_activity_id1}")
3061 result = json_response(conn_res, 200)
3062 assert [%{"id" => ^scheduled_activity_id3}, %{"id" => ^scheduled_activity_id2}] = result
3067 |> get("/api/v1/scheduled_statuses?limit=2&since_id=#{scheduled_activity_id1}")
3069 result = json_response(conn_res, 200)
3070 assert [%{"id" => ^scheduled_activity_id4}, %{"id" => ^scheduled_activity_id3}] = result
3075 |> get("/api/v1/scheduled_statuses?limit=2&max_id=#{scheduled_activity_id4}")
3077 result = json_response(conn_res, 200)
3078 assert [%{"id" => ^scheduled_activity_id3}, %{"id" => ^scheduled_activity_id2}] = result
3081 test "shows a scheduled activity", %{conn: conn} do
3082 user = insert(:user)
3083 scheduled_activity = insert(:scheduled_activity, user: user)
3087 |> assign(:user, user)
3088 |> get("/api/v1/scheduled_statuses/#{scheduled_activity.id}")
3090 assert %{"id" => scheduled_activity_id} = json_response(res_conn, 200)
3091 assert scheduled_activity_id == scheduled_activity.id |> to_string()
3095 |> assign(:user, user)
3096 |> get("/api/v1/scheduled_statuses/404")
3098 assert %{"error" => "Record not found"} = json_response(res_conn, 404)
3101 test "updates a scheduled activity", %{conn: conn} do
3102 user = insert(:user)
3103 scheduled_activity = insert(:scheduled_activity, user: user)
3106 NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond)
3110 |> assign(:user, user)
3111 |> put("/api/v1/scheduled_statuses/#{scheduled_activity.id}", %{
3112 scheduled_at: new_scheduled_at
3115 assert %{"scheduled_at" => expected_scheduled_at} = json_response(res_conn, 200)
3116 assert expected_scheduled_at == Pleroma.Web.CommonAPI.Utils.to_masto_date(new_scheduled_at)
3120 |> assign(:user, user)
3121 |> put("/api/v1/scheduled_statuses/404", %{scheduled_at: new_scheduled_at})
3123 assert %{"error" => "Record not found"} = json_response(res_conn, 404)
3126 test "deletes a scheduled activity", %{conn: conn} do
3127 user = insert(:user)
3128 scheduled_activity = insert(:scheduled_activity, user: user)
3132 |> assign(:user, user)
3133 |> delete("/api/v1/scheduled_statuses/#{scheduled_activity.id}")
3135 assert %{} = json_response(res_conn, 200)
3136 assert nil == Repo.get(ScheduledActivity, scheduled_activity.id)
3140 |> assign(:user, user)
3141 |> delete("/api/v1/scheduled_statuses/#{scheduled_activity.id}")
3143 assert %{"error" => "Record not found"} = json_response(res_conn, 404)
3147 test "Repeated posts that are replies incorrectly have in_reply_to_id null", %{conn: conn} do
3148 user1 = insert(:user)
3149 user2 = insert(:user)
3150 user3 = insert(:user)
3152 {:ok, replied_to} = TwitterAPI.create_status(user1, %{"status" => "cofe"})
3154 # Reply to status from another user
3157 |> assign(:user, user2)
3158 |> post("/api/v1/statuses", %{"status" => "xD", "in_reply_to_id" => replied_to.id})
3160 assert %{"content" => "xD", "id" => id} = json_response(conn1, 200)
3162 activity = Activity.get_by_id_with_object(id)
3164 assert Object.normalize(activity).data["inReplyTo"] == Object.normalize(replied_to).data["id"]
3165 assert Activity.get_in_reply_to_activity(activity).id == replied_to.id
3167 # Reblog from the third user
3170 |> assign(:user, user3)
3171 |> post("/api/v1/statuses/#{activity.id}/reblog")
3173 assert %{"reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 1}} =
3174 json_response(conn2, 200)
3176 assert to_string(activity.id) == id
3178 # Getting third user status
3181 |> assign(:user, user3)
3182 |> get("api/v1/timelines/home")
3184 [reblogged_activity] = json_response(conn3, 200)
3186 assert reblogged_activity["reblog"]["in_reply_to_id"] == replied_to.id
3188 replied_to_user = User.get_by_ap_id(replied_to.data["actor"])
3189 assert reblogged_activity["reblog"]["in_reply_to_account_id"] == replied_to_user.id