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["irreversible"] == false
576 assert response["id"] != nil
577 assert response["id"] != ""
580 test "fetching a list of filters", %{conn: conn} do
583 query_one = %Pleroma.Filter{
590 query_two = %Pleroma.Filter{
597 {:ok, filter_one} = Pleroma.Filter.create(query_one)
598 {:ok, filter_two} = Pleroma.Filter.create(query_two)
602 |> assign(:user, user)
603 |> get("/api/v1/filters")
604 |> json_response(200)
610 filters: [filter_two, filter_one]
614 test "get a filter", %{conn: conn} do
617 query = %Pleroma.Filter{
624 {:ok, filter} = Pleroma.Filter.create(query)
628 |> assign(:user, user)
629 |> get("/api/v1/filters/#{filter.filter_id}")
631 assert _response = json_response(conn, 200)
634 test "update a filter", %{conn: conn} do
637 query = %Pleroma.Filter{
644 {:ok, _filter} = Pleroma.Filter.create(query)
646 new = %Pleroma.Filter{
653 |> assign(:user, user)
654 |> put("/api/v1/filters/#{query.filter_id}", %{
659 assert response = json_response(conn, 200)
660 assert response["phrase"] == new.phrase
661 assert response["context"] == new.context
664 test "delete a filter", %{conn: conn} do
667 query = %Pleroma.Filter{
674 {:ok, filter} = Pleroma.Filter.create(query)
678 |> assign(:user, user)
679 |> delete("/api/v1/filters/#{filter.filter_id}")
681 assert response = json_response(conn, 200)
682 assert response == %{}
687 test "creating a list", %{conn: conn} do
692 |> assign(:user, user)
693 |> post("/api/v1/lists", %{"title" => "cuties"})
695 assert %{"title" => title} = json_response(conn, 200)
696 assert title == "cuties"
699 test "adding users to a list", %{conn: conn} do
701 other_user = insert(:user)
702 {:ok, list} = Pleroma.List.create("name", user)
706 |> assign(:user, user)
707 |> post("/api/v1/lists/#{list.id}/accounts", %{"account_ids" => [other_user.id]})
709 assert %{} == json_response(conn, 200)
710 %Pleroma.List{following: following} = Pleroma.List.get(list.id, user)
711 assert following == [other_user.follower_address]
714 test "removing users from a list", %{conn: conn} do
716 other_user = insert(:user)
717 third_user = insert(:user)
718 {:ok, list} = Pleroma.List.create("name", user)
719 {:ok, list} = Pleroma.List.follow(list, other_user)
720 {:ok, list} = Pleroma.List.follow(list, third_user)
724 |> assign(:user, user)
725 |> delete("/api/v1/lists/#{list.id}/accounts", %{"account_ids" => [other_user.id]})
727 assert %{} == json_response(conn, 200)
728 %Pleroma.List{following: following} = Pleroma.List.get(list.id, user)
729 assert following == [third_user.follower_address]
732 test "listing users in a list", %{conn: conn} do
734 other_user = insert(:user)
735 {:ok, list} = Pleroma.List.create("name", user)
736 {:ok, list} = Pleroma.List.follow(list, other_user)
740 |> assign(:user, user)
741 |> get("/api/v1/lists/#{list.id}/accounts", %{"account_ids" => [other_user.id]})
743 assert [%{"id" => id}] = json_response(conn, 200)
744 assert id == to_string(other_user.id)
747 test "retrieving a list", %{conn: conn} do
749 {:ok, list} = Pleroma.List.create("name", user)
753 |> assign(:user, user)
754 |> get("/api/v1/lists/#{list.id}")
756 assert %{"id" => id} = json_response(conn, 200)
757 assert id == to_string(list.id)
760 test "renaming a list", %{conn: conn} do
762 {:ok, list} = Pleroma.List.create("name", user)
766 |> assign(:user, user)
767 |> put("/api/v1/lists/#{list.id}", %{"title" => "newname"})
769 assert %{"title" => name} = json_response(conn, 200)
770 assert name == "newname"
773 test "deleting a list", %{conn: conn} do
775 {:ok, list} = Pleroma.List.create("name", user)
779 |> assign(:user, user)
780 |> delete("/api/v1/lists/#{list.id}")
782 assert %{} = json_response(conn, 200)
783 assert is_nil(Repo.get(Pleroma.List, list.id))
786 test "list timeline", %{conn: conn} do
788 other_user = insert(:user)
789 {:ok, _activity_one} = TwitterAPI.create_status(user, %{"status" => "Marisa is cute."})
790 {:ok, activity_two} = TwitterAPI.create_status(other_user, %{"status" => "Marisa is cute."})
791 {:ok, list} = Pleroma.List.create("name", user)
792 {:ok, list} = Pleroma.List.follow(list, other_user)
796 |> assign(:user, user)
797 |> get("/api/v1/timelines/list/#{list.id}")
799 assert [%{"id" => id}] = json_response(conn, 200)
801 assert id == to_string(activity_two.id)
804 test "list timeline does not leak non-public statuses for unfollowed users", %{conn: conn} do
806 other_user = insert(:user)
807 {:ok, activity_one} = TwitterAPI.create_status(other_user, %{"status" => "Marisa is cute."})
809 {:ok, _activity_two} =
810 TwitterAPI.create_status(other_user, %{
811 "status" => "Marisa is cute.",
812 "visibility" => "private"
815 {:ok, list} = Pleroma.List.create("name", user)
816 {:ok, list} = Pleroma.List.follow(list, other_user)
820 |> assign(:user, user)
821 |> get("/api/v1/timelines/list/#{list.id}")
823 assert [%{"id" => id}] = json_response(conn, 200)
825 assert id == to_string(activity_one.id)
829 describe "notifications" do
830 test "list of notifications", %{conn: conn} do
832 other_user = insert(:user)
835 TwitterAPI.create_status(other_user, %{"status" => "hi @#{user.nickname}"})
837 {:ok, [_notification]} = Notification.create_notifications(activity)
841 |> assign(:user, user)
842 |> get("/api/v1/notifications")
845 "hi <span class=\"h-card\"><a data-user=\"#{user.id}\" class=\"u-url mention\" href=\"#{
847 }\">@<span>#{user.nickname}</span></a></span>"
849 assert [%{"status" => %{"content" => response}} | _rest] = json_response(conn, 200)
850 assert response == expected_response
853 test "getting a single notification", %{conn: conn} do
855 other_user = insert(:user)
858 TwitterAPI.create_status(other_user, %{"status" => "hi @#{user.nickname}"})
860 {:ok, [notification]} = Notification.create_notifications(activity)
864 |> assign(:user, user)
865 |> get("/api/v1/notifications/#{notification.id}")
868 "hi <span class=\"h-card\"><a data-user=\"#{user.id}\" class=\"u-url mention\" href=\"#{
870 }\">@<span>#{user.nickname}</span></a></span>"
872 assert %{"status" => %{"content" => response}} = json_response(conn, 200)
873 assert response == expected_response
876 test "dismissing a single notification", %{conn: conn} do
878 other_user = insert(:user)
881 TwitterAPI.create_status(other_user, %{"status" => "hi @#{user.nickname}"})
883 {:ok, [notification]} = Notification.create_notifications(activity)
887 |> assign(:user, user)
888 |> post("/api/v1/notifications/dismiss", %{"id" => notification.id})
890 assert %{} = json_response(conn, 200)
893 test "clearing all notifications", %{conn: conn} do
895 other_user = insert(:user)
898 TwitterAPI.create_status(other_user, %{"status" => "hi @#{user.nickname}"})
900 {:ok, [_notification]} = Notification.create_notifications(activity)
904 |> assign(:user, user)
905 |> post("/api/v1/notifications/clear")
907 assert %{} = json_response(conn, 200)
911 |> assign(:user, user)
912 |> get("/api/v1/notifications")
914 assert all = json_response(conn, 200)
918 test "paginates notifications using min_id, since_id, max_id, and limit", %{conn: conn} do
920 other_user = insert(:user)
922 {:ok, activity1} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
923 {:ok, activity2} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
924 {:ok, activity3} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
925 {:ok, activity4} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
927 notification1_id = Repo.get_by(Notification, activity_id: activity1.id).id |> to_string()
928 notification2_id = Repo.get_by(Notification, activity_id: activity2.id).id |> to_string()
929 notification3_id = Repo.get_by(Notification, activity_id: activity3.id).id |> to_string()
930 notification4_id = Repo.get_by(Notification, activity_id: activity4.id).id |> to_string()
934 |> assign(:user, user)
939 |> get("/api/v1/notifications?limit=2&min_id=#{notification1_id}")
941 result = json_response(conn_res, 200)
942 assert [%{"id" => ^notification3_id}, %{"id" => ^notification2_id}] = result
947 |> get("/api/v1/notifications?limit=2&since_id=#{notification1_id}")
949 result = json_response(conn_res, 200)
950 assert [%{"id" => ^notification4_id}, %{"id" => ^notification3_id}] = result
955 |> get("/api/v1/notifications?limit=2&max_id=#{notification4_id}")
957 result = json_response(conn_res, 200)
958 assert [%{"id" => ^notification3_id}, %{"id" => ^notification2_id}] = result
961 test "filters notifications using exclude_types", %{conn: conn} do
963 other_user = insert(:user)
965 {:ok, mention_activity} = CommonAPI.post(other_user, %{"status" => "hey @#{user.nickname}"})
966 {:ok, create_activity} = CommonAPI.post(user, %{"status" => "hey"})
967 {:ok, favorite_activity, _} = CommonAPI.favorite(create_activity.id, other_user)
968 {:ok, reblog_activity, _} = CommonAPI.repeat(create_activity.id, other_user)
969 {:ok, _, _, follow_activity} = CommonAPI.follow(other_user, user)
971 mention_notification_id =
972 Repo.get_by(Notification, activity_id: mention_activity.id).id |> to_string()
974 favorite_notification_id =
975 Repo.get_by(Notification, activity_id: favorite_activity.id).id |> to_string()
977 reblog_notification_id =
978 Repo.get_by(Notification, activity_id: reblog_activity.id).id |> to_string()
980 follow_notification_id =
981 Repo.get_by(Notification, activity_id: follow_activity.id).id |> to_string()
985 |> assign(:user, user)
988 get(conn, "/api/v1/notifications", %{exclude_types: ["mention", "favourite", "reblog"]})
990 assert [%{"id" => ^follow_notification_id}] = json_response(conn_res, 200)
993 get(conn, "/api/v1/notifications", %{exclude_types: ["favourite", "reblog", "follow"]})
995 assert [%{"id" => ^mention_notification_id}] = json_response(conn_res, 200)
998 get(conn, "/api/v1/notifications", %{exclude_types: ["reblog", "follow", "mention"]})
1000 assert [%{"id" => ^favorite_notification_id}] = json_response(conn_res, 200)
1003 get(conn, "/api/v1/notifications", %{exclude_types: ["follow", "mention", "favourite"]})
1005 assert [%{"id" => ^reblog_notification_id}] = json_response(conn_res, 200)
1008 test "destroy multiple", %{conn: conn} do
1009 user = insert(:user)
1010 other_user = insert(:user)
1012 {:ok, activity1} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
1013 {:ok, activity2} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
1014 {:ok, activity3} = CommonAPI.post(user, %{"status" => "hi @#{other_user.nickname}"})
1015 {:ok, activity4} = CommonAPI.post(user, %{"status" => "hi @#{other_user.nickname}"})
1017 notification1_id = Repo.get_by(Notification, activity_id: activity1.id).id |> to_string()
1018 notification2_id = Repo.get_by(Notification, activity_id: activity2.id).id |> to_string()
1019 notification3_id = Repo.get_by(Notification, activity_id: activity3.id).id |> to_string()
1020 notification4_id = Repo.get_by(Notification, activity_id: activity4.id).id |> to_string()
1024 |> assign(:user, user)
1028 |> get("/api/v1/notifications")
1030 result = json_response(conn_res, 200)
1031 assert [%{"id" => ^notification2_id}, %{"id" => ^notification1_id}] = result
1035 |> assign(:user, other_user)
1039 |> get("/api/v1/notifications")
1041 result = json_response(conn_res, 200)
1042 assert [%{"id" => ^notification4_id}, %{"id" => ^notification3_id}] = result
1046 |> delete("/api/v1/notifications/destroy_multiple", %{
1047 "ids" => [notification1_id, notification2_id]
1050 assert json_response(conn_destroy, 200) == %{}
1054 |> get("/api/v1/notifications")
1056 result = json_response(conn_res, 200)
1057 assert [%{"id" => ^notification4_id}, %{"id" => ^notification3_id}] = result
1061 describe "reblogging" do
1062 test "reblogs and returns the reblogged status", %{conn: conn} do
1063 activity = insert(:note_activity)
1064 user = insert(:user)
1068 |> assign(:user, user)
1069 |> post("/api/v1/statuses/#{activity.id}/reblog")
1072 "reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 1},
1074 } = json_response(conn, 200)
1076 assert to_string(activity.id) == id
1079 test "reblogged status for another user", %{conn: conn} do
1080 activity = insert(:note_activity)
1081 user1 = insert(:user)
1082 user2 = insert(:user)
1083 user3 = insert(:user)
1084 CommonAPI.favorite(activity.id, user2)
1085 {:ok, _bookmark} = Pleroma.Bookmark.create(user2.id, activity.id)
1086 {:ok, reblog_activity1, _object} = CommonAPI.repeat(activity.id, user1)
1087 {:ok, _, _object} = CommonAPI.repeat(activity.id, user2)
1091 |> assign(:user, user3)
1092 |> get("/api/v1/statuses/#{reblog_activity1.id}")
1095 "reblog" => %{"id" => id, "reblogged" => false, "reblogs_count" => 2},
1096 "reblogged" => false,
1097 "favourited" => false,
1098 "bookmarked" => false
1099 } = json_response(conn_res, 200)
1103 |> assign(:user, user2)
1104 |> get("/api/v1/statuses/#{reblog_activity1.id}")
1107 "reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 2},
1108 "reblogged" => true,
1109 "favourited" => true,
1110 "bookmarked" => true
1111 } = json_response(conn_res, 200)
1113 assert to_string(activity.id) == id
1117 describe "unreblogging" do
1118 test "unreblogs and returns the unreblogged status", %{conn: conn} do
1119 activity = insert(:note_activity)
1120 user = insert(:user)
1122 {:ok, _, _} = CommonAPI.repeat(activity.id, user)
1126 |> assign(:user, user)
1127 |> post("/api/v1/statuses/#{activity.id}/unreblog")
1129 assert %{"id" => id, "reblogged" => false, "reblogs_count" => 0} = json_response(conn, 200)
1131 assert to_string(activity.id) == id
1135 describe "favoriting" do
1136 test "favs a status and returns it", %{conn: conn} do
1137 activity = insert(:note_activity)
1138 user = insert(:user)
1142 |> assign(:user, user)
1143 |> post("/api/v1/statuses/#{activity.id}/favourite")
1145 assert %{"id" => id, "favourites_count" => 1, "favourited" => true} =
1146 json_response(conn, 200)
1148 assert to_string(activity.id) == id
1151 test "returns 500 for a wrong id", %{conn: conn} do
1152 user = insert(:user)
1156 |> assign(:user, user)
1157 |> post("/api/v1/statuses/1/favourite")
1158 |> json_response(500)
1160 assert resp == "Something went wrong"
1164 describe "unfavoriting" do
1165 test "unfavorites a status and returns it", %{conn: conn} do
1166 activity = insert(:note_activity)
1167 user = insert(:user)
1169 {:ok, _, _} = CommonAPI.favorite(activity.id, user)
1173 |> assign(:user, user)
1174 |> post("/api/v1/statuses/#{activity.id}/unfavourite")
1176 assert %{"id" => id, "favourites_count" => 0, "favourited" => false} =
1177 json_response(conn, 200)
1179 assert to_string(activity.id) == id
1183 describe "user timelines" do
1184 test "gets a users statuses", %{conn: conn} do
1185 user_one = insert(:user)
1186 user_two = insert(:user)
1187 user_three = insert(:user)
1189 {:ok, user_three} = User.follow(user_three, user_one)
1191 {:ok, activity} = CommonAPI.post(user_one, %{"status" => "HI!!!"})
1193 {:ok, direct_activity} =
1194 CommonAPI.post(user_one, %{
1195 "status" => "Hi, @#{user_two.nickname}.",
1196 "visibility" => "direct"
1199 {:ok, private_activity} =
1200 CommonAPI.post(user_one, %{"status" => "private", "visibility" => "private"})
1204 |> get("/api/v1/accounts/#{user_one.id}/statuses")
1206 assert [%{"id" => id}] = json_response(resp, 200)
1207 assert id == to_string(activity.id)
1211 |> assign(:user, user_two)
1212 |> get("/api/v1/accounts/#{user_one.id}/statuses")
1214 assert [%{"id" => id_one}, %{"id" => id_two}] = json_response(resp, 200)
1215 assert id_one == to_string(direct_activity.id)
1216 assert id_two == to_string(activity.id)
1220 |> assign(:user, user_three)
1221 |> get("/api/v1/accounts/#{user_one.id}/statuses")
1223 assert [%{"id" => id_one}, %{"id" => id_two}] = json_response(resp, 200)
1224 assert id_one == to_string(private_activity.id)
1225 assert id_two == to_string(activity.id)
1228 test "unimplemented pinned statuses feature", %{conn: conn} do
1229 note = insert(:note_activity)
1230 user = User.get_cached_by_ap_id(note.data["actor"])
1234 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
1236 assert json_response(conn, 200) == []
1239 test "gets an users media", %{conn: conn} do
1240 note = insert(:note_activity)
1241 user = User.get_cached_by_ap_id(note.data["actor"])
1243 file = %Plug.Upload{
1244 content_type: "image/jpg",
1245 path: Path.absname("test/fixtures/image.jpg"),
1246 filename: "an_image.jpg"
1250 TwitterAPI.upload(file, user, "json")
1254 TwitterAPI.create_status(user, %{"status" => "cofe", "media_ids" => [media["media_id"]]})
1258 |> get("/api/v1/accounts/#{user.id}/statuses", %{"only_media" => "true"})
1260 assert [%{"id" => id}] = json_response(conn, 200)
1261 assert id == to_string(image_post.id)
1265 |> get("/api/v1/accounts/#{user.id}/statuses", %{"only_media" => "1"})
1267 assert [%{"id" => id}] = json_response(conn, 200)
1268 assert id == to_string(image_post.id)
1271 test "gets a user's statuses without reblogs", %{conn: conn} do
1272 user = insert(:user)
1273 {:ok, post} = CommonAPI.post(user, %{"status" => "HI!!!"})
1274 {:ok, _, _} = CommonAPI.repeat(post.id, user)
1278 |> get("/api/v1/accounts/#{user.id}/statuses", %{"exclude_reblogs" => "true"})
1280 assert [%{"id" => id}] = json_response(conn, 200)
1281 assert id == to_string(post.id)
1285 |> get("/api/v1/accounts/#{user.id}/statuses", %{"exclude_reblogs" => "1"})
1287 assert [%{"id" => id}] = json_response(conn, 200)
1288 assert id == to_string(post.id)
1292 describe "user relationships" do
1293 test "returns the relationships for the current user", %{conn: conn} do
1294 user = insert(:user)
1295 other_user = insert(:user)
1296 {:ok, user} = User.follow(user, other_user)
1300 |> assign(:user, user)
1301 |> get("/api/v1/accounts/relationships", %{"id" => [other_user.id]})
1303 assert [relationship] = json_response(conn, 200)
1305 assert to_string(other_user.id) == relationship["id"]
1309 describe "locked accounts" do
1310 test "/api/v1/follow_requests works" do
1311 user = insert(:user, %{info: %Pleroma.User.Info{locked: true}})
1312 other_user = insert(:user)
1314 {:ok, _activity} = ActivityPub.follow(other_user, user)
1316 user = User.get_cached_by_id(user.id)
1317 other_user = User.get_cached_by_id(other_user.id)
1319 assert User.following?(other_user, user) == false
1323 |> assign(:user, user)
1324 |> get("/api/v1/follow_requests")
1326 assert [relationship] = json_response(conn, 200)
1327 assert to_string(other_user.id) == relationship["id"]
1330 test "/api/v1/follow_requests/:id/authorize works" do
1331 user = insert(:user, %{info: %User.Info{locked: true}})
1332 other_user = insert(:user)
1334 {:ok, _activity} = ActivityPub.follow(other_user, user)
1336 user = User.get_cached_by_id(user.id)
1337 other_user = User.get_cached_by_id(other_user.id)
1339 assert User.following?(other_user, user) == false
1343 |> assign(:user, user)
1344 |> post("/api/v1/follow_requests/#{other_user.id}/authorize")
1346 assert relationship = json_response(conn, 200)
1347 assert to_string(other_user.id) == relationship["id"]
1349 user = User.get_cached_by_id(user.id)
1350 other_user = User.get_cached_by_id(other_user.id)
1352 assert User.following?(other_user, user) == true
1355 test "verify_credentials", %{conn: conn} do
1356 user = insert(:user, %{info: %Pleroma.User.Info{default_scope: "private"}})
1360 |> assign(:user, user)
1361 |> get("/api/v1/accounts/verify_credentials")
1363 assert %{"id" => id, "source" => %{"privacy" => "private"}} = json_response(conn, 200)
1364 assert id == to_string(user.id)
1367 test "/api/v1/follow_requests/:id/reject works" do
1368 user = insert(:user, %{info: %Pleroma.User.Info{locked: true}})
1369 other_user = insert(:user)
1371 {:ok, _activity} = ActivityPub.follow(other_user, user)
1373 user = User.get_cached_by_id(user.id)
1377 |> assign(:user, user)
1378 |> post("/api/v1/follow_requests/#{other_user.id}/reject")
1380 assert relationship = json_response(conn, 200)
1381 assert to_string(other_user.id) == relationship["id"]
1383 user = User.get_cached_by_id(user.id)
1384 other_user = User.get_cached_by_id(other_user.id)
1386 assert User.following?(other_user, user) == false
1390 test "account fetching", %{conn: conn} do
1391 user = insert(:user)
1395 |> get("/api/v1/accounts/#{user.id}")
1397 assert %{"id" => id} = json_response(conn, 200)
1398 assert id == to_string(user.id)
1402 |> get("/api/v1/accounts/-1")
1404 assert %{"error" => "Can't find user"} = json_response(conn, 404)
1407 test "account fetching also works nickname", %{conn: conn} do
1408 user = insert(:user)
1412 |> get("/api/v1/accounts/#{user.nickname}")
1414 assert %{"id" => id} = json_response(conn, 200)
1415 assert id == user.id
1418 test "media upload", %{conn: conn} do
1419 file = %Plug.Upload{
1420 content_type: "image/jpg",
1421 path: Path.absname("test/fixtures/image.jpg"),
1422 filename: "an_image.jpg"
1425 desc = "Description of the image"
1427 user = insert(:user)
1431 |> assign(:user, user)
1432 |> post("/api/v1/media", %{"file" => file, "description" => desc})
1434 assert media = json_response(conn, 200)
1436 assert media["type"] == "image"
1437 assert media["description"] == desc
1440 object = Repo.get(Object, media["id"])
1441 assert object.data["actor"] == User.ap_id(user)
1444 test "hashtag timeline", %{conn: conn} do
1445 following = insert(:user)
1448 {:ok, activity} = TwitterAPI.create_status(following, %{"status" => "test #2hu"})
1450 {:ok, [_activity]} =
1451 OStatus.fetch_activity_from_url("https://shitposter.club/notice/2827873")
1455 |> get("/api/v1/timelines/tag/2hu")
1457 assert [%{"id" => id}] = json_response(nconn, 200)
1459 assert id == to_string(activity.id)
1461 # works for different capitalization too
1464 |> get("/api/v1/timelines/tag/2HU")
1466 assert [%{"id" => id}] = json_response(nconn, 200)
1468 assert id == to_string(activity.id)
1472 test "multi-hashtag timeline", %{conn: conn} do
1473 user = insert(:user)
1475 {:ok, activity_test} = CommonAPI.post(user, %{"status" => "#test"})
1476 {:ok, activity_test1} = CommonAPI.post(user, %{"status" => "#test #test1"})
1477 {:ok, activity_none} = CommonAPI.post(user, %{"status" => "#test #none"})
1481 |> get("/api/v1/timelines/tag/test", %{"any" => ["test1"]})
1483 [status_none, status_test1, status_test] = json_response(any_test, 200)
1485 assert to_string(activity_test.id) == status_test["id"]
1486 assert to_string(activity_test1.id) == status_test1["id"]
1487 assert to_string(activity_none.id) == status_none["id"]
1491 |> get("/api/v1/timelines/tag/test", %{"all" => ["test1"], "none" => ["none"]})
1493 assert [status_test1] == json_response(restricted_test, 200)
1495 all_test = conn |> get("/api/v1/timelines/tag/test", %{"all" => ["none"]})
1497 assert [status_none] == json_response(all_test, 200)
1500 test "getting followers", %{conn: conn} do
1501 user = insert(:user)
1502 other_user = insert(:user)
1503 {:ok, user} = User.follow(user, other_user)
1507 |> get("/api/v1/accounts/#{other_user.id}/followers")
1509 assert [%{"id" => id}] = json_response(conn, 200)
1510 assert id == to_string(user.id)
1513 test "getting followers, hide_followers", %{conn: conn} do
1514 user = insert(:user)
1515 other_user = insert(:user, %{info: %{hide_followers: true}})
1516 {:ok, _user} = User.follow(user, other_user)
1520 |> get("/api/v1/accounts/#{other_user.id}/followers")
1522 assert [] == json_response(conn, 200)
1525 test "getting followers, hide_followers, same user requesting", %{conn: conn} do
1526 user = insert(:user)
1527 other_user = insert(:user, %{info: %{hide_followers: true}})
1528 {:ok, _user} = User.follow(user, other_user)
1532 |> assign(:user, other_user)
1533 |> get("/api/v1/accounts/#{other_user.id}/followers")
1535 refute [] == json_response(conn, 200)
1538 test "getting followers, pagination", %{conn: conn} do
1539 user = insert(:user)
1540 follower1 = insert(:user)
1541 follower2 = insert(:user)
1542 follower3 = insert(:user)
1543 {:ok, _} = User.follow(follower1, user)
1544 {:ok, _} = User.follow(follower2, user)
1545 {:ok, _} = User.follow(follower3, user)
1549 |> assign(:user, user)
1553 |> get("/api/v1/accounts/#{user.id}/followers?since_id=#{follower1.id}")
1555 assert [%{"id" => id3}, %{"id" => id2}] = json_response(res_conn, 200)
1556 assert id3 == follower3.id
1557 assert id2 == follower2.id
1561 |> get("/api/v1/accounts/#{user.id}/followers?max_id=#{follower3.id}")
1563 assert [%{"id" => id2}, %{"id" => id1}] = json_response(res_conn, 200)
1564 assert id2 == follower2.id
1565 assert id1 == follower1.id
1569 |> get("/api/v1/accounts/#{user.id}/followers?limit=1&max_id=#{follower3.id}")
1571 assert [%{"id" => id2}] = json_response(res_conn, 200)
1572 assert id2 == follower2.id
1574 assert [link_header] = get_resp_header(res_conn, "link")
1575 assert link_header =~ ~r/min_id=#{follower2.id}/
1576 assert link_header =~ ~r/max_id=#{follower2.id}/
1579 test "getting following", %{conn: conn} do
1580 user = insert(:user)
1581 other_user = insert(:user)
1582 {:ok, user} = User.follow(user, other_user)
1586 |> get("/api/v1/accounts/#{user.id}/following")
1588 assert [%{"id" => id}] = json_response(conn, 200)
1589 assert id == to_string(other_user.id)
1592 test "getting following, hide_follows", %{conn: conn} do
1593 user = insert(:user, %{info: %{hide_follows: true}})
1594 other_user = insert(:user)
1595 {:ok, user} = User.follow(user, other_user)
1599 |> get("/api/v1/accounts/#{user.id}/following")
1601 assert [] == json_response(conn, 200)
1604 test "getting following, hide_follows, same user requesting", %{conn: conn} do
1605 user = insert(:user, %{info: %{hide_follows: true}})
1606 other_user = insert(:user)
1607 {:ok, user} = User.follow(user, other_user)
1611 |> assign(:user, user)
1612 |> get("/api/v1/accounts/#{user.id}/following")
1614 refute [] == json_response(conn, 200)
1617 test "getting following, pagination", %{conn: conn} do
1618 user = insert(:user)
1619 following1 = insert(:user)
1620 following2 = insert(:user)
1621 following3 = insert(:user)
1622 {:ok, _} = User.follow(user, following1)
1623 {:ok, _} = User.follow(user, following2)
1624 {:ok, _} = User.follow(user, following3)
1628 |> assign(:user, user)
1632 |> get("/api/v1/accounts/#{user.id}/following?since_id=#{following1.id}")
1634 assert [%{"id" => id3}, %{"id" => id2}] = json_response(res_conn, 200)
1635 assert id3 == following3.id
1636 assert id2 == following2.id
1640 |> get("/api/v1/accounts/#{user.id}/following?max_id=#{following3.id}")
1642 assert [%{"id" => id2}, %{"id" => id1}] = json_response(res_conn, 200)
1643 assert id2 == following2.id
1644 assert id1 == following1.id
1648 |> get("/api/v1/accounts/#{user.id}/following?limit=1&max_id=#{following3.id}")
1650 assert [%{"id" => id2}] = json_response(res_conn, 200)
1651 assert id2 == following2.id
1653 assert [link_header] = get_resp_header(res_conn, "link")
1654 assert link_header =~ ~r/min_id=#{following2.id}/
1655 assert link_header =~ ~r/max_id=#{following2.id}/
1658 test "following / unfollowing a user", %{conn: conn} do
1659 user = insert(:user)
1660 other_user = insert(:user)
1664 |> assign(:user, user)
1665 |> post("/api/v1/accounts/#{other_user.id}/follow")
1667 assert %{"id" => _id, "following" => true} = json_response(conn, 200)
1669 user = User.get_cached_by_id(user.id)
1673 |> assign(:user, user)
1674 |> post("/api/v1/accounts/#{other_user.id}/unfollow")
1676 assert %{"id" => _id, "following" => false} = json_response(conn, 200)
1678 user = User.get_cached_by_id(user.id)
1682 |> assign(:user, user)
1683 |> post("/api/v1/follows", %{"uri" => other_user.nickname})
1685 assert %{"id" => id} = json_response(conn, 200)
1686 assert id == to_string(other_user.id)
1689 test "following without reblogs" do
1690 follower = insert(:user)
1691 followed = insert(:user)
1692 other_user = insert(:user)
1696 |> assign(:user, follower)
1697 |> post("/api/v1/accounts/#{followed.id}/follow?reblogs=false")
1699 assert %{"showing_reblogs" => false} = json_response(conn, 200)
1701 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "hey"})
1702 {:ok, reblog, _} = CommonAPI.repeat(activity.id, followed)
1706 |> assign(:user, User.get_cached_by_id(follower.id))
1707 |> get("/api/v1/timelines/home")
1709 assert [] == json_response(conn, 200)
1713 |> assign(:user, follower)
1714 |> post("/api/v1/accounts/#{followed.id}/follow?reblogs=true")
1716 assert %{"showing_reblogs" => true} = json_response(conn, 200)
1720 |> assign(:user, User.get_cached_by_id(follower.id))
1721 |> get("/api/v1/timelines/home")
1723 expected_activity_id = reblog.id
1724 assert [%{"id" => ^expected_activity_id}] = json_response(conn, 200)
1727 test "following / unfollowing errors" do
1728 user = insert(:user)
1732 |> assign(:user, user)
1735 conn_res = post(conn, "/api/v1/accounts/#{user.id}/follow")
1736 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
1739 user = User.get_cached_by_id(user.id)
1740 conn_res = post(conn, "/api/v1/accounts/#{user.id}/unfollow")
1741 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
1743 # self follow via uri
1744 user = User.get_cached_by_id(user.id)
1745 conn_res = post(conn, "/api/v1/follows", %{"uri" => user.nickname})
1746 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
1748 # follow non existing user
1749 conn_res = post(conn, "/api/v1/accounts/doesntexist/follow")
1750 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
1752 # follow non existing user via uri
1753 conn_res = post(conn, "/api/v1/follows", %{"uri" => "doesntexist"})
1754 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
1756 # unfollow non existing user
1757 conn_res = post(conn, "/api/v1/accounts/doesntexist/unfollow")
1758 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
1761 test "muting / unmuting a user", %{conn: conn} do
1762 user = insert(:user)
1763 other_user = insert(:user)
1767 |> assign(:user, user)
1768 |> post("/api/v1/accounts/#{other_user.id}/mute")
1770 assert %{"id" => _id, "muting" => true} = json_response(conn, 200)
1772 user = User.get_cached_by_id(user.id)
1776 |> assign(:user, user)
1777 |> post("/api/v1/accounts/#{other_user.id}/unmute")
1779 assert %{"id" => _id, "muting" => false} = json_response(conn, 200)
1782 test "subscribing / unsubscribing to a user", %{conn: conn} do
1783 user = insert(:user)
1784 subscription_target = insert(:user)
1788 |> assign(:user, user)
1789 |> post("/api/v1/pleroma/accounts/#{subscription_target.id}/subscribe")
1791 assert %{"id" => _id, "subscribing" => true} = json_response(conn, 200)
1795 |> assign(:user, user)
1796 |> post("/api/v1/pleroma/accounts/#{subscription_target.id}/unsubscribe")
1798 assert %{"id" => _id, "subscribing" => false} = json_response(conn, 200)
1801 test "getting a list of mutes", %{conn: conn} do
1802 user = insert(:user)
1803 other_user = insert(:user)
1805 {:ok, user} = User.mute(user, other_user)
1809 |> assign(:user, user)
1810 |> get("/api/v1/mutes")
1812 other_user_id = to_string(other_user.id)
1813 assert [%{"id" => ^other_user_id}] = json_response(conn, 200)
1816 test "blocking / unblocking a user", %{conn: conn} do
1817 user = insert(:user)
1818 other_user = insert(:user)
1822 |> assign(:user, user)
1823 |> post("/api/v1/accounts/#{other_user.id}/block")
1825 assert %{"id" => _id, "blocking" => true} = json_response(conn, 200)
1827 user = User.get_cached_by_id(user.id)
1831 |> assign(:user, user)
1832 |> post("/api/v1/accounts/#{other_user.id}/unblock")
1834 assert %{"id" => _id, "blocking" => false} = json_response(conn, 200)
1837 test "getting a list of blocks", %{conn: conn} do
1838 user = insert(:user)
1839 other_user = insert(:user)
1841 {:ok, user} = User.block(user, other_user)
1845 |> assign(:user, user)
1846 |> get("/api/v1/blocks")
1848 other_user_id = to_string(other_user.id)
1849 assert [%{"id" => ^other_user_id}] = json_response(conn, 200)
1852 test "blocking / unblocking a domain", %{conn: conn} do
1853 user = insert(:user)
1854 other_user = insert(:user, %{ap_id: "https://dogwhistle.zone/@pundit"})
1858 |> assign(:user, user)
1859 |> post("/api/v1/domain_blocks", %{"domain" => "dogwhistle.zone"})
1861 assert %{} = json_response(conn, 200)
1862 user = User.get_cached_by_ap_id(user.ap_id)
1863 assert User.blocks?(user, other_user)
1867 |> assign(:user, user)
1868 |> delete("/api/v1/domain_blocks", %{"domain" => "dogwhistle.zone"})
1870 assert %{} = json_response(conn, 200)
1871 user = User.get_cached_by_ap_id(user.ap_id)
1872 refute User.blocks?(user, other_user)
1875 test "getting a list of domain blocks", %{conn: conn} do
1876 user = insert(:user)
1878 {:ok, user} = User.block_domain(user, "bad.site")
1879 {:ok, user} = User.block_domain(user, "even.worse.site")
1883 |> assign(:user, user)
1884 |> get("/api/v1/domain_blocks")
1886 domain_blocks = json_response(conn, 200)
1888 assert "bad.site" in domain_blocks
1889 assert "even.worse.site" in domain_blocks
1892 test "unimplemented follow_requests, blocks, domain blocks" do
1893 user = insert(:user)
1895 ["blocks", "domain_blocks", "follow_requests"]
1896 |> Enum.each(fn endpoint ->
1899 |> assign(:user, user)
1900 |> get("/api/v1/#{endpoint}")
1902 assert [] = json_response(conn, 200)
1906 test "account search", %{conn: conn} do
1907 user = insert(:user)
1908 user_two = insert(:user, %{nickname: "shp@shitposter.club"})
1909 user_three = insert(:user, %{nickname: "shp@heldscal.la", name: "I love 2hu"})
1913 |> assign(:user, user)
1914 |> get("/api/v1/accounts/search", %{"q" => "shp"})
1915 |> json_response(200)
1917 result_ids = for result <- results, do: result["acct"]
1919 assert user_two.nickname in result_ids
1920 assert user_three.nickname in result_ids
1924 |> assign(:user, user)
1925 |> get("/api/v1/accounts/search", %{"q" => "2hu"})
1926 |> json_response(200)
1928 result_ids = for result <- results, do: result["acct"]
1930 assert user_three.nickname in result_ids
1933 test "search", %{conn: conn} do
1934 user = insert(:user)
1935 user_two = insert(:user, %{nickname: "shp@shitposter.club"})
1936 user_three = insert(:user, %{nickname: "shp@heldscal.la", name: "I love 2hu"})
1938 {:ok, activity} = CommonAPI.post(user, %{"status" => "This is about 2hu"})
1941 CommonAPI.post(user, %{
1942 "status" => "This is about 2hu, but private",
1943 "visibility" => "private"
1946 {:ok, _} = CommonAPI.post(user_two, %{"status" => "This isn't"})
1950 |> get("/api/v1/search", %{"q" => "2hu"})
1952 assert results = json_response(conn, 200)
1954 [account | _] = results["accounts"]
1955 assert account["id"] == to_string(user_three.id)
1957 assert results["hashtags"] == []
1959 [status] = results["statuses"]
1960 assert status["id"] == to_string(activity.id)
1963 test "search fetches remote statuses", %{conn: conn} do
1967 |> get("/api/v1/search", %{"q" => "https://shitposter.club/notice/2827873"})
1969 assert results = json_response(conn, 200)
1971 [status] = results["statuses"]
1972 assert status["uri"] == "tag:shitposter.club,2017-05-05:noticeId=2827873:objectType=comment"
1976 test "search doesn't show statuses that it shouldn't", %{conn: conn} do
1978 CommonAPI.post(insert(:user), %{
1979 "status" => "This is about 2hu, but private",
1980 "visibility" => "private"
1986 |> get("/api/v1/search", %{"q" => Object.normalize(activity).data["id"]})
1988 assert results = json_response(conn, 200)
1990 [] = results["statuses"]
1994 test "search fetches remote accounts", %{conn: conn} do
1997 |> get("/api/v1/search", %{"q" => "shp@social.heldscal.la", "resolve" => "true"})
1999 assert results = json_response(conn, 200)
2000 [account] = results["accounts"]
2001 assert account["acct"] == "shp@social.heldscal.la"
2004 test "returns the favorites of a user", %{conn: conn} do
2005 user = insert(:user)
2006 other_user = insert(:user)
2008 {:ok, _} = CommonAPI.post(other_user, %{"status" => "bla"})
2009 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "traps are happy"})
2011 {:ok, _, _} = CommonAPI.favorite(activity.id, user)
2015 |> assign(:user, user)
2016 |> get("/api/v1/favourites")
2018 assert [status] = json_response(first_conn, 200)
2019 assert status["id"] == to_string(activity.id)
2021 assert [{"link", _link_header}] =
2022 Enum.filter(first_conn.resp_headers, fn element -> match?({"link", _}, element) end)
2024 # Honours query params
2025 {:ok, second_activity} =
2026 CommonAPI.post(other_user, %{
2028 "Trees Are Never Sad Look At Them Every Once In Awhile They're Quite Beautiful."
2031 {:ok, _, _} = CommonAPI.favorite(second_activity.id, user)
2033 last_like = status["id"]
2037 |> assign(:user, user)
2038 |> get("/api/v1/favourites?since_id=#{last_like}")
2040 assert [second_status] = json_response(second_conn, 200)
2041 assert second_status["id"] == to_string(second_activity.id)
2045 |> assign(:user, user)
2046 |> get("/api/v1/favourites?limit=0")
2048 assert [] = json_response(third_conn, 200)
2051 describe "getting favorites timeline of specified user" do
2053 [current_user, user] = insert_pair(:user, %{info: %{hide_favorites: false}})
2054 [current_user: current_user, user: user]
2057 test "returns list of statuses favorited by specified user", %{
2059 current_user: current_user,
2062 [activity | _] = insert_pair(:note_activity)
2063 CommonAPI.favorite(activity.id, user)
2067 |> assign(:user, current_user)
2068 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2069 |> json_response(:ok)
2073 assert length(response) == 1
2074 assert like["id"] == activity.id
2077 test "returns favorites for specified user_id when user is not logged in", %{
2081 activity = insert(:note_activity)
2082 CommonAPI.favorite(activity.id, user)
2086 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2087 |> json_response(:ok)
2089 assert length(response) == 1
2092 test "returns favorited DM only when user is logged in and he is one of recipients", %{
2094 current_user: current_user,
2098 CommonAPI.post(current_user, %{
2099 "status" => "Hi @#{user.nickname}!",
2100 "visibility" => "direct"
2103 CommonAPI.favorite(direct.id, user)
2107 |> assign(:user, current_user)
2108 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2109 |> json_response(:ok)
2111 assert length(response) == 1
2113 anonymous_response =
2115 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2116 |> json_response(:ok)
2118 assert length(anonymous_response) == 0
2121 test "does not return others' favorited DM when user is not one of recipients", %{
2123 current_user: current_user,
2126 user_two = insert(:user)
2129 CommonAPI.post(user_two, %{
2130 "status" => "Hi @#{user.nickname}!",
2131 "visibility" => "direct"
2134 CommonAPI.favorite(direct.id, user)
2138 |> assign(:user, current_user)
2139 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2140 |> json_response(:ok)
2142 assert length(response) == 0
2145 test "paginates favorites using since_id and max_id", %{
2147 current_user: current_user,
2150 activities = insert_list(10, :note_activity)
2152 Enum.each(activities, fn activity ->
2153 CommonAPI.favorite(activity.id, user)
2156 third_activity = Enum.at(activities, 2)
2157 seventh_activity = Enum.at(activities, 6)
2161 |> assign(:user, current_user)
2162 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites", %{
2163 since_id: third_activity.id,
2164 max_id: seventh_activity.id
2166 |> json_response(:ok)
2168 assert length(response) == 3
2169 refute third_activity in response
2170 refute seventh_activity in response
2173 test "limits favorites using limit parameter", %{
2175 current_user: current_user,
2179 |> insert_list(:note_activity)
2180 |> Enum.each(fn activity ->
2181 CommonAPI.favorite(activity.id, user)
2186 |> assign(:user, current_user)
2187 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites", %{limit: "3"})
2188 |> json_response(:ok)
2190 assert length(response) == 3
2193 test "returns empty response when user does not have any favorited statuses", %{
2195 current_user: current_user,
2200 |> assign(:user, current_user)
2201 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2202 |> json_response(:ok)
2204 assert Enum.empty?(response)
2207 test "returns 404 error when specified user is not exist", %{conn: conn} do
2208 conn = get(conn, "/api/v1/pleroma/accounts/test/favourites")
2210 assert json_response(conn, 404) == %{"error" => "Record not found"}
2213 test "returns 403 error when user has hidden own favorites", %{
2215 current_user: current_user
2217 user = insert(:user, %{info: %{hide_favorites: true}})
2218 activity = insert(:note_activity)
2219 CommonAPI.favorite(activity.id, user)
2223 |> assign(:user, current_user)
2224 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2226 assert json_response(conn, 403) == %{"error" => "Can't get favorites"}
2229 test "hides favorites for new users by default", %{conn: conn, current_user: current_user} do
2230 user = insert(:user)
2231 activity = insert(:note_activity)
2232 CommonAPI.favorite(activity.id, user)
2236 |> assign(:user, current_user)
2237 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2239 assert user.info.hide_favorites
2240 assert json_response(conn, 403) == %{"error" => "Can't get favorites"}
2244 describe "updating credentials" do
2245 test "updates the user's bio", %{conn: conn} do
2246 user = insert(:user)
2247 user2 = insert(:user)
2251 |> assign(:user, user)
2252 |> patch("/api/v1/accounts/update_credentials", %{
2253 "note" => "I drink #cofe with @#{user2.nickname}"
2256 assert user = json_response(conn, 200)
2258 assert user["note"] ==
2259 ~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=") <>
2261 ~s(" class="u-url mention" href=") <>
2262 user2.ap_id <> ~s(">@<span>) <> user2.nickname <> ~s(</span></a></span>)
2265 test "updates the user's locking status", %{conn: conn} do
2266 user = insert(:user)
2270 |> assign(:user, user)
2271 |> patch("/api/v1/accounts/update_credentials", %{locked: "true"})
2273 assert user = json_response(conn, 200)
2274 assert user["locked"] == true
2277 test "updates the user's default scope", %{conn: conn} do
2278 user = insert(:user)
2282 |> assign(:user, user)
2283 |> patch("/api/v1/accounts/update_credentials", %{default_scope: "cofe"})
2285 assert user = json_response(conn, 200)
2286 assert user["source"]["privacy"] == "cofe"
2289 test "updates the user's hide_followers status", %{conn: conn} do
2290 user = insert(:user)
2294 |> assign(:user, user)
2295 |> patch("/api/v1/accounts/update_credentials", %{hide_followers: "true"})
2297 assert user = json_response(conn, 200)
2298 assert user["pleroma"]["hide_followers"] == true
2301 test "updates the user's hide_follows status", %{conn: conn} do
2302 user = insert(:user)
2306 |> assign(:user, user)
2307 |> patch("/api/v1/accounts/update_credentials", %{hide_follows: "true"})
2309 assert user = json_response(conn, 200)
2310 assert user["pleroma"]["hide_follows"] == true
2313 test "updates the user's hide_favorites status", %{conn: conn} do
2314 user = insert(:user)
2318 |> assign(:user, user)
2319 |> patch("/api/v1/accounts/update_credentials", %{hide_favorites: "true"})
2321 assert user = json_response(conn, 200)
2322 assert user["pleroma"]["hide_favorites"] == true
2325 test "updates the user's show_role status", %{conn: conn} do
2326 user = insert(:user)
2330 |> assign(:user, user)
2331 |> patch("/api/v1/accounts/update_credentials", %{show_role: "false"})
2333 assert user = json_response(conn, 200)
2334 assert user["source"]["pleroma"]["show_role"] == false
2337 test "updates the user's no_rich_text status", %{conn: conn} do
2338 user = insert(:user)
2342 |> assign(:user, user)
2343 |> patch("/api/v1/accounts/update_credentials", %{no_rich_text: "true"})
2345 assert user = json_response(conn, 200)
2346 assert user["source"]["pleroma"]["no_rich_text"] == true
2349 test "updates the user's name", %{conn: conn} do
2350 user = insert(:user)
2354 |> assign(:user, user)
2355 |> patch("/api/v1/accounts/update_credentials", %{"display_name" => "markorepairs"})
2357 assert user = json_response(conn, 200)
2358 assert user["display_name"] == "markorepairs"
2361 test "updates the user's avatar", %{conn: conn} do
2362 user = insert(:user)
2364 new_avatar = %Plug.Upload{
2365 content_type: "image/jpg",
2366 path: Path.absname("test/fixtures/image.jpg"),
2367 filename: "an_image.jpg"
2372 |> assign(:user, user)
2373 |> patch("/api/v1/accounts/update_credentials", %{"avatar" => new_avatar})
2375 assert user_response = json_response(conn, 200)
2376 assert user_response["avatar"] != User.avatar_url(user)
2379 test "updates the user's banner", %{conn: conn} do
2380 user = insert(:user)
2382 new_header = %Plug.Upload{
2383 content_type: "image/jpg",
2384 path: Path.absname("test/fixtures/image.jpg"),
2385 filename: "an_image.jpg"
2390 |> assign(:user, user)
2391 |> patch("/api/v1/accounts/update_credentials", %{"header" => new_header})
2393 assert user_response = json_response(conn, 200)
2394 assert user_response["header"] != User.banner_url(user)
2397 test "requires 'write' permission", %{conn: conn} do
2398 token1 = insert(:oauth_token, scopes: ["read"])
2399 token2 = insert(:oauth_token, scopes: ["write", "follow"])
2401 for token <- [token1, token2] do
2404 |> put_req_header("authorization", "Bearer #{token.token}")
2405 |> patch("/api/v1/accounts/update_credentials", %{})
2407 if token == token1 do
2408 assert %{"error" => "Insufficient permissions: write."} == json_response(conn, 403)
2410 assert json_response(conn, 200)
2415 test "updates profile emojos", %{conn: conn} do
2416 user = insert(:user)
2418 note = "*sips :blank:*"
2419 name = "I am :firefox:"
2423 |> assign(:user, user)
2424 |> patch("/api/v1/accounts/update_credentials", %{
2426 "display_name" => name
2429 assert json_response(conn, 200)
2433 |> get("/api/v1/accounts/#{user.id}")
2435 assert user = json_response(conn, 200)
2437 assert user["note"] == note
2438 assert user["display_name"] == name
2439 assert [%{"shortcode" => "blank"}, %{"shortcode" => "firefox"}] = user["emojis"]
2443 test "get instance information", %{conn: conn} do
2444 conn = get(conn, "/api/v1/instance")
2445 assert result = json_response(conn, 200)
2447 email = Pleroma.Config.get([:instance, :email])
2448 # Note: not checking for "max_toot_chars" since it's optional
2454 "email" => from_config_email,
2456 "streaming_api" => _
2461 "registrations" => _
2464 assert email == from_config_email
2467 test "get instance stats", %{conn: conn} do
2468 user = insert(:user, %{local: true})
2470 user2 = insert(:user, %{local: true})
2471 {:ok, _user2} = User.deactivate(user2, !user2.info.deactivated)
2473 insert(:user, %{local: false, nickname: "u@peer1.com"})
2474 insert(:user, %{local: false, nickname: "u@peer2.com"})
2476 {:ok, _} = TwitterAPI.create_status(user, %{"status" => "cofe"})
2478 # Stats should count users with missing or nil `info.deactivated` value
2479 user = User.get_cached_by_id(user.id)
2480 info_change = Changeset.change(user.info, %{deactivated: nil})
2484 |> Changeset.change()
2485 |> Changeset.put_embed(:info, info_change)
2486 |> User.update_and_set_cache()
2488 Pleroma.Stats.update_stats()
2490 conn = get(conn, "/api/v1/instance")
2492 assert result = json_response(conn, 200)
2494 stats = result["stats"]
2497 assert stats["user_count"] == 1
2498 assert stats["status_count"] == 1
2499 assert stats["domain_count"] == 2
2502 test "get peers", %{conn: conn} do
2503 insert(:user, %{local: false, nickname: "u@peer1.com"})
2504 insert(:user, %{local: false, nickname: "u@peer2.com"})
2506 Pleroma.Stats.update_stats()
2508 conn = get(conn, "/api/v1/instance/peers")
2510 assert result = json_response(conn, 200)
2512 assert ["peer1.com", "peer2.com"] == Enum.sort(result)
2515 test "put settings", %{conn: conn} do
2516 user = insert(:user)
2520 |> assign(:user, user)
2521 |> put("/api/web/settings", %{"data" => %{"programming" => "socks"}})
2523 assert _result = json_response(conn, 200)
2525 user = User.get_cached_by_ap_id(user.ap_id)
2526 assert user.info.settings == %{"programming" => "socks"}
2529 describe "pinned statuses" do
2531 Pleroma.Config.put([:instance, :max_pinned_statuses], 1)
2533 user = insert(:user)
2534 {:ok, activity} = CommonAPI.post(user, %{"status" => "HI!!!"})
2536 [user: user, activity: activity]
2539 test "returns pinned statuses", %{conn: conn, user: user, activity: activity} do
2540 {:ok, _} = CommonAPI.pin(activity.id, user)
2544 |> assign(:user, user)
2545 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
2546 |> json_response(200)
2548 id_str = to_string(activity.id)
2550 assert [%{"id" => ^id_str, "pinned" => true}] = result
2553 test "pin status", %{conn: conn, user: user, activity: activity} do
2554 id_str = to_string(activity.id)
2556 assert %{"id" => ^id_str, "pinned" => true} =
2558 |> assign(:user, user)
2559 |> post("/api/v1/statuses/#{activity.id}/pin")
2560 |> json_response(200)
2562 assert [%{"id" => ^id_str, "pinned" => true}] =
2564 |> assign(:user, user)
2565 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
2566 |> json_response(200)
2569 test "unpin status", %{conn: conn, user: user, activity: activity} do
2570 {:ok, _} = CommonAPI.pin(activity.id, user)
2572 id_str = to_string(activity.id)
2573 user = refresh_record(user)
2575 assert %{"id" => ^id_str, "pinned" => false} =
2577 |> assign(:user, user)
2578 |> post("/api/v1/statuses/#{activity.id}/unpin")
2579 |> json_response(200)
2583 |> assign(:user, user)
2584 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
2585 |> json_response(200)
2588 test "max pinned statuses", %{conn: conn, user: user, activity: activity_one} do
2589 {:ok, activity_two} = CommonAPI.post(user, %{"status" => "HI!!!"})
2591 id_str_one = to_string(activity_one.id)
2593 assert %{"id" => ^id_str_one, "pinned" => true} =
2595 |> assign(:user, user)
2596 |> post("/api/v1/statuses/#{id_str_one}/pin")
2597 |> json_response(200)
2599 user = refresh_record(user)
2601 assert %{"error" => "You have already pinned the maximum number of statuses"} =
2603 |> assign(:user, user)
2604 |> post("/api/v1/statuses/#{activity_two.id}/pin")
2605 |> json_response(400)
2608 test "Status rich-media Card", %{conn: conn, user: user} do
2609 Pleroma.Config.put([:rich_media, :enabled], true)
2610 {:ok, activity} = CommonAPI.post(user, %{"status" => "http://example.com/ogp"})
2614 |> get("/api/v1/statuses/#{activity.id}/card")
2615 |> json_response(200)
2617 assert response == %{
2618 "image" => "http://ia.media-imdb.com/images/rock.jpg",
2619 "provider_name" => "www.imdb.com",
2620 "provider_url" => "http://www.imdb.com",
2621 "title" => "The Rock",
2623 "url" => "http://www.imdb.com/title/tt0117500/",
2624 "description" => nil,
2627 "image" => "http://ia.media-imdb.com/images/rock.jpg",
2628 "title" => "The Rock",
2629 "type" => "video.movie",
2630 "url" => "http://www.imdb.com/title/tt0117500/"
2635 # works with private posts
2637 CommonAPI.post(user, %{"status" => "http://example.com/ogp", "visibility" => "direct"})
2641 |> assign(:user, user)
2642 |> get("/api/v1/statuses/#{activity.id}/card")
2643 |> json_response(200)
2645 assert response_two == response
2647 Pleroma.Config.put([:rich_media, :enabled], false)
2652 user = insert(:user)
2653 for_user = insert(:user)
2656 CommonAPI.post(user, %{
2657 "status" => "heweoo?"
2661 CommonAPI.post(user, %{
2662 "status" => "heweoo!"
2667 |> assign(:user, for_user)
2668 |> post("/api/v1/statuses/#{activity1.id}/bookmark")
2670 assert json_response(response1, 200)["bookmarked"] == true
2674 |> assign(:user, for_user)
2675 |> post("/api/v1/statuses/#{activity2.id}/bookmark")
2677 assert json_response(response2, 200)["bookmarked"] == true
2681 |> assign(:user, for_user)
2682 |> get("/api/v1/bookmarks")
2684 assert [json_response(response2, 200), json_response(response1, 200)] ==
2685 json_response(bookmarks, 200)
2689 |> assign(:user, for_user)
2690 |> post("/api/v1/statuses/#{activity1.id}/unbookmark")
2692 assert json_response(response1, 200)["bookmarked"] == false
2696 |> assign(:user, for_user)
2697 |> get("/api/v1/bookmarks")
2699 assert [json_response(response2, 200)] == json_response(bookmarks, 200)
2702 describe "conversation muting" do
2704 user = insert(:user)
2705 {:ok, activity} = CommonAPI.post(user, %{"status" => "HIE"})
2707 [user: user, activity: activity]
2710 test "mute conversation", %{conn: conn, user: user, activity: activity} do
2711 id_str = to_string(activity.id)
2713 assert %{"id" => ^id_str, "muted" => true} =
2715 |> assign(:user, user)
2716 |> post("/api/v1/statuses/#{activity.id}/mute")
2717 |> json_response(200)
2720 test "unmute conversation", %{conn: conn, user: user, activity: activity} do
2721 {:ok, _} = CommonAPI.add_mute(user, activity)
2723 id_str = to_string(activity.id)
2724 user = refresh_record(user)
2726 assert %{"id" => ^id_str, "muted" => false} =
2728 |> assign(:user, user)
2729 |> post("/api/v1/statuses/#{activity.id}/unmute")
2730 |> json_response(200)
2734 test "flavours switching (Pleroma Extension)", %{conn: conn} do
2735 user = insert(:user)
2739 |> assign(:user, user)
2740 |> get("/api/v1/pleroma/flavour")
2742 assert "glitch" == json_response(get_old_flavour, 200)
2746 |> assign(:user, user)
2747 |> post("/api/v1/pleroma/flavour/vanilla")
2749 assert "vanilla" == json_response(set_flavour, 200)
2753 |> assign(:user, user)
2754 |> post("/api/v1/pleroma/flavour/vanilla")
2756 assert json_response(set_flavour, 200) == json_response(get_new_flavour, 200)
2759 describe "reports" do
2761 reporter = insert(:user)
2762 target_user = insert(:user)
2764 {:ok, activity} = CommonAPI.post(target_user, %{"status" => "foobar"})
2766 [reporter: reporter, target_user: target_user, activity: activity]
2769 test "submit a basic report", %{conn: conn, reporter: reporter, target_user: target_user} do
2770 assert %{"action_taken" => false, "id" => _} =
2772 |> assign(:user, reporter)
2773 |> post("/api/v1/reports", %{"account_id" => target_user.id})
2774 |> json_response(200)
2777 test "submit a report with statuses and comment", %{
2780 target_user: target_user,
2783 assert %{"action_taken" => false, "id" => _} =
2785 |> assign(:user, reporter)
2786 |> post("/api/v1/reports", %{
2787 "account_id" => target_user.id,
2788 "status_ids" => [activity.id],
2789 "comment" => "bad status!"
2791 |> json_response(200)
2794 test "account_id is required", %{
2799 assert %{"error" => "Valid `account_id` required"} =
2801 |> assign(:user, reporter)
2802 |> post("/api/v1/reports", %{"status_ids" => [activity.id]})
2803 |> json_response(400)
2806 test "comment must be up to the size specified in the config", %{
2809 target_user: target_user
2811 max_size = Pleroma.Config.get([:instance, :max_report_comment_size], 1000)
2812 comment = String.pad_trailing("a", max_size + 1, "a")
2814 error = %{"error" => "Comment must be up to #{max_size} characters"}
2818 |> assign(:user, reporter)
2819 |> post("/api/v1/reports", %{"account_id" => target_user.id, "comment" => comment})
2820 |> json_response(400)
2824 describe "link headers" do
2825 test "preserves parameters in link headers", %{conn: conn} do
2826 user = insert(:user)
2827 other_user = insert(:user)
2830 CommonAPI.post(other_user, %{
2831 "status" => "hi @#{user.nickname}",
2832 "visibility" => "public"
2836 CommonAPI.post(other_user, %{
2837 "status" => "hi @#{user.nickname}",
2838 "visibility" => "public"
2841 notification1 = Repo.get_by(Notification, activity_id: activity1.id)
2842 notification2 = Repo.get_by(Notification, activity_id: activity2.id)
2846 |> assign(:user, user)
2847 |> get("/api/v1/notifications", %{media_only: true})
2849 assert [link_header] = get_resp_header(conn, "link")
2850 assert link_header =~ ~r/media_only=true/
2851 assert link_header =~ ~r/min_id=#{notification2.id}/
2852 assert link_header =~ ~r/max_id=#{notification1.id}/
2856 test "accounts fetches correct account for nicknames beginning with numbers", %{conn: conn} do
2857 # Need to set an old-style integer ID to reproduce the problem
2858 # (these are no longer assigned to new accounts but were preserved
2859 # for existing accounts during the migration to flakeIDs)
2860 user_one = insert(:user, %{id: 1212})
2861 user_two = insert(:user, %{nickname: "#{user_one.id}garbage"})
2865 |> get("/api/v1/accounts/#{user_one.id}")
2869 |> get("/api/v1/accounts/#{user_two.nickname}")
2873 |> get("/api/v1/accounts/#{user_two.id}")
2875 acc_one = json_response(resp_one, 200)
2876 acc_two = json_response(resp_two, 200)
2877 acc_three = json_response(resp_three, 200)
2878 refute acc_one == acc_two
2879 assert acc_two == acc_three
2882 describe "custom emoji" do
2883 test "with tags", %{conn: conn} do
2886 |> get("/api/v1/custom_emojis")
2887 |> json_response(200)
2889 assert Map.has_key?(emoji, "shortcode")
2890 assert Map.has_key?(emoji, "static_url")
2891 assert Map.has_key?(emoji, "tags")
2892 assert is_list(emoji["tags"])
2893 assert Map.has_key?(emoji, "url")
2894 assert Map.has_key?(emoji, "visible_in_picker")
2898 describe "index/2 redirections" do
2899 setup %{conn: conn} do
2903 signing_salt: "cooldude"
2908 |> Plug.Session.call(Plug.Session.init(session_opts))
2911 test_path = "/web/statuses/test"
2912 %{conn: conn, path: test_path}
2915 test "redirects not logged-in users to the login page", %{conn: conn, path: path} do
2916 conn = get(conn, path)
2918 assert conn.status == 302
2919 assert redirected_to(conn) == "/web/login"
2922 test "does not redirect logged in users to the login page", %{conn: conn, path: path} do
2923 token = insert(:oauth_token)
2927 |> assign(:user, token.user)
2928 |> put_session(:oauth_token, token.token)
2931 assert conn.status == 200
2934 test "saves referer path to session", %{conn: conn, path: path} do
2935 conn = get(conn, path)
2936 return_to = Plug.Conn.get_session(conn, :return_to)
2938 assert return_to == path
2941 test "redirects to the saved path after log in", %{conn: conn, path: path} do
2942 app = insert(:oauth_app, client_name: "Mastodon-Local", redirect_uris: ".")
2943 auth = insert(:oauth_authorization, app: app)
2947 |> put_session(:return_to, path)
2948 |> get("/web/login", %{code: auth.token})
2950 assert conn.status == 302
2951 assert redirected_to(conn) == path
2954 test "redirects to the getting-started page when referer is not present", %{conn: conn} do
2955 app = insert(:oauth_app, client_name: "Mastodon-Local", redirect_uris: ".")
2956 auth = insert(:oauth_authorization, app: app)
2958 conn = get(conn, "/web/login", %{code: auth.token})
2960 assert conn.status == 302
2961 assert redirected_to(conn) == "/web/getting-started"
2965 describe "scheduled activities" do
2966 test "creates a scheduled activity", %{conn: conn} do
2967 user = insert(:user)
2968 scheduled_at = NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond)
2972 |> assign(:user, user)
2973 |> post("/api/v1/statuses", %{
2974 "status" => "scheduled",
2975 "scheduled_at" => scheduled_at
2978 assert %{"scheduled_at" => expected_scheduled_at} = json_response(conn, 200)
2979 assert expected_scheduled_at == Pleroma.Web.CommonAPI.Utils.to_masto_date(scheduled_at)
2980 assert [] == Repo.all(Activity)
2983 test "creates a scheduled activity with a media attachment", %{conn: conn} do
2984 user = insert(:user)
2985 scheduled_at = NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond)
2987 file = %Plug.Upload{
2988 content_type: "image/jpg",
2989 path: Path.absname("test/fixtures/image.jpg"),
2990 filename: "an_image.jpg"
2993 {:ok, upload} = ActivityPub.upload(file, actor: user.ap_id)
2997 |> assign(:user, user)
2998 |> post("/api/v1/statuses", %{
2999 "media_ids" => [to_string(upload.id)],
3000 "status" => "scheduled",
3001 "scheduled_at" => scheduled_at
3004 assert %{"media_attachments" => [media_attachment]} = json_response(conn, 200)
3005 assert %{"type" => "image"} = media_attachment
3008 test "skips the scheduling and creates the activity if scheduled_at is earlier than 5 minutes from now",
3010 user = insert(:user)
3013 NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(5) - 1, :millisecond)
3017 |> assign(:user, user)
3018 |> post("/api/v1/statuses", %{
3019 "status" => "not scheduled",
3020 "scheduled_at" => scheduled_at
3023 assert %{"content" => "not scheduled"} = json_response(conn, 200)
3024 assert [] == Repo.all(ScheduledActivity)
3027 test "returns error when daily user limit is exceeded", %{conn: conn} do
3028 user = insert(:user)
3031 NaiveDateTime.utc_now()
3032 |> NaiveDateTime.add(:timer.minutes(6), :millisecond)
3033 |> NaiveDateTime.to_iso8601()
3035 attrs = %{params: %{}, scheduled_at: today}
3036 {:ok, _} = ScheduledActivity.create(user, attrs)
3037 {:ok, _} = ScheduledActivity.create(user, attrs)
3041 |> assign(:user, user)
3042 |> post("/api/v1/statuses", %{"status" => "scheduled", "scheduled_at" => today})
3044 assert %{"error" => "daily limit exceeded"} == json_response(conn, 422)
3047 test "returns error when total user limit is exceeded", %{conn: conn} do
3048 user = insert(:user)
3051 NaiveDateTime.utc_now()
3052 |> NaiveDateTime.add(:timer.minutes(6), :millisecond)
3053 |> NaiveDateTime.to_iso8601()
3056 NaiveDateTime.utc_now()
3057 |> NaiveDateTime.add(:timer.hours(36), :millisecond)
3058 |> NaiveDateTime.to_iso8601()
3060 attrs = %{params: %{}, scheduled_at: today}
3061 {:ok, _} = ScheduledActivity.create(user, attrs)
3062 {:ok, _} = ScheduledActivity.create(user, attrs)
3063 {:ok, _} = ScheduledActivity.create(user, %{params: %{}, scheduled_at: tomorrow})
3067 |> assign(:user, user)
3068 |> post("/api/v1/statuses", %{"status" => "scheduled", "scheduled_at" => tomorrow})
3070 assert %{"error" => "total limit exceeded"} == json_response(conn, 422)
3073 test "shows scheduled activities", %{conn: conn} do
3074 user = insert(:user)
3075 scheduled_activity_id1 = insert(:scheduled_activity, user: user).id |> to_string()
3076 scheduled_activity_id2 = insert(:scheduled_activity, user: user).id |> to_string()
3077 scheduled_activity_id3 = insert(:scheduled_activity, user: user).id |> to_string()
3078 scheduled_activity_id4 = insert(:scheduled_activity, user: user).id |> to_string()
3082 |> assign(:user, user)
3087 |> get("/api/v1/scheduled_statuses?limit=2&min_id=#{scheduled_activity_id1}")
3089 result = json_response(conn_res, 200)
3090 assert [%{"id" => ^scheduled_activity_id3}, %{"id" => ^scheduled_activity_id2}] = result
3095 |> get("/api/v1/scheduled_statuses?limit=2&since_id=#{scheduled_activity_id1}")
3097 result = json_response(conn_res, 200)
3098 assert [%{"id" => ^scheduled_activity_id4}, %{"id" => ^scheduled_activity_id3}] = result
3103 |> get("/api/v1/scheduled_statuses?limit=2&max_id=#{scheduled_activity_id4}")
3105 result = json_response(conn_res, 200)
3106 assert [%{"id" => ^scheduled_activity_id3}, %{"id" => ^scheduled_activity_id2}] = result
3109 test "shows a scheduled activity", %{conn: conn} do
3110 user = insert(:user)
3111 scheduled_activity = insert(:scheduled_activity, user: user)
3115 |> assign(:user, user)
3116 |> get("/api/v1/scheduled_statuses/#{scheduled_activity.id}")
3118 assert %{"id" => scheduled_activity_id} = json_response(res_conn, 200)
3119 assert scheduled_activity_id == scheduled_activity.id |> to_string()
3123 |> assign(:user, user)
3124 |> get("/api/v1/scheduled_statuses/404")
3126 assert %{"error" => "Record not found"} = json_response(res_conn, 404)
3129 test "updates a scheduled activity", %{conn: conn} do
3130 user = insert(:user)
3131 scheduled_activity = insert(:scheduled_activity, user: user)
3134 NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond)
3138 |> assign(:user, user)
3139 |> put("/api/v1/scheduled_statuses/#{scheduled_activity.id}", %{
3140 scheduled_at: new_scheduled_at
3143 assert %{"scheduled_at" => expected_scheduled_at} = json_response(res_conn, 200)
3144 assert expected_scheduled_at == Pleroma.Web.CommonAPI.Utils.to_masto_date(new_scheduled_at)
3148 |> assign(:user, user)
3149 |> put("/api/v1/scheduled_statuses/404", %{scheduled_at: new_scheduled_at})
3151 assert %{"error" => "Record not found"} = json_response(res_conn, 404)
3154 test "deletes a scheduled activity", %{conn: conn} do
3155 user = insert(:user)
3156 scheduled_activity = insert(:scheduled_activity, user: user)
3160 |> assign(:user, user)
3161 |> delete("/api/v1/scheduled_statuses/#{scheduled_activity.id}")
3163 assert %{} = json_response(res_conn, 200)
3164 assert nil == Repo.get(ScheduledActivity, scheduled_activity.id)
3168 |> assign(:user, user)
3169 |> delete("/api/v1/scheduled_statuses/#{scheduled_activity.id}")
3171 assert %{"error" => "Record not found"} = json_response(res_conn, 404)
3175 test "Repeated posts that are replies incorrectly have in_reply_to_id null", %{conn: conn} do
3176 user1 = insert(:user)
3177 user2 = insert(:user)
3178 user3 = insert(:user)
3180 {:ok, replied_to} = TwitterAPI.create_status(user1, %{"status" => "cofe"})
3182 # Reply to status from another user
3185 |> assign(:user, user2)
3186 |> post("/api/v1/statuses", %{"status" => "xD", "in_reply_to_id" => replied_to.id})
3188 assert %{"content" => "xD", "id" => id} = json_response(conn1, 200)
3190 activity = Activity.get_by_id_with_object(id)
3192 assert Object.normalize(activity).data["inReplyTo"] == Object.normalize(replied_to).data["id"]
3193 assert Activity.get_in_reply_to_activity(activity).id == replied_to.id
3195 # Reblog from the third user
3198 |> assign(:user, user3)
3199 |> post("/api/v1/statuses/#{activity.id}/reblog")
3201 assert %{"reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 1}} =
3202 json_response(conn2, 200)
3204 assert to_string(activity.id) == id
3206 # Getting third user status
3209 |> assign(:user, user3)
3210 |> get("api/v1/timelines/home")
3212 [reblogged_activity] = json_response(conn3, 200)
3214 assert reblogged_activity["reblog"]["in_reply_to_id"] == replied_to.id
3216 replied_to_user = User.get_by_ap_id(replied_to.data["actor"])
3217 assert reblogged_activity["reblog"]["in_reply_to_account_id"] == replied_to_user.id