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.OAuth.Token
20 alias Pleroma.Web.OStatus
21 alias Pleroma.Web.Push
22 alias Pleroma.Web.TwitterAPI.TwitterAPI
23 import Pleroma.Factory
24 import ExUnit.CaptureLog
28 mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
32 test "the home timeline", %{conn: conn} do
34 following = insert(:user)
36 {:ok, _activity} = TwitterAPI.create_status(following, %{"status" => "test"})
40 |> assign(:user, user)
41 |> get("/api/v1/timelines/home")
43 assert Enum.empty?(json_response(conn, 200))
45 {:ok, user} = User.follow(user, following)
49 |> assign(:user, user)
50 |> get("/api/v1/timelines/home")
52 assert [%{"content" => "test"}] = json_response(conn, 200)
55 test "the public timeline", %{conn: conn} do
56 following = insert(:user)
59 {:ok, _activity} = TwitterAPI.create_status(following, %{"status" => "test"})
62 OStatus.fetch_activity_from_url("https://shitposter.club/notice/2827873")
66 |> get("/api/v1/timelines/public", %{"local" => "False"})
68 assert length(json_response(conn, 200)) == 2
72 |> get("/api/v1/timelines/public", %{"local" => "True"})
74 assert [%{"content" => "test"}] = json_response(conn, 200)
78 |> get("/api/v1/timelines/public", %{"local" => "1"})
80 assert [%{"content" => "test"}] = json_response(conn, 200)
84 test "posting a status", %{conn: conn} do
87 idempotency_key = "Pikachu rocks!"
91 |> assign(:user, user)
92 |> put_req_header("idempotency-key", idempotency_key)
93 |> post("/api/v1/statuses", %{
95 "spoiler_text" => "2hu",
96 "sensitive" => "false"
99 {:ok, ttl} = Cachex.ttl(:idempotency_cache, idempotency_key)
101 assert ttl > :timer.seconds(6 * 60 * 60 - 1)
103 assert %{"content" => "cofe", "id" => id, "spoiler_text" => "2hu", "sensitive" => false} =
104 json_response(conn_one, 200)
106 assert Activity.get_by_id(id)
110 |> assign(:user, user)
111 |> put_req_header("idempotency-key", idempotency_key)
112 |> post("/api/v1/statuses", %{
114 "spoiler_text" => "2hu",
115 "sensitive" => "false"
118 assert %{"id" => second_id} = json_response(conn_two, 200)
120 assert id == second_id
124 |> assign(:user, user)
125 |> post("/api/v1/statuses", %{
127 "spoiler_text" => "2hu",
128 "sensitive" => "false"
131 assert %{"id" => third_id} = json_response(conn_three, 200)
133 refute id == third_id
136 test "posting a sensitive status", %{conn: conn} do
141 |> assign(:user, user)
142 |> post("/api/v1/statuses", %{"status" => "cofe", "sensitive" => true})
144 assert %{"content" => "cofe", "id" => id, "sensitive" => true} = json_response(conn, 200)
145 assert Activity.get_by_id(id)
148 test "posting a fake status", %{conn: conn} do
153 |> assign(:user, user)
154 |> post("/api/v1/statuses", %{
156 "\"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"
159 real_status = json_response(real_conn, 200)
162 assert Object.get_by_ap_id(real_status["uri"])
166 |> Map.put("id", nil)
167 |> Map.put("url", nil)
168 |> Map.put("uri", nil)
169 |> Map.put("created_at", nil)
170 |> Kernel.put_in(["pleroma", "conversation_id"], nil)
174 |> assign(:user, user)
175 |> post("/api/v1/statuses", %{
177 "\"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",
181 fake_status = json_response(fake_conn, 200)
184 refute Object.get_by_ap_id(fake_status["uri"])
188 |> Map.put("id", nil)
189 |> Map.put("url", nil)
190 |> Map.put("uri", nil)
191 |> Map.put("created_at", nil)
192 |> Kernel.put_in(["pleroma", "conversation_id"], nil)
194 assert real_status == fake_status
197 test "posting a status with OGP link preview", %{conn: conn} do
198 Pleroma.Config.put([:rich_media, :enabled], true)
203 |> assign(:user, user)
204 |> post("/api/v1/statuses", %{
205 "status" => "http://example.com/ogp"
208 assert %{"id" => id, "card" => %{"title" => "The Rock"}} = json_response(conn, 200)
209 assert Activity.get_by_id(id)
210 Pleroma.Config.put([:rich_media, :enabled], false)
213 test "posting a direct status", %{conn: conn} do
214 user1 = insert(:user)
215 user2 = insert(:user)
216 content = "direct cofe @#{user2.nickname}"
220 |> assign(:user, user1)
221 |> post("api/v1/statuses", %{"status" => content, "visibility" => "direct"})
223 assert %{"id" => id, "visibility" => "direct"} = json_response(conn, 200)
224 assert activity = Activity.get_by_id(id)
225 assert activity.recipients == [user2.ap_id, user1.ap_id]
226 assert activity.data["to"] == [user2.ap_id]
227 assert activity.data["cc"] == []
230 test "direct timeline", %{conn: conn} do
231 user_one = insert(:user)
232 user_two = insert(:user)
234 {:ok, user_two} = User.follow(user_two, user_one)
237 CommonAPI.post(user_one, %{
238 "status" => "Hi @#{user_two.nickname}!",
239 "visibility" => "direct"
242 {:ok, _follower_only} =
243 CommonAPI.post(user_one, %{
244 "status" => "Hi @#{user_two.nickname}!",
245 "visibility" => "private"
248 # Only direct should be visible here
251 |> assign(:user, user_two)
252 |> get("api/v1/timelines/direct")
254 [status] = json_response(res_conn, 200)
256 assert %{"visibility" => "direct"} = status
257 assert status["url"] != direct.data["id"]
259 # User should be able to see his own direct message
262 |> assign(:user, user_one)
263 |> get("api/v1/timelines/direct")
265 [status] = json_response(res_conn, 200)
267 assert %{"visibility" => "direct"} = status
269 # Both should be visible here
272 |> assign(:user, user_two)
273 |> get("api/v1/timelines/home")
275 [_s1, _s2] = json_response(res_conn, 200)
278 Enum.each(1..20, fn _ ->
280 CommonAPI.post(user_one, %{
281 "status" => "Hi @#{user_two.nickname}!",
282 "visibility" => "direct"
288 |> assign(:user, user_two)
289 |> get("api/v1/timelines/direct")
291 statuses = json_response(res_conn, 200)
292 assert length(statuses) == 20
296 |> assign(:user, user_two)
297 |> get("api/v1/timelines/direct", %{max_id: List.last(statuses)["id"]})
299 [status] = json_response(res_conn, 200)
301 assert status["url"] != direct.data["id"]
304 test "Conversations", %{conn: conn} do
305 user_one = insert(:user)
306 user_two = insert(:user)
308 {:ok, user_two} = User.follow(user_two, user_one)
311 CommonAPI.post(user_one, %{
312 "status" => "Hi @#{user_two.nickname}!",
313 "visibility" => "direct"
316 {:ok, _follower_only} =
317 CommonAPI.post(user_one, %{
318 "status" => "Hi @#{user_two.nickname}!",
319 "visibility" => "private"
324 |> assign(:user, user_one)
325 |> get("/api/v1/conversations")
327 assert response = json_response(res_conn, 200)
332 "accounts" => res_accounts,
333 "last_status" => res_last_status,
338 assert length(res_accounts) == 2
339 assert is_binary(res_id)
340 assert unread == true
341 assert res_last_status["id"] == direct.id
343 # Apparently undocumented API endpoint
346 |> assign(:user, user_one)
347 |> post("/api/v1/conversations/#{res_id}/read")
349 assert response = json_response(res_conn, 200)
350 assert length(response["accounts"]) == 2
351 assert response["last_status"]["id"] == direct.id
352 assert response["unread"] == false
354 # (vanilla) Mastodon frontend behaviour
357 |> assign(:user, user_one)
358 |> get("/api/v1/statuses/#{res_last_status["id"]}/context")
360 assert %{"ancestors" => [], "descendants" => []} == json_response(res_conn, 200)
363 test "doesn't include DMs from blocked users", %{conn: conn} do
364 blocker = insert(:user)
365 blocked = insert(:user)
367 {:ok, blocker} = User.block(blocker, blocked)
369 {:ok, _blocked_direct} =
370 CommonAPI.post(blocked, %{
371 "status" => "Hi @#{blocker.nickname}!",
372 "visibility" => "direct"
376 CommonAPI.post(user, %{
377 "status" => "Hi @#{blocker.nickname}!",
378 "visibility" => "direct"
383 |> assign(:user, user)
384 |> get("api/v1/timelines/direct")
386 [status] = json_response(res_conn, 200)
387 assert status["id"] == direct.id
390 test "replying to a status", %{conn: conn} do
393 {:ok, replied_to} = TwitterAPI.create_status(user, %{"status" => "cofe"})
397 |> assign(:user, user)
398 |> post("/api/v1/statuses", %{"status" => "xD", "in_reply_to_id" => replied_to.id})
400 assert %{"content" => "xD", "id" => id} = json_response(conn, 200)
402 activity = Activity.get_by_id(id)
404 assert activity.data["context"] == replied_to.data["context"]
405 assert Activity.get_in_reply_to_activity(activity).id == replied_to.id
408 test "posting a status with an invalid in_reply_to_id", %{conn: conn} do
413 |> assign(:user, user)
414 |> post("/api/v1/statuses", %{"status" => "xD", "in_reply_to_id" => ""})
416 assert %{"content" => "xD", "id" => id} = json_response(conn, 200)
418 activity = Activity.get_by_id(id)
423 test "verify_credentials", %{conn: conn} do
428 |> assign(:user, user)
429 |> get("/api/v1/accounts/verify_credentials")
431 assert %{"id" => id, "source" => %{"privacy" => "public"}} = json_response(conn, 200)
432 assert id == to_string(user.id)
435 test "verify_credentials default scope unlisted", %{conn: conn} do
436 user = insert(:user, %{info: %Pleroma.User.Info{default_scope: "unlisted"}})
440 |> assign(:user, user)
441 |> get("/api/v1/accounts/verify_credentials")
443 assert %{"id" => id, "source" => %{"privacy" => "unlisted"}} = json_response(conn, 200)
444 assert id == to_string(user.id)
447 test "apps/verify_credentials", %{conn: conn} do
448 token = insert(:oauth_token)
452 |> assign(:user, token.user)
453 |> assign(:token, token)
454 |> get("/api/v1/apps/verify_credentials")
456 app = Repo.preload(token, :app).app
459 "name" => app.client_name,
460 "website" => app.website,
461 "vapid_key" => Push.vapid_config() |> Keyword.get(:public_key)
464 assert expected == json_response(conn, 200)
467 test "creates an oauth app", %{conn: conn} do
469 app_attrs = build(:oauth_app)
473 |> assign(:user, user)
474 |> post("/api/v1/apps", %{
475 client_name: app_attrs.client_name,
476 redirect_uris: app_attrs.redirect_uris
479 [app] = Repo.all(App)
482 "name" => app.client_name,
483 "website" => app.website,
484 "client_id" => app.client_id,
485 "client_secret" => app.client_secret,
486 "id" => app.id |> to_string(),
487 "redirect_uri" => app.redirect_uris,
488 "vapid_key" => Push.vapid_config() |> Keyword.get(:public_key)
491 assert expected == json_response(conn, 200)
494 test "get a status", %{conn: conn} do
495 activity = insert(:note_activity)
499 |> get("/api/v1/statuses/#{activity.id}")
501 assert %{"id" => id} = json_response(conn, 200)
502 assert id == to_string(activity.id)
505 describe "deleting a status" do
506 test "when you created it", %{conn: conn} do
507 activity = insert(:note_activity)
508 author = User.get_cached_by_ap_id(activity.data["actor"])
512 |> assign(:user, author)
513 |> delete("/api/v1/statuses/#{activity.id}")
515 assert %{} = json_response(conn, 200)
517 refute Activity.get_by_id(activity.id)
520 test "when you didn't create it", %{conn: conn} do
521 activity = insert(:note_activity)
526 |> assign(:user, user)
527 |> delete("/api/v1/statuses/#{activity.id}")
529 assert %{"error" => _} = json_response(conn, 403)
531 assert Activity.get_by_id(activity.id) == activity
534 test "when you're an admin or moderator", %{conn: conn} do
535 activity1 = insert(:note_activity)
536 activity2 = insert(:note_activity)
537 admin = insert(:user, info: %{is_admin: true})
538 moderator = insert(:user, info: %{is_moderator: true})
542 |> assign(:user, admin)
543 |> delete("/api/v1/statuses/#{activity1.id}")
545 assert %{} = json_response(res_conn, 200)
549 |> assign(:user, moderator)
550 |> delete("/api/v1/statuses/#{activity2.id}")
552 assert %{} = json_response(res_conn, 200)
554 refute Activity.get_by_id(activity1.id)
555 refute Activity.get_by_id(activity2.id)
559 describe "filters" do
560 test "creating a filter", %{conn: conn} do
563 filter = %Pleroma.Filter{
570 |> assign(:user, user)
571 |> post("/api/v1/filters", %{"phrase" => filter.phrase, context: filter.context})
573 assert response = json_response(conn, 200)
574 assert response["phrase"] == filter.phrase
575 assert response["context"] == filter.context
576 assert response["irreversible"] == false
577 assert response["id"] != nil
578 assert response["id"] != ""
581 test "fetching a list of filters", %{conn: conn} do
584 query_one = %Pleroma.Filter{
591 query_two = %Pleroma.Filter{
598 {:ok, filter_one} = Pleroma.Filter.create(query_one)
599 {:ok, filter_two} = Pleroma.Filter.create(query_two)
603 |> assign(:user, user)
604 |> get("/api/v1/filters")
605 |> json_response(200)
611 filters: [filter_two, filter_one]
615 test "get a filter", %{conn: conn} do
618 query = %Pleroma.Filter{
625 {:ok, filter} = Pleroma.Filter.create(query)
629 |> assign(:user, user)
630 |> get("/api/v1/filters/#{filter.filter_id}")
632 assert _response = json_response(conn, 200)
635 test "update a filter", %{conn: conn} do
638 query = %Pleroma.Filter{
645 {:ok, _filter} = Pleroma.Filter.create(query)
647 new = %Pleroma.Filter{
654 |> assign(:user, user)
655 |> put("/api/v1/filters/#{query.filter_id}", %{
660 assert response = json_response(conn, 200)
661 assert response["phrase"] == new.phrase
662 assert response["context"] == new.context
665 test "delete a filter", %{conn: conn} do
668 query = %Pleroma.Filter{
675 {:ok, filter} = Pleroma.Filter.create(query)
679 |> assign(:user, user)
680 |> delete("/api/v1/filters/#{filter.filter_id}")
682 assert response = json_response(conn, 200)
683 assert response == %{}
688 test "creating a list", %{conn: conn} do
693 |> assign(:user, user)
694 |> post("/api/v1/lists", %{"title" => "cuties"})
696 assert %{"title" => title} = json_response(conn, 200)
697 assert title == "cuties"
700 test "adding users to a list", %{conn: conn} do
702 other_user = insert(:user)
703 {:ok, list} = Pleroma.List.create("name", user)
707 |> assign(:user, user)
708 |> post("/api/v1/lists/#{list.id}/accounts", %{"account_ids" => [other_user.id]})
710 assert %{} == json_response(conn, 200)
711 %Pleroma.List{following: following} = Pleroma.List.get(list.id, user)
712 assert following == [other_user.follower_address]
715 test "removing users from a list", %{conn: conn} do
717 other_user = insert(:user)
718 third_user = insert(:user)
719 {:ok, list} = Pleroma.List.create("name", user)
720 {:ok, list} = Pleroma.List.follow(list, other_user)
721 {:ok, list} = Pleroma.List.follow(list, third_user)
725 |> assign(:user, user)
726 |> delete("/api/v1/lists/#{list.id}/accounts", %{"account_ids" => [other_user.id]})
728 assert %{} == json_response(conn, 200)
729 %Pleroma.List{following: following} = Pleroma.List.get(list.id, user)
730 assert following == [third_user.follower_address]
733 test "listing users in a list", %{conn: conn} do
735 other_user = insert(:user)
736 {:ok, list} = Pleroma.List.create("name", user)
737 {:ok, list} = Pleroma.List.follow(list, other_user)
741 |> assign(:user, user)
742 |> get("/api/v1/lists/#{list.id}/accounts", %{"account_ids" => [other_user.id]})
744 assert [%{"id" => id}] = json_response(conn, 200)
745 assert id == to_string(other_user.id)
748 test "retrieving a list", %{conn: conn} do
750 {:ok, list} = Pleroma.List.create("name", user)
754 |> assign(:user, user)
755 |> get("/api/v1/lists/#{list.id}")
757 assert %{"id" => id} = json_response(conn, 200)
758 assert id == to_string(list.id)
761 test "renaming a list", %{conn: conn} do
763 {:ok, list} = Pleroma.List.create("name", user)
767 |> assign(:user, user)
768 |> put("/api/v1/lists/#{list.id}", %{"title" => "newname"})
770 assert %{"title" => name} = json_response(conn, 200)
771 assert name == "newname"
774 test "deleting a list", %{conn: conn} do
776 {:ok, list} = Pleroma.List.create("name", user)
780 |> assign(:user, user)
781 |> delete("/api/v1/lists/#{list.id}")
783 assert %{} = json_response(conn, 200)
784 assert is_nil(Repo.get(Pleroma.List, list.id))
787 test "list timeline", %{conn: conn} do
789 other_user = insert(:user)
790 {:ok, _activity_one} = TwitterAPI.create_status(user, %{"status" => "Marisa is cute."})
791 {:ok, activity_two} = TwitterAPI.create_status(other_user, %{"status" => "Marisa is cute."})
792 {:ok, list} = Pleroma.List.create("name", user)
793 {:ok, list} = Pleroma.List.follow(list, other_user)
797 |> assign(:user, user)
798 |> get("/api/v1/timelines/list/#{list.id}")
800 assert [%{"id" => id}] = json_response(conn, 200)
802 assert id == to_string(activity_two.id)
805 test "list timeline does not leak non-public statuses for unfollowed users", %{conn: conn} do
807 other_user = insert(:user)
808 {:ok, activity_one} = TwitterAPI.create_status(other_user, %{"status" => "Marisa is cute."})
810 {:ok, _activity_two} =
811 TwitterAPI.create_status(other_user, %{
812 "status" => "Marisa is cute.",
813 "visibility" => "private"
816 {:ok, list} = Pleroma.List.create("name", user)
817 {:ok, list} = Pleroma.List.follow(list, other_user)
821 |> assign(:user, user)
822 |> get("/api/v1/timelines/list/#{list.id}")
824 assert [%{"id" => id}] = json_response(conn, 200)
826 assert id == to_string(activity_one.id)
830 describe "notifications" do
831 test "list of notifications", %{conn: conn} do
833 other_user = insert(:user)
836 TwitterAPI.create_status(other_user, %{"status" => "hi @#{user.nickname}"})
838 {:ok, [_notification]} = Notification.create_notifications(activity)
842 |> assign(:user, user)
843 |> get("/api/v1/notifications")
846 "hi <span class=\"h-card\"><a data-user=\"#{user.id}\" class=\"u-url mention\" href=\"#{
848 }\">@<span>#{user.nickname}</span></a></span>"
850 assert [%{"status" => %{"content" => response}} | _rest] = json_response(conn, 200)
851 assert response == expected_response
854 test "getting a single notification", %{conn: conn} do
856 other_user = insert(:user)
859 TwitterAPI.create_status(other_user, %{"status" => "hi @#{user.nickname}"})
861 {:ok, [notification]} = Notification.create_notifications(activity)
865 |> assign(:user, user)
866 |> get("/api/v1/notifications/#{notification.id}")
869 "hi <span class=\"h-card\"><a data-user=\"#{user.id}\" class=\"u-url mention\" href=\"#{
871 }\">@<span>#{user.nickname}</span></a></span>"
873 assert %{"status" => %{"content" => response}} = json_response(conn, 200)
874 assert response == expected_response
877 test "dismissing a single notification", %{conn: conn} do
879 other_user = insert(:user)
882 TwitterAPI.create_status(other_user, %{"status" => "hi @#{user.nickname}"})
884 {:ok, [notification]} = Notification.create_notifications(activity)
888 |> assign(:user, user)
889 |> post("/api/v1/notifications/dismiss", %{"id" => notification.id})
891 assert %{} = json_response(conn, 200)
894 test "clearing all notifications", %{conn: conn} do
896 other_user = insert(:user)
899 TwitterAPI.create_status(other_user, %{"status" => "hi @#{user.nickname}"})
901 {:ok, [_notification]} = Notification.create_notifications(activity)
905 |> assign(:user, user)
906 |> post("/api/v1/notifications/clear")
908 assert %{} = json_response(conn, 200)
912 |> assign(:user, user)
913 |> get("/api/v1/notifications")
915 assert all = json_response(conn, 200)
919 test "paginates notifications using min_id, since_id, max_id, and limit", %{conn: conn} do
921 other_user = insert(:user)
923 {:ok, activity1} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
924 {:ok, activity2} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
925 {:ok, activity3} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
926 {:ok, activity4} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
928 notification1_id = Repo.get_by(Notification, activity_id: activity1.id).id |> to_string()
929 notification2_id = Repo.get_by(Notification, activity_id: activity2.id).id |> to_string()
930 notification3_id = Repo.get_by(Notification, activity_id: activity3.id).id |> to_string()
931 notification4_id = Repo.get_by(Notification, activity_id: activity4.id).id |> to_string()
935 |> assign(:user, user)
940 |> get("/api/v1/notifications?limit=2&min_id=#{notification1_id}")
942 result = json_response(conn_res, 200)
943 assert [%{"id" => ^notification3_id}, %{"id" => ^notification2_id}] = result
948 |> get("/api/v1/notifications?limit=2&since_id=#{notification1_id}")
950 result = json_response(conn_res, 200)
951 assert [%{"id" => ^notification4_id}, %{"id" => ^notification3_id}] = result
956 |> get("/api/v1/notifications?limit=2&max_id=#{notification4_id}")
958 result = json_response(conn_res, 200)
959 assert [%{"id" => ^notification3_id}, %{"id" => ^notification2_id}] = result
962 test "filters notifications using exclude_types", %{conn: conn} do
964 other_user = insert(:user)
966 {:ok, mention_activity} = CommonAPI.post(other_user, %{"status" => "hey @#{user.nickname}"})
967 {:ok, create_activity} = CommonAPI.post(user, %{"status" => "hey"})
968 {:ok, favorite_activity, _} = CommonAPI.favorite(create_activity.id, other_user)
969 {:ok, reblog_activity, _} = CommonAPI.repeat(create_activity.id, other_user)
970 {:ok, _, _, follow_activity} = CommonAPI.follow(other_user, user)
972 mention_notification_id =
973 Repo.get_by(Notification, activity_id: mention_activity.id).id |> to_string()
975 favorite_notification_id =
976 Repo.get_by(Notification, activity_id: favorite_activity.id).id |> to_string()
978 reblog_notification_id =
979 Repo.get_by(Notification, activity_id: reblog_activity.id).id |> to_string()
981 follow_notification_id =
982 Repo.get_by(Notification, activity_id: follow_activity.id).id |> to_string()
986 |> assign(:user, user)
989 get(conn, "/api/v1/notifications", %{exclude_types: ["mention", "favourite", "reblog"]})
991 assert [%{"id" => ^follow_notification_id}] = json_response(conn_res, 200)
994 get(conn, "/api/v1/notifications", %{exclude_types: ["favourite", "reblog", "follow"]})
996 assert [%{"id" => ^mention_notification_id}] = json_response(conn_res, 200)
999 get(conn, "/api/v1/notifications", %{exclude_types: ["reblog", "follow", "mention"]})
1001 assert [%{"id" => ^favorite_notification_id}] = json_response(conn_res, 200)
1004 get(conn, "/api/v1/notifications", %{exclude_types: ["follow", "mention", "favourite"]})
1006 assert [%{"id" => ^reblog_notification_id}] = json_response(conn_res, 200)
1009 test "destroy multiple", %{conn: conn} do
1010 user = insert(:user)
1011 other_user = insert(:user)
1013 {:ok, activity1} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
1014 {:ok, activity2} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
1015 {:ok, activity3} = CommonAPI.post(user, %{"status" => "hi @#{other_user.nickname}"})
1016 {:ok, activity4} = CommonAPI.post(user, %{"status" => "hi @#{other_user.nickname}"})
1018 notification1_id = Repo.get_by(Notification, activity_id: activity1.id).id |> to_string()
1019 notification2_id = Repo.get_by(Notification, activity_id: activity2.id).id |> to_string()
1020 notification3_id = Repo.get_by(Notification, activity_id: activity3.id).id |> to_string()
1021 notification4_id = Repo.get_by(Notification, activity_id: activity4.id).id |> to_string()
1025 |> assign(:user, user)
1029 |> get("/api/v1/notifications")
1031 result = json_response(conn_res, 200)
1032 assert [%{"id" => ^notification2_id}, %{"id" => ^notification1_id}] = result
1036 |> assign(:user, other_user)
1040 |> get("/api/v1/notifications")
1042 result = json_response(conn_res, 200)
1043 assert [%{"id" => ^notification4_id}, %{"id" => ^notification3_id}] = result
1047 |> delete("/api/v1/notifications/destroy_multiple", %{
1048 "ids" => [notification1_id, notification2_id]
1051 assert json_response(conn_destroy, 200) == %{}
1055 |> get("/api/v1/notifications")
1057 result = json_response(conn_res, 200)
1058 assert [%{"id" => ^notification4_id}, %{"id" => ^notification3_id}] = result
1062 describe "reblogging" do
1063 test "reblogs and returns the reblogged status", %{conn: conn} do
1064 activity = insert(:note_activity)
1065 user = insert(:user)
1069 |> assign(:user, user)
1070 |> post("/api/v1/statuses/#{activity.id}/reblog")
1073 "reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 1},
1075 } = json_response(conn, 200)
1077 assert to_string(activity.id) == id
1080 test "reblogged status for another user", %{conn: conn} do
1081 activity = insert(:note_activity)
1082 user1 = insert(:user)
1083 user2 = insert(:user)
1084 user3 = insert(:user)
1085 CommonAPI.favorite(activity.id, user2)
1086 {:ok, _bookmark} = Pleroma.Bookmark.create(user2.id, activity.id)
1087 {:ok, reblog_activity1, _object} = CommonAPI.repeat(activity.id, user1)
1088 {:ok, _, _object} = CommonAPI.repeat(activity.id, user2)
1092 |> assign(:user, user3)
1093 |> get("/api/v1/statuses/#{reblog_activity1.id}")
1096 "reblog" => %{"id" => id, "reblogged" => false, "reblogs_count" => 2},
1097 "reblogged" => false,
1098 "favourited" => false,
1099 "bookmarked" => false
1100 } = json_response(conn_res, 200)
1104 |> assign(:user, user2)
1105 |> get("/api/v1/statuses/#{reblog_activity1.id}")
1108 "reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 2},
1109 "reblogged" => true,
1110 "favourited" => true,
1111 "bookmarked" => true
1112 } = json_response(conn_res, 200)
1114 assert to_string(activity.id) == id
1118 describe "unreblogging" do
1119 test "unreblogs and returns the unreblogged status", %{conn: conn} do
1120 activity = insert(:note_activity)
1121 user = insert(:user)
1123 {:ok, _, _} = CommonAPI.repeat(activity.id, user)
1127 |> assign(:user, user)
1128 |> post("/api/v1/statuses/#{activity.id}/unreblog")
1130 assert %{"id" => id, "reblogged" => false, "reblogs_count" => 0} = json_response(conn, 200)
1132 assert to_string(activity.id) == id
1136 describe "favoriting" do
1137 test "favs a status and returns it", %{conn: conn} do
1138 activity = insert(:note_activity)
1139 user = insert(:user)
1143 |> assign(:user, user)
1144 |> post("/api/v1/statuses/#{activity.id}/favourite")
1146 assert %{"id" => id, "favourites_count" => 1, "favourited" => true} =
1147 json_response(conn, 200)
1149 assert to_string(activity.id) == id
1152 test "returns 500 for a wrong id", %{conn: conn} do
1153 user = insert(:user)
1157 |> assign(:user, user)
1158 |> post("/api/v1/statuses/1/favourite")
1159 |> json_response(500)
1161 assert resp == "Something went wrong"
1165 describe "unfavoriting" do
1166 test "unfavorites a status and returns it", %{conn: conn} do
1167 activity = insert(:note_activity)
1168 user = insert(:user)
1170 {:ok, _, _} = CommonAPI.favorite(activity.id, user)
1174 |> assign(:user, user)
1175 |> post("/api/v1/statuses/#{activity.id}/unfavourite")
1177 assert %{"id" => id, "favourites_count" => 0, "favourited" => false} =
1178 json_response(conn, 200)
1180 assert to_string(activity.id) == id
1184 describe "user timelines" do
1185 test "gets a users statuses", %{conn: conn} do
1186 user_one = insert(:user)
1187 user_two = insert(:user)
1188 user_three = insert(:user)
1190 {:ok, user_three} = User.follow(user_three, user_one)
1192 {:ok, activity} = CommonAPI.post(user_one, %{"status" => "HI!!!"})
1194 {:ok, direct_activity} =
1195 CommonAPI.post(user_one, %{
1196 "status" => "Hi, @#{user_two.nickname}.",
1197 "visibility" => "direct"
1200 {:ok, private_activity} =
1201 CommonAPI.post(user_one, %{"status" => "private", "visibility" => "private"})
1205 |> get("/api/v1/accounts/#{user_one.id}/statuses")
1207 assert [%{"id" => id}] = json_response(resp, 200)
1208 assert id == to_string(activity.id)
1212 |> assign(:user, user_two)
1213 |> get("/api/v1/accounts/#{user_one.id}/statuses")
1215 assert [%{"id" => id_one}, %{"id" => id_two}] = json_response(resp, 200)
1216 assert id_one == to_string(direct_activity.id)
1217 assert id_two == to_string(activity.id)
1221 |> assign(:user, user_three)
1222 |> get("/api/v1/accounts/#{user_one.id}/statuses")
1224 assert [%{"id" => id_one}, %{"id" => id_two}] = json_response(resp, 200)
1225 assert id_one == to_string(private_activity.id)
1226 assert id_two == to_string(activity.id)
1229 test "unimplemented pinned statuses feature", %{conn: conn} do
1230 note = insert(:note_activity)
1231 user = User.get_cached_by_ap_id(note.data["actor"])
1235 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
1237 assert json_response(conn, 200) == []
1240 test "gets an users media", %{conn: conn} do
1241 note = insert(:note_activity)
1242 user = User.get_cached_by_ap_id(note.data["actor"])
1244 file = %Plug.Upload{
1245 content_type: "image/jpg",
1246 path: Path.absname("test/fixtures/image.jpg"),
1247 filename: "an_image.jpg"
1251 TwitterAPI.upload(file, user, "json")
1255 TwitterAPI.create_status(user, %{"status" => "cofe", "media_ids" => [media["media_id"]]})
1259 |> get("/api/v1/accounts/#{user.id}/statuses", %{"only_media" => "true"})
1261 assert [%{"id" => id}] = json_response(conn, 200)
1262 assert id == to_string(image_post.id)
1266 |> get("/api/v1/accounts/#{user.id}/statuses", %{"only_media" => "1"})
1268 assert [%{"id" => id}] = json_response(conn, 200)
1269 assert id == to_string(image_post.id)
1272 test "gets a user's statuses without reblogs", %{conn: conn} do
1273 user = insert(:user)
1274 {:ok, post} = CommonAPI.post(user, %{"status" => "HI!!!"})
1275 {:ok, _, _} = CommonAPI.repeat(post.id, user)
1279 |> get("/api/v1/accounts/#{user.id}/statuses", %{"exclude_reblogs" => "true"})
1281 assert [%{"id" => id}] = json_response(conn, 200)
1282 assert id == to_string(post.id)
1286 |> get("/api/v1/accounts/#{user.id}/statuses", %{"exclude_reblogs" => "1"})
1288 assert [%{"id" => id}] = json_response(conn, 200)
1289 assert id == to_string(post.id)
1293 describe "user relationships" do
1294 test "returns the relationships for the current user", %{conn: conn} do
1295 user = insert(:user)
1296 other_user = insert(:user)
1297 {:ok, user} = User.follow(user, other_user)
1301 |> assign(:user, user)
1302 |> get("/api/v1/accounts/relationships", %{"id" => [other_user.id]})
1304 assert [relationship] = json_response(conn, 200)
1306 assert to_string(other_user.id) == relationship["id"]
1310 describe "locked accounts" do
1311 test "/api/v1/follow_requests works" do
1312 user = insert(:user, %{info: %Pleroma.User.Info{locked: true}})
1313 other_user = insert(:user)
1315 {:ok, _activity} = ActivityPub.follow(other_user, user)
1317 user = User.get_cached_by_id(user.id)
1318 other_user = User.get_cached_by_id(other_user.id)
1320 assert User.following?(other_user, user) == false
1324 |> assign(:user, user)
1325 |> get("/api/v1/follow_requests")
1327 assert [relationship] = json_response(conn, 200)
1328 assert to_string(other_user.id) == relationship["id"]
1331 test "/api/v1/follow_requests/:id/authorize works" do
1332 user = insert(:user, %{info: %User.Info{locked: true}})
1333 other_user = insert(:user)
1335 {:ok, _activity} = ActivityPub.follow(other_user, user)
1337 user = User.get_cached_by_id(user.id)
1338 other_user = User.get_cached_by_id(other_user.id)
1340 assert User.following?(other_user, user) == false
1344 |> assign(:user, user)
1345 |> post("/api/v1/follow_requests/#{other_user.id}/authorize")
1347 assert relationship = json_response(conn, 200)
1348 assert to_string(other_user.id) == relationship["id"]
1350 user = User.get_cached_by_id(user.id)
1351 other_user = User.get_cached_by_id(other_user.id)
1353 assert User.following?(other_user, user) == true
1356 test "verify_credentials", %{conn: conn} do
1357 user = insert(:user, %{info: %Pleroma.User.Info{default_scope: "private"}})
1361 |> assign(:user, user)
1362 |> get("/api/v1/accounts/verify_credentials")
1364 assert %{"id" => id, "source" => %{"privacy" => "private"}} = json_response(conn, 200)
1365 assert id == to_string(user.id)
1368 test "/api/v1/follow_requests/:id/reject works" do
1369 user = insert(:user, %{info: %Pleroma.User.Info{locked: true}})
1370 other_user = insert(:user)
1372 {:ok, _activity} = ActivityPub.follow(other_user, user)
1374 user = User.get_cached_by_id(user.id)
1378 |> assign(:user, user)
1379 |> post("/api/v1/follow_requests/#{other_user.id}/reject")
1381 assert relationship = json_response(conn, 200)
1382 assert to_string(other_user.id) == relationship["id"]
1384 user = User.get_cached_by_id(user.id)
1385 other_user = User.get_cached_by_id(other_user.id)
1387 assert User.following?(other_user, user) == false
1391 test "account fetching", %{conn: conn} do
1392 user = insert(:user)
1396 |> get("/api/v1/accounts/#{user.id}")
1398 assert %{"id" => id} = json_response(conn, 200)
1399 assert id == to_string(user.id)
1403 |> get("/api/v1/accounts/-1")
1405 assert %{"error" => "Can't find user"} = json_response(conn, 404)
1408 test "account fetching also works nickname", %{conn: conn} do
1409 user = insert(:user)
1413 |> get("/api/v1/accounts/#{user.nickname}")
1415 assert %{"id" => id} = json_response(conn, 200)
1416 assert id == user.id
1419 test "media upload", %{conn: conn} do
1420 file = %Plug.Upload{
1421 content_type: "image/jpg",
1422 path: Path.absname("test/fixtures/image.jpg"),
1423 filename: "an_image.jpg"
1426 desc = "Description of the image"
1428 user = insert(:user)
1432 |> assign(:user, user)
1433 |> post("/api/v1/media", %{"file" => file, "description" => desc})
1435 assert media = json_response(conn, 200)
1437 assert media["type"] == "image"
1438 assert media["description"] == desc
1441 object = Repo.get(Object, media["id"])
1442 assert object.data["actor"] == User.ap_id(user)
1445 test "hashtag timeline", %{conn: conn} do
1446 following = insert(:user)
1449 {:ok, activity} = TwitterAPI.create_status(following, %{"status" => "test #2hu"})
1451 {:ok, [_activity]} =
1452 OStatus.fetch_activity_from_url("https://shitposter.club/notice/2827873")
1456 |> get("/api/v1/timelines/tag/2hu")
1458 assert [%{"id" => id}] = json_response(nconn, 200)
1460 assert id == to_string(activity.id)
1462 # works for different capitalization too
1465 |> get("/api/v1/timelines/tag/2HU")
1467 assert [%{"id" => id}] = json_response(nconn, 200)
1469 assert id == to_string(activity.id)
1473 test "multi-hashtag timeline", %{conn: conn} do
1474 user = insert(:user)
1476 {:ok, activity_test} = CommonAPI.post(user, %{"status" => "#test"})
1477 {:ok, activity_test1} = CommonAPI.post(user, %{"status" => "#test #test1"})
1478 {:ok, activity_none} = CommonAPI.post(user, %{"status" => "#test #none"})
1482 |> get("/api/v1/timelines/tag/test", %{"any" => ["test1"]})
1484 [status_none, status_test1, status_test] = json_response(any_test, 200)
1486 assert to_string(activity_test.id) == status_test["id"]
1487 assert to_string(activity_test1.id) == status_test1["id"]
1488 assert to_string(activity_none.id) == status_none["id"]
1492 |> get("/api/v1/timelines/tag/test", %{"all" => ["test1"], "none" => ["none"]})
1494 assert [status_test1] == json_response(restricted_test, 200)
1496 all_test = conn |> get("/api/v1/timelines/tag/test", %{"all" => ["none"]})
1498 assert [status_none] == json_response(all_test, 200)
1501 test "getting followers", %{conn: conn} do
1502 user = insert(:user)
1503 other_user = insert(:user)
1504 {:ok, user} = User.follow(user, other_user)
1508 |> get("/api/v1/accounts/#{other_user.id}/followers")
1510 assert [%{"id" => id}] = json_response(conn, 200)
1511 assert id == to_string(user.id)
1514 test "getting followers, hide_followers", %{conn: conn} do
1515 user = insert(:user)
1516 other_user = insert(:user, %{info: %{hide_followers: true}})
1517 {:ok, _user} = User.follow(user, other_user)
1521 |> get("/api/v1/accounts/#{other_user.id}/followers")
1523 assert [] == json_response(conn, 200)
1526 test "getting followers, hide_followers, same user requesting", %{conn: conn} do
1527 user = insert(:user)
1528 other_user = insert(:user, %{info: %{hide_followers: true}})
1529 {:ok, _user} = User.follow(user, other_user)
1533 |> assign(:user, other_user)
1534 |> get("/api/v1/accounts/#{other_user.id}/followers")
1536 refute [] == json_response(conn, 200)
1539 test "getting followers, pagination", %{conn: conn} do
1540 user = insert(:user)
1541 follower1 = insert(:user)
1542 follower2 = insert(:user)
1543 follower3 = insert(:user)
1544 {:ok, _} = User.follow(follower1, user)
1545 {:ok, _} = User.follow(follower2, user)
1546 {:ok, _} = User.follow(follower3, user)
1550 |> assign(:user, user)
1554 |> get("/api/v1/accounts/#{user.id}/followers?since_id=#{follower1.id}")
1556 assert [%{"id" => id3}, %{"id" => id2}] = json_response(res_conn, 200)
1557 assert id3 == follower3.id
1558 assert id2 == follower2.id
1562 |> get("/api/v1/accounts/#{user.id}/followers?max_id=#{follower3.id}")
1564 assert [%{"id" => id2}, %{"id" => id1}] = json_response(res_conn, 200)
1565 assert id2 == follower2.id
1566 assert id1 == follower1.id
1570 |> get("/api/v1/accounts/#{user.id}/followers?limit=1&max_id=#{follower3.id}")
1572 assert [%{"id" => id2}] = json_response(res_conn, 200)
1573 assert id2 == follower2.id
1575 assert [link_header] = get_resp_header(res_conn, "link")
1576 assert link_header =~ ~r/min_id=#{follower2.id}/
1577 assert link_header =~ ~r/max_id=#{follower2.id}/
1580 test "getting following", %{conn: conn} do
1581 user = insert(:user)
1582 other_user = insert(:user)
1583 {:ok, user} = User.follow(user, other_user)
1587 |> get("/api/v1/accounts/#{user.id}/following")
1589 assert [%{"id" => id}] = json_response(conn, 200)
1590 assert id == to_string(other_user.id)
1593 test "getting following, hide_follows", %{conn: conn} do
1594 user = insert(:user, %{info: %{hide_follows: true}})
1595 other_user = insert(:user)
1596 {:ok, user} = User.follow(user, other_user)
1600 |> get("/api/v1/accounts/#{user.id}/following")
1602 assert [] == json_response(conn, 200)
1605 test "getting following, hide_follows, same user requesting", %{conn: conn} do
1606 user = insert(:user, %{info: %{hide_follows: true}})
1607 other_user = insert(:user)
1608 {:ok, user} = User.follow(user, other_user)
1612 |> assign(:user, user)
1613 |> get("/api/v1/accounts/#{user.id}/following")
1615 refute [] == json_response(conn, 200)
1618 test "getting following, pagination", %{conn: conn} do
1619 user = insert(:user)
1620 following1 = insert(:user)
1621 following2 = insert(:user)
1622 following3 = insert(:user)
1623 {:ok, _} = User.follow(user, following1)
1624 {:ok, _} = User.follow(user, following2)
1625 {:ok, _} = User.follow(user, following3)
1629 |> assign(:user, user)
1633 |> get("/api/v1/accounts/#{user.id}/following?since_id=#{following1.id}")
1635 assert [%{"id" => id3}, %{"id" => id2}] = json_response(res_conn, 200)
1636 assert id3 == following3.id
1637 assert id2 == following2.id
1641 |> get("/api/v1/accounts/#{user.id}/following?max_id=#{following3.id}")
1643 assert [%{"id" => id2}, %{"id" => id1}] = json_response(res_conn, 200)
1644 assert id2 == following2.id
1645 assert id1 == following1.id
1649 |> get("/api/v1/accounts/#{user.id}/following?limit=1&max_id=#{following3.id}")
1651 assert [%{"id" => id2}] = json_response(res_conn, 200)
1652 assert id2 == following2.id
1654 assert [link_header] = get_resp_header(res_conn, "link")
1655 assert link_header =~ ~r/min_id=#{following2.id}/
1656 assert link_header =~ ~r/max_id=#{following2.id}/
1659 test "following / unfollowing a user", %{conn: conn} do
1660 user = insert(:user)
1661 other_user = insert(:user)
1665 |> assign(:user, user)
1666 |> post("/api/v1/accounts/#{other_user.id}/follow")
1668 assert %{"id" => _id, "following" => true} = json_response(conn, 200)
1670 user = User.get_cached_by_id(user.id)
1674 |> assign(:user, user)
1675 |> post("/api/v1/accounts/#{other_user.id}/unfollow")
1677 assert %{"id" => _id, "following" => false} = json_response(conn, 200)
1679 user = User.get_cached_by_id(user.id)
1683 |> assign(:user, user)
1684 |> post("/api/v1/follows", %{"uri" => other_user.nickname})
1686 assert %{"id" => id} = json_response(conn, 200)
1687 assert id == to_string(other_user.id)
1690 test "following without reblogs" do
1691 follower = insert(:user)
1692 followed = insert(:user)
1693 other_user = insert(:user)
1697 |> assign(:user, follower)
1698 |> post("/api/v1/accounts/#{followed.id}/follow?reblogs=false")
1700 assert %{"showing_reblogs" => false} = json_response(conn, 200)
1702 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "hey"})
1703 {:ok, reblog, _} = CommonAPI.repeat(activity.id, followed)
1707 |> assign(:user, User.get_cached_by_id(follower.id))
1708 |> get("/api/v1/timelines/home")
1710 assert [] == json_response(conn, 200)
1714 |> assign(:user, follower)
1715 |> post("/api/v1/accounts/#{followed.id}/follow?reblogs=true")
1717 assert %{"showing_reblogs" => true} = json_response(conn, 200)
1721 |> assign(:user, User.get_cached_by_id(follower.id))
1722 |> get("/api/v1/timelines/home")
1724 expected_activity_id = reblog.id
1725 assert [%{"id" => ^expected_activity_id}] = json_response(conn, 200)
1728 test "following / unfollowing errors" do
1729 user = insert(:user)
1733 |> assign(:user, user)
1736 conn_res = post(conn, "/api/v1/accounts/#{user.id}/follow")
1737 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
1740 user = User.get_cached_by_id(user.id)
1741 conn_res = post(conn, "/api/v1/accounts/#{user.id}/unfollow")
1742 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
1744 # self follow via uri
1745 user = User.get_cached_by_id(user.id)
1746 conn_res = post(conn, "/api/v1/follows", %{"uri" => user.nickname})
1747 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
1749 # follow non existing user
1750 conn_res = post(conn, "/api/v1/accounts/doesntexist/follow")
1751 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
1753 # follow non existing user via uri
1754 conn_res = post(conn, "/api/v1/follows", %{"uri" => "doesntexist"})
1755 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
1757 # unfollow non existing user
1758 conn_res = post(conn, "/api/v1/accounts/doesntexist/unfollow")
1759 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
1762 test "muting / unmuting a user", %{conn: conn} do
1763 user = insert(:user)
1764 other_user = insert(:user)
1768 |> assign(:user, user)
1769 |> post("/api/v1/accounts/#{other_user.id}/mute")
1771 assert %{"id" => _id, "muting" => true} = json_response(conn, 200)
1773 user = User.get_cached_by_id(user.id)
1777 |> assign(:user, user)
1778 |> post("/api/v1/accounts/#{other_user.id}/unmute")
1780 assert %{"id" => _id, "muting" => false} = json_response(conn, 200)
1783 test "subscribing / unsubscribing to a user", %{conn: conn} do
1784 user = insert(:user)
1785 subscription_target = insert(:user)
1789 |> assign(:user, user)
1790 |> post("/api/v1/pleroma/accounts/#{subscription_target.id}/subscribe")
1792 assert %{"id" => _id, "subscribing" => true} = json_response(conn, 200)
1796 |> assign(:user, user)
1797 |> post("/api/v1/pleroma/accounts/#{subscription_target.id}/unsubscribe")
1799 assert %{"id" => _id, "subscribing" => false} = json_response(conn, 200)
1802 test "getting a list of mutes", %{conn: conn} do
1803 user = insert(:user)
1804 other_user = insert(:user)
1806 {:ok, user} = User.mute(user, other_user)
1810 |> assign(:user, user)
1811 |> get("/api/v1/mutes")
1813 other_user_id = to_string(other_user.id)
1814 assert [%{"id" => ^other_user_id}] = json_response(conn, 200)
1817 test "blocking / unblocking a user", %{conn: conn} do
1818 user = insert(:user)
1819 other_user = insert(:user)
1823 |> assign(:user, user)
1824 |> post("/api/v1/accounts/#{other_user.id}/block")
1826 assert %{"id" => _id, "blocking" => true} = json_response(conn, 200)
1828 user = User.get_cached_by_id(user.id)
1832 |> assign(:user, user)
1833 |> post("/api/v1/accounts/#{other_user.id}/unblock")
1835 assert %{"id" => _id, "blocking" => false} = json_response(conn, 200)
1838 test "getting a list of blocks", %{conn: conn} do
1839 user = insert(:user)
1840 other_user = insert(:user)
1842 {:ok, user} = User.block(user, other_user)
1846 |> assign(:user, user)
1847 |> get("/api/v1/blocks")
1849 other_user_id = to_string(other_user.id)
1850 assert [%{"id" => ^other_user_id}] = json_response(conn, 200)
1853 test "blocking / unblocking a domain", %{conn: conn} do
1854 user = insert(:user)
1855 other_user = insert(:user, %{ap_id: "https://dogwhistle.zone/@pundit"})
1859 |> assign(:user, user)
1860 |> post("/api/v1/domain_blocks", %{"domain" => "dogwhistle.zone"})
1862 assert %{} = json_response(conn, 200)
1863 user = User.get_cached_by_ap_id(user.ap_id)
1864 assert User.blocks?(user, other_user)
1868 |> assign(:user, user)
1869 |> delete("/api/v1/domain_blocks", %{"domain" => "dogwhistle.zone"})
1871 assert %{} = json_response(conn, 200)
1872 user = User.get_cached_by_ap_id(user.ap_id)
1873 refute User.blocks?(user, other_user)
1876 test "getting a list of domain blocks", %{conn: conn} do
1877 user = insert(:user)
1879 {:ok, user} = User.block_domain(user, "bad.site")
1880 {:ok, user} = User.block_domain(user, "even.worse.site")
1884 |> assign(:user, user)
1885 |> get("/api/v1/domain_blocks")
1887 domain_blocks = json_response(conn, 200)
1889 assert "bad.site" in domain_blocks
1890 assert "even.worse.site" in domain_blocks
1893 test "unimplemented follow_requests, blocks, domain blocks" do
1894 user = insert(:user)
1896 ["blocks", "domain_blocks", "follow_requests"]
1897 |> Enum.each(fn endpoint ->
1900 |> assign(:user, user)
1901 |> get("/api/v1/#{endpoint}")
1903 assert [] = json_response(conn, 200)
1907 test "account search", %{conn: conn} do
1908 user = insert(:user)
1909 user_two = insert(:user, %{nickname: "shp@shitposter.club"})
1910 user_three = insert(:user, %{nickname: "shp@heldscal.la", name: "I love 2hu"})
1914 |> assign(:user, user)
1915 |> get("/api/v1/accounts/search", %{"q" => "shp"})
1916 |> json_response(200)
1918 result_ids = for result <- results, do: result["acct"]
1920 assert user_two.nickname in result_ids
1921 assert user_three.nickname in result_ids
1925 |> assign(:user, user)
1926 |> get("/api/v1/accounts/search", %{"q" => "2hu"})
1927 |> json_response(200)
1929 result_ids = for result <- results, do: result["acct"]
1931 assert user_three.nickname in result_ids
1934 test "search", %{conn: conn} do
1935 user = insert(:user)
1936 user_two = insert(:user, %{nickname: "shp@shitposter.club"})
1937 user_three = insert(:user, %{nickname: "shp@heldscal.la", name: "I love 2hu"})
1939 {:ok, activity} = CommonAPI.post(user, %{"status" => "This is about 2hu"})
1942 CommonAPI.post(user, %{
1943 "status" => "This is about 2hu, but private",
1944 "visibility" => "private"
1947 {:ok, _} = CommonAPI.post(user_two, %{"status" => "This isn't"})
1951 |> get("/api/v1/search", %{"q" => "2hu"})
1953 assert results = json_response(conn, 200)
1955 [account | _] = results["accounts"]
1956 assert account["id"] == to_string(user_three.id)
1958 assert results["hashtags"] == []
1960 [status] = results["statuses"]
1961 assert status["id"] == to_string(activity.id)
1964 test "search fetches remote statuses", %{conn: conn} do
1968 |> get("/api/v1/search", %{"q" => "https://shitposter.club/notice/2827873"})
1970 assert results = json_response(conn, 200)
1972 [status] = results["statuses"]
1973 assert status["uri"] == "tag:shitposter.club,2017-05-05:noticeId=2827873:objectType=comment"
1977 test "search doesn't show statuses that it shouldn't", %{conn: conn} do
1979 CommonAPI.post(insert(:user), %{
1980 "status" => "This is about 2hu, but private",
1981 "visibility" => "private"
1987 |> get("/api/v1/search", %{"q" => Object.normalize(activity).data["id"]})
1989 assert results = json_response(conn, 200)
1991 [] = results["statuses"]
1995 test "search fetches remote accounts", %{conn: conn} do
1998 |> get("/api/v1/search", %{"q" => "shp@social.heldscal.la", "resolve" => "true"})
2000 assert results = json_response(conn, 200)
2001 [account] = results["accounts"]
2002 assert account["acct"] == "shp@social.heldscal.la"
2005 test "returns the favorites of a user", %{conn: conn} do
2006 user = insert(:user)
2007 other_user = insert(:user)
2009 {:ok, _} = CommonAPI.post(other_user, %{"status" => "bla"})
2010 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "traps are happy"})
2012 {:ok, _, _} = CommonAPI.favorite(activity.id, user)
2016 |> assign(:user, user)
2017 |> get("/api/v1/favourites")
2019 assert [status] = json_response(first_conn, 200)
2020 assert status["id"] == to_string(activity.id)
2022 assert [{"link", _link_header}] =
2023 Enum.filter(first_conn.resp_headers, fn element -> match?({"link", _}, element) end)
2025 # Honours query params
2026 {:ok, second_activity} =
2027 CommonAPI.post(other_user, %{
2029 "Trees Are Never Sad Look At Them Every Once In Awhile They're Quite Beautiful."
2032 {:ok, _, _} = CommonAPI.favorite(second_activity.id, user)
2034 last_like = status["id"]
2038 |> assign(:user, user)
2039 |> get("/api/v1/favourites?since_id=#{last_like}")
2041 assert [second_status] = json_response(second_conn, 200)
2042 assert second_status["id"] == to_string(second_activity.id)
2046 |> assign(:user, user)
2047 |> get("/api/v1/favourites?limit=0")
2049 assert [] = json_response(third_conn, 200)
2052 describe "getting favorites timeline of specified user" do
2054 [current_user, user] = insert_pair(:user, %{info: %{hide_favorites: false}})
2055 [current_user: current_user, user: user]
2058 test "returns list of statuses favorited by specified user", %{
2060 current_user: current_user,
2063 [activity | _] = insert_pair(:note_activity)
2064 CommonAPI.favorite(activity.id, user)
2068 |> assign(:user, current_user)
2069 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2070 |> json_response(:ok)
2074 assert length(response) == 1
2075 assert like["id"] == activity.id
2078 test "returns favorites for specified user_id when user is not logged in", %{
2082 activity = insert(:note_activity)
2083 CommonAPI.favorite(activity.id, user)
2087 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2088 |> json_response(:ok)
2090 assert length(response) == 1
2093 test "returns favorited DM only when user is logged in and he is one of recipients", %{
2095 current_user: current_user,
2099 CommonAPI.post(current_user, %{
2100 "status" => "Hi @#{user.nickname}!",
2101 "visibility" => "direct"
2104 CommonAPI.favorite(direct.id, user)
2108 |> assign(:user, current_user)
2109 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2110 |> json_response(:ok)
2112 assert length(response) == 1
2114 anonymous_response =
2116 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2117 |> json_response(:ok)
2119 assert length(anonymous_response) == 0
2122 test "does not return others' favorited DM when user is not one of recipients", %{
2124 current_user: current_user,
2127 user_two = insert(:user)
2130 CommonAPI.post(user_two, %{
2131 "status" => "Hi @#{user.nickname}!",
2132 "visibility" => "direct"
2135 CommonAPI.favorite(direct.id, user)
2139 |> assign(:user, current_user)
2140 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2141 |> json_response(:ok)
2143 assert length(response) == 0
2146 test "paginates favorites using since_id and max_id", %{
2148 current_user: current_user,
2151 activities = insert_list(10, :note_activity)
2153 Enum.each(activities, fn activity ->
2154 CommonAPI.favorite(activity.id, user)
2157 third_activity = Enum.at(activities, 2)
2158 seventh_activity = Enum.at(activities, 6)
2162 |> assign(:user, current_user)
2163 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites", %{
2164 since_id: third_activity.id,
2165 max_id: seventh_activity.id
2167 |> json_response(:ok)
2169 assert length(response) == 3
2170 refute third_activity in response
2171 refute seventh_activity in response
2174 test "limits favorites using limit parameter", %{
2176 current_user: current_user,
2180 |> insert_list(:note_activity)
2181 |> Enum.each(fn activity ->
2182 CommonAPI.favorite(activity.id, user)
2187 |> assign(:user, current_user)
2188 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites", %{limit: "3"})
2189 |> json_response(:ok)
2191 assert length(response) == 3
2194 test "returns empty response when user does not have any favorited statuses", %{
2196 current_user: current_user,
2201 |> assign(:user, current_user)
2202 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2203 |> json_response(:ok)
2205 assert Enum.empty?(response)
2208 test "returns 404 error when specified user is not exist", %{conn: conn} do
2209 conn = get(conn, "/api/v1/pleroma/accounts/test/favourites")
2211 assert json_response(conn, 404) == %{"error" => "Record not found"}
2214 test "returns 403 error when user has hidden own favorites", %{
2216 current_user: current_user
2218 user = insert(:user, %{info: %{hide_favorites: true}})
2219 activity = insert(:note_activity)
2220 CommonAPI.favorite(activity.id, user)
2224 |> assign(:user, current_user)
2225 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2227 assert json_response(conn, 403) == %{"error" => "Can't get favorites"}
2230 test "hides favorites for new users by default", %{conn: conn, current_user: current_user} do
2231 user = insert(:user)
2232 activity = insert(:note_activity)
2233 CommonAPI.favorite(activity.id, user)
2237 |> assign(:user, current_user)
2238 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2240 assert user.info.hide_favorites
2241 assert json_response(conn, 403) == %{"error" => "Can't get favorites"}
2245 describe "updating credentials" do
2246 test "updates the user's bio", %{conn: conn} do
2247 user = insert(:user)
2248 user2 = insert(:user)
2252 |> assign(:user, user)
2253 |> patch("/api/v1/accounts/update_credentials", %{
2254 "note" => "I drink #cofe with @#{user2.nickname}"
2257 assert user = json_response(conn, 200)
2259 assert user["note"] ==
2260 ~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=") <>
2262 ~s(" class="u-url mention" href=") <>
2263 user2.ap_id <> ~s(">@<span>) <> user2.nickname <> ~s(</span></a></span>)
2266 test "updates the user's locking status", %{conn: conn} do
2267 user = insert(:user)
2271 |> assign(:user, user)
2272 |> patch("/api/v1/accounts/update_credentials", %{locked: "true"})
2274 assert user = json_response(conn, 200)
2275 assert user["locked"] == true
2278 test "updates the user's default scope", %{conn: conn} do
2279 user = insert(:user)
2283 |> assign(:user, user)
2284 |> patch("/api/v1/accounts/update_credentials", %{default_scope: "cofe"})
2286 assert user = json_response(conn, 200)
2287 assert user["source"]["privacy"] == "cofe"
2290 test "updates the user's hide_followers status", %{conn: conn} do
2291 user = insert(:user)
2295 |> assign(:user, user)
2296 |> patch("/api/v1/accounts/update_credentials", %{hide_followers: "true"})
2298 assert user = json_response(conn, 200)
2299 assert user["pleroma"]["hide_followers"] == true
2302 test "updates the user's hide_follows status", %{conn: conn} do
2303 user = insert(:user)
2307 |> assign(:user, user)
2308 |> patch("/api/v1/accounts/update_credentials", %{hide_follows: "true"})
2310 assert user = json_response(conn, 200)
2311 assert user["pleroma"]["hide_follows"] == true
2314 test "updates the user's hide_favorites status", %{conn: conn} do
2315 user = insert(:user)
2319 |> assign(:user, user)
2320 |> patch("/api/v1/accounts/update_credentials", %{hide_favorites: "true"})
2322 assert user = json_response(conn, 200)
2323 assert user["pleroma"]["hide_favorites"] == true
2326 test "updates the user's show_role status", %{conn: conn} do
2327 user = insert(:user)
2331 |> assign(:user, user)
2332 |> patch("/api/v1/accounts/update_credentials", %{show_role: "false"})
2334 assert user = json_response(conn, 200)
2335 assert user["source"]["pleroma"]["show_role"] == false
2338 test "updates the user's no_rich_text status", %{conn: conn} do
2339 user = insert(:user)
2343 |> assign(:user, user)
2344 |> patch("/api/v1/accounts/update_credentials", %{no_rich_text: "true"})
2346 assert user = json_response(conn, 200)
2347 assert user["source"]["pleroma"]["no_rich_text"] == true
2350 test "updates the user's name", %{conn: conn} do
2351 user = insert(:user)
2355 |> assign(:user, user)
2356 |> patch("/api/v1/accounts/update_credentials", %{"display_name" => "markorepairs"})
2358 assert user = json_response(conn, 200)
2359 assert user["display_name"] == "markorepairs"
2362 test "updates the user's avatar", %{conn: conn} do
2363 user = insert(:user)
2365 new_avatar = %Plug.Upload{
2366 content_type: "image/jpg",
2367 path: Path.absname("test/fixtures/image.jpg"),
2368 filename: "an_image.jpg"
2373 |> assign(:user, user)
2374 |> patch("/api/v1/accounts/update_credentials", %{"avatar" => new_avatar})
2376 assert user_response = json_response(conn, 200)
2377 assert user_response["avatar"] != User.avatar_url(user)
2380 test "updates the user's banner", %{conn: conn} do
2381 user = insert(:user)
2383 new_header = %Plug.Upload{
2384 content_type: "image/jpg",
2385 path: Path.absname("test/fixtures/image.jpg"),
2386 filename: "an_image.jpg"
2391 |> assign(:user, user)
2392 |> patch("/api/v1/accounts/update_credentials", %{"header" => new_header})
2394 assert user_response = json_response(conn, 200)
2395 assert user_response["header"] != User.banner_url(user)
2398 test "requires 'write' permission", %{conn: conn} do
2399 token1 = insert(:oauth_token, scopes: ["read"])
2400 token2 = insert(:oauth_token, scopes: ["write", "follow"])
2402 for token <- [token1, token2] do
2405 |> put_req_header("authorization", "Bearer #{token.token}")
2406 |> patch("/api/v1/accounts/update_credentials", %{})
2408 if token == token1 do
2409 assert %{"error" => "Insufficient permissions: write."} == json_response(conn, 403)
2411 assert json_response(conn, 200)
2416 test "updates profile emojos", %{conn: conn} do
2417 user = insert(:user)
2419 note = "*sips :blank:*"
2420 name = "I am :firefox:"
2424 |> assign(:user, user)
2425 |> patch("/api/v1/accounts/update_credentials", %{
2427 "display_name" => name
2430 assert json_response(conn, 200)
2434 |> get("/api/v1/accounts/#{user.id}")
2436 assert user = json_response(conn, 200)
2438 assert user["note"] == note
2439 assert user["display_name"] == name
2440 assert [%{"shortcode" => "blank"}, %{"shortcode" => "firefox"}] = user["emojis"]
2444 test "get instance information", %{conn: conn} do
2445 conn = get(conn, "/api/v1/instance")
2446 assert result = json_response(conn, 200)
2448 email = Pleroma.Config.get([:instance, :email])
2449 # Note: not checking for "max_toot_chars" since it's optional
2455 "email" => from_config_email,
2457 "streaming_api" => _
2462 "registrations" => _
2465 assert email == from_config_email
2468 test "get instance stats", %{conn: conn} do
2469 user = insert(:user, %{local: true})
2471 user2 = insert(:user, %{local: true})
2472 {:ok, _user2} = User.deactivate(user2, !user2.info.deactivated)
2474 insert(:user, %{local: false, nickname: "u@peer1.com"})
2475 insert(:user, %{local: false, nickname: "u@peer2.com"})
2477 {:ok, _} = TwitterAPI.create_status(user, %{"status" => "cofe"})
2479 # Stats should count users with missing or nil `info.deactivated` value
2480 user = User.get_cached_by_id(user.id)
2481 info_change = Changeset.change(user.info, %{deactivated: nil})
2485 |> Changeset.change()
2486 |> Changeset.put_embed(:info, info_change)
2487 |> User.update_and_set_cache()
2489 Pleroma.Stats.update_stats()
2491 conn = get(conn, "/api/v1/instance")
2493 assert result = json_response(conn, 200)
2495 stats = result["stats"]
2498 assert stats["user_count"] == 1
2499 assert stats["status_count"] == 1
2500 assert stats["domain_count"] == 2
2503 test "get peers", %{conn: conn} do
2504 insert(:user, %{local: false, nickname: "u@peer1.com"})
2505 insert(:user, %{local: false, nickname: "u@peer2.com"})
2507 Pleroma.Stats.update_stats()
2509 conn = get(conn, "/api/v1/instance/peers")
2511 assert result = json_response(conn, 200)
2513 assert ["peer1.com", "peer2.com"] == Enum.sort(result)
2516 test "put settings", %{conn: conn} do
2517 user = insert(:user)
2521 |> assign(:user, user)
2522 |> put("/api/web/settings", %{"data" => %{"programming" => "socks"}})
2524 assert _result = json_response(conn, 200)
2526 user = User.get_cached_by_ap_id(user.ap_id)
2527 assert user.info.settings == %{"programming" => "socks"}
2530 describe "pinned statuses" do
2532 Pleroma.Config.put([:instance, :max_pinned_statuses], 1)
2534 user = insert(:user)
2535 {:ok, activity} = CommonAPI.post(user, %{"status" => "HI!!!"})
2537 [user: user, activity: activity]
2540 test "returns pinned statuses", %{conn: conn, user: user, activity: activity} do
2541 {:ok, _} = CommonAPI.pin(activity.id, user)
2545 |> assign(:user, user)
2546 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
2547 |> json_response(200)
2549 id_str = to_string(activity.id)
2551 assert [%{"id" => ^id_str, "pinned" => true}] = result
2554 test "pin status", %{conn: conn, user: user, activity: activity} do
2555 id_str = to_string(activity.id)
2557 assert %{"id" => ^id_str, "pinned" => true} =
2559 |> assign(:user, user)
2560 |> post("/api/v1/statuses/#{activity.id}/pin")
2561 |> json_response(200)
2563 assert [%{"id" => ^id_str, "pinned" => true}] =
2565 |> assign(:user, user)
2566 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
2567 |> json_response(200)
2570 test "unpin status", %{conn: conn, user: user, activity: activity} do
2571 {:ok, _} = CommonAPI.pin(activity.id, user)
2573 id_str = to_string(activity.id)
2574 user = refresh_record(user)
2576 assert %{"id" => ^id_str, "pinned" => false} =
2578 |> assign(:user, user)
2579 |> post("/api/v1/statuses/#{activity.id}/unpin")
2580 |> json_response(200)
2584 |> assign(:user, user)
2585 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
2586 |> json_response(200)
2589 test "max pinned statuses", %{conn: conn, user: user, activity: activity_one} do
2590 {:ok, activity_two} = CommonAPI.post(user, %{"status" => "HI!!!"})
2592 id_str_one = to_string(activity_one.id)
2594 assert %{"id" => ^id_str_one, "pinned" => true} =
2596 |> assign(:user, user)
2597 |> post("/api/v1/statuses/#{id_str_one}/pin")
2598 |> json_response(200)
2600 user = refresh_record(user)
2602 assert %{"error" => "You have already pinned the maximum number of statuses"} =
2604 |> assign(:user, user)
2605 |> post("/api/v1/statuses/#{activity_two.id}/pin")
2606 |> json_response(400)
2609 test "Status rich-media Card", %{conn: conn, user: user} do
2610 Pleroma.Config.put([:rich_media, :enabled], true)
2611 {:ok, activity} = CommonAPI.post(user, %{"status" => "http://example.com/ogp"})
2615 |> get("/api/v1/statuses/#{activity.id}/card")
2616 |> json_response(200)
2618 assert response == %{
2619 "image" => "http://ia.media-imdb.com/images/rock.jpg",
2620 "provider_name" => "www.imdb.com",
2621 "provider_url" => "http://www.imdb.com",
2622 "title" => "The Rock",
2624 "url" => "http://www.imdb.com/title/tt0117500/",
2625 "description" => nil,
2628 "image" => "http://ia.media-imdb.com/images/rock.jpg",
2629 "title" => "The Rock",
2630 "type" => "video.movie",
2631 "url" => "http://www.imdb.com/title/tt0117500/"
2636 # works with private posts
2638 CommonAPI.post(user, %{"status" => "http://example.com/ogp", "visibility" => "direct"})
2642 |> assign(:user, user)
2643 |> get("/api/v1/statuses/#{activity.id}/card")
2644 |> json_response(200)
2646 assert response_two == response
2648 Pleroma.Config.put([:rich_media, :enabled], false)
2653 user = insert(:user)
2654 for_user = insert(:user)
2657 CommonAPI.post(user, %{
2658 "status" => "heweoo?"
2662 CommonAPI.post(user, %{
2663 "status" => "heweoo!"
2668 |> assign(:user, for_user)
2669 |> post("/api/v1/statuses/#{activity1.id}/bookmark")
2671 assert json_response(response1, 200)["bookmarked"] == true
2675 |> assign(:user, for_user)
2676 |> post("/api/v1/statuses/#{activity2.id}/bookmark")
2678 assert json_response(response2, 200)["bookmarked"] == true
2682 |> assign(:user, for_user)
2683 |> get("/api/v1/bookmarks")
2685 assert [json_response(response2, 200), json_response(response1, 200)] ==
2686 json_response(bookmarks, 200)
2690 |> assign(:user, for_user)
2691 |> post("/api/v1/statuses/#{activity1.id}/unbookmark")
2693 assert json_response(response1, 200)["bookmarked"] == false
2697 |> assign(:user, for_user)
2698 |> get("/api/v1/bookmarks")
2700 assert [json_response(response2, 200)] == json_response(bookmarks, 200)
2703 describe "conversation muting" do
2705 user = insert(:user)
2706 {:ok, activity} = CommonAPI.post(user, %{"status" => "HIE"})
2708 [user: user, activity: activity]
2711 test "mute conversation", %{conn: conn, user: user, activity: activity} do
2712 id_str = to_string(activity.id)
2714 assert %{"id" => ^id_str, "muted" => true} =
2716 |> assign(:user, user)
2717 |> post("/api/v1/statuses/#{activity.id}/mute")
2718 |> json_response(200)
2721 test "unmute conversation", %{conn: conn, user: user, activity: activity} do
2722 {:ok, _} = CommonAPI.add_mute(user, activity)
2724 id_str = to_string(activity.id)
2725 user = refresh_record(user)
2727 assert %{"id" => ^id_str, "muted" => false} =
2729 |> assign(:user, user)
2730 |> post("/api/v1/statuses/#{activity.id}/unmute")
2731 |> json_response(200)
2735 test "flavours switching (Pleroma Extension)", %{conn: conn} do
2736 user = insert(:user)
2740 |> assign(:user, user)
2741 |> get("/api/v1/pleroma/flavour")
2743 assert "glitch" == json_response(get_old_flavour, 200)
2747 |> assign(:user, user)
2748 |> post("/api/v1/pleroma/flavour/vanilla")
2750 assert "vanilla" == json_response(set_flavour, 200)
2754 |> assign(:user, user)
2755 |> post("/api/v1/pleroma/flavour/vanilla")
2757 assert json_response(set_flavour, 200) == json_response(get_new_flavour, 200)
2760 describe "reports" do
2762 reporter = insert(:user)
2763 target_user = insert(:user)
2765 {:ok, activity} = CommonAPI.post(target_user, %{"status" => "foobar"})
2767 [reporter: reporter, target_user: target_user, activity: activity]
2770 test "submit a basic report", %{conn: conn, reporter: reporter, target_user: target_user} do
2771 assert %{"action_taken" => false, "id" => _} =
2773 |> assign(:user, reporter)
2774 |> post("/api/v1/reports", %{"account_id" => target_user.id})
2775 |> json_response(200)
2778 test "submit a report with statuses and comment", %{
2781 target_user: target_user,
2784 assert %{"action_taken" => false, "id" => _} =
2786 |> assign(:user, reporter)
2787 |> post("/api/v1/reports", %{
2788 "account_id" => target_user.id,
2789 "status_ids" => [activity.id],
2790 "comment" => "bad status!"
2792 |> json_response(200)
2795 test "account_id is required", %{
2800 assert %{"error" => "Valid `account_id` required"} =
2802 |> assign(:user, reporter)
2803 |> post("/api/v1/reports", %{"status_ids" => [activity.id]})
2804 |> json_response(400)
2807 test "comment must be up to the size specified in the config", %{
2810 target_user: target_user
2812 max_size = Pleroma.Config.get([:instance, :max_report_comment_size], 1000)
2813 comment = String.pad_trailing("a", max_size + 1, "a")
2815 error = %{"error" => "Comment must be up to #{max_size} characters"}
2819 |> assign(:user, reporter)
2820 |> post("/api/v1/reports", %{"account_id" => target_user.id, "comment" => comment})
2821 |> json_response(400)
2825 describe "link headers" do
2826 test "preserves parameters in link headers", %{conn: conn} do
2827 user = insert(:user)
2828 other_user = insert(:user)
2831 CommonAPI.post(other_user, %{
2832 "status" => "hi @#{user.nickname}",
2833 "visibility" => "public"
2837 CommonAPI.post(other_user, %{
2838 "status" => "hi @#{user.nickname}",
2839 "visibility" => "public"
2842 notification1 = Repo.get_by(Notification, activity_id: activity1.id)
2843 notification2 = Repo.get_by(Notification, activity_id: activity2.id)
2847 |> assign(:user, user)
2848 |> get("/api/v1/notifications", %{media_only: true})
2850 assert [link_header] = get_resp_header(conn, "link")
2851 assert link_header =~ ~r/media_only=true/
2852 assert link_header =~ ~r/min_id=#{notification2.id}/
2853 assert link_header =~ ~r/max_id=#{notification1.id}/
2857 test "accounts fetches correct account for nicknames beginning with numbers", %{conn: conn} do
2858 # Need to set an old-style integer ID to reproduce the problem
2859 # (these are no longer assigned to new accounts but were preserved
2860 # for existing accounts during the migration to flakeIDs)
2861 user_one = insert(:user, %{id: 1212})
2862 user_two = insert(:user, %{nickname: "#{user_one.id}garbage"})
2866 |> get("/api/v1/accounts/#{user_one.id}")
2870 |> get("/api/v1/accounts/#{user_two.nickname}")
2874 |> get("/api/v1/accounts/#{user_two.id}")
2876 acc_one = json_response(resp_one, 200)
2877 acc_two = json_response(resp_two, 200)
2878 acc_three = json_response(resp_three, 200)
2879 refute acc_one == acc_two
2880 assert acc_two == acc_three
2883 describe "custom emoji" do
2884 test "with tags", %{conn: conn} do
2887 |> get("/api/v1/custom_emojis")
2888 |> json_response(200)
2890 assert Map.has_key?(emoji, "shortcode")
2891 assert Map.has_key?(emoji, "static_url")
2892 assert Map.has_key?(emoji, "tags")
2893 assert is_list(emoji["tags"])
2894 assert Map.has_key?(emoji, "url")
2895 assert Map.has_key?(emoji, "visible_in_picker")
2899 describe "index/2 redirections" do
2900 setup %{conn: conn} do
2904 signing_salt: "cooldude"
2909 |> Plug.Session.call(Plug.Session.init(session_opts))
2912 test_path = "/web/statuses/test"
2913 %{conn: conn, path: test_path}
2916 test "redirects not logged-in users to the login page", %{conn: conn, path: path} do
2917 conn = get(conn, path)
2919 assert conn.status == 302
2920 assert redirected_to(conn) == "/web/login"
2923 test "does not redirect logged in users to the login page", %{conn: conn, path: path} do
2924 token = insert(:oauth_token)
2928 |> assign(:user, token.user)
2929 |> put_session(:oauth_token, token.token)
2932 assert conn.status == 200
2935 test "saves referer path to session", %{conn: conn, path: path} do
2936 conn = get(conn, path)
2937 return_to = Plug.Conn.get_session(conn, :return_to)
2939 assert return_to == path
2942 test "redirects to the saved path after log in", %{conn: conn, path: path} do
2943 app = insert(:oauth_app, client_name: "Mastodon-Local", redirect_uris: ".")
2944 auth = insert(:oauth_authorization, app: app)
2948 |> put_session(:return_to, path)
2949 |> get("/web/login", %{code: auth.token})
2951 assert conn.status == 302
2952 assert redirected_to(conn) == path
2955 test "redirects to the getting-started page when referer is not present", %{conn: conn} do
2956 app = insert(:oauth_app, client_name: "Mastodon-Local", redirect_uris: ".")
2957 auth = insert(:oauth_authorization, app: app)
2959 conn = get(conn, "/web/login", %{code: auth.token})
2961 assert conn.status == 302
2962 assert redirected_to(conn) == "/web/getting-started"
2966 describe "scheduled activities" do
2967 test "creates a scheduled activity", %{conn: conn} do
2968 user = insert(:user)
2969 scheduled_at = NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond)
2973 |> assign(:user, user)
2974 |> post("/api/v1/statuses", %{
2975 "status" => "scheduled",
2976 "scheduled_at" => scheduled_at
2979 assert %{"scheduled_at" => expected_scheduled_at} = json_response(conn, 200)
2980 assert expected_scheduled_at == Pleroma.Web.CommonAPI.Utils.to_masto_date(scheduled_at)
2981 assert [] == Repo.all(Activity)
2984 test "creates a scheduled activity with a media attachment", %{conn: conn} do
2985 user = insert(:user)
2986 scheduled_at = NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond)
2988 file = %Plug.Upload{
2989 content_type: "image/jpg",
2990 path: Path.absname("test/fixtures/image.jpg"),
2991 filename: "an_image.jpg"
2994 {:ok, upload} = ActivityPub.upload(file, actor: user.ap_id)
2998 |> assign(:user, user)
2999 |> post("/api/v1/statuses", %{
3000 "media_ids" => [to_string(upload.id)],
3001 "status" => "scheduled",
3002 "scheduled_at" => scheduled_at
3005 assert %{"media_attachments" => [media_attachment]} = json_response(conn, 200)
3006 assert %{"type" => "image"} = media_attachment
3009 test "skips the scheduling and creates the activity if scheduled_at is earlier than 5 minutes from now",
3011 user = insert(:user)
3014 NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(5) - 1, :millisecond)
3018 |> assign(:user, user)
3019 |> post("/api/v1/statuses", %{
3020 "status" => "not scheduled",
3021 "scheduled_at" => scheduled_at
3024 assert %{"content" => "not scheduled"} = json_response(conn, 200)
3025 assert [] == Repo.all(ScheduledActivity)
3028 test "returns error when daily user limit is exceeded", %{conn: conn} do
3029 user = insert(:user)
3032 NaiveDateTime.utc_now()
3033 |> NaiveDateTime.add(:timer.minutes(6), :millisecond)
3034 |> NaiveDateTime.to_iso8601()
3036 attrs = %{params: %{}, scheduled_at: today}
3037 {:ok, _} = ScheduledActivity.create(user, attrs)
3038 {:ok, _} = ScheduledActivity.create(user, attrs)
3042 |> assign(:user, user)
3043 |> post("/api/v1/statuses", %{"status" => "scheduled", "scheduled_at" => today})
3045 assert %{"error" => "daily limit exceeded"} == json_response(conn, 422)
3048 test "returns error when total user limit is exceeded", %{conn: conn} do
3049 user = insert(:user)
3052 NaiveDateTime.utc_now()
3053 |> NaiveDateTime.add(:timer.minutes(6), :millisecond)
3054 |> NaiveDateTime.to_iso8601()
3057 NaiveDateTime.utc_now()
3058 |> NaiveDateTime.add(:timer.hours(36), :millisecond)
3059 |> NaiveDateTime.to_iso8601()
3061 attrs = %{params: %{}, scheduled_at: today}
3062 {:ok, _} = ScheduledActivity.create(user, attrs)
3063 {:ok, _} = ScheduledActivity.create(user, attrs)
3064 {:ok, _} = ScheduledActivity.create(user, %{params: %{}, scheduled_at: tomorrow})
3068 |> assign(:user, user)
3069 |> post("/api/v1/statuses", %{"status" => "scheduled", "scheduled_at" => tomorrow})
3071 assert %{"error" => "total limit exceeded"} == json_response(conn, 422)
3074 test "shows scheduled activities", %{conn: conn} do
3075 user = insert(:user)
3076 scheduled_activity_id1 = insert(:scheduled_activity, user: user).id |> to_string()
3077 scheduled_activity_id2 = insert(:scheduled_activity, user: user).id |> to_string()
3078 scheduled_activity_id3 = insert(:scheduled_activity, user: user).id |> to_string()
3079 scheduled_activity_id4 = insert(:scheduled_activity, user: user).id |> to_string()
3083 |> assign(:user, user)
3088 |> get("/api/v1/scheduled_statuses?limit=2&min_id=#{scheduled_activity_id1}")
3090 result = json_response(conn_res, 200)
3091 assert [%{"id" => ^scheduled_activity_id3}, %{"id" => ^scheduled_activity_id2}] = result
3096 |> get("/api/v1/scheduled_statuses?limit=2&since_id=#{scheduled_activity_id1}")
3098 result = json_response(conn_res, 200)
3099 assert [%{"id" => ^scheduled_activity_id4}, %{"id" => ^scheduled_activity_id3}] = result
3104 |> get("/api/v1/scheduled_statuses?limit=2&max_id=#{scheduled_activity_id4}")
3106 result = json_response(conn_res, 200)
3107 assert [%{"id" => ^scheduled_activity_id3}, %{"id" => ^scheduled_activity_id2}] = result
3110 test "shows a scheduled activity", %{conn: conn} do
3111 user = insert(:user)
3112 scheduled_activity = insert(:scheduled_activity, user: user)
3116 |> assign(:user, user)
3117 |> get("/api/v1/scheduled_statuses/#{scheduled_activity.id}")
3119 assert %{"id" => scheduled_activity_id} = json_response(res_conn, 200)
3120 assert scheduled_activity_id == scheduled_activity.id |> to_string()
3124 |> assign(:user, user)
3125 |> get("/api/v1/scheduled_statuses/404")
3127 assert %{"error" => "Record not found"} = json_response(res_conn, 404)
3130 test "updates a scheduled activity", %{conn: conn} do
3131 user = insert(:user)
3132 scheduled_activity = insert(:scheduled_activity, user: user)
3135 NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond)
3139 |> assign(:user, user)
3140 |> put("/api/v1/scheduled_statuses/#{scheduled_activity.id}", %{
3141 scheduled_at: new_scheduled_at
3144 assert %{"scheduled_at" => expected_scheduled_at} = json_response(res_conn, 200)
3145 assert expected_scheduled_at == Pleroma.Web.CommonAPI.Utils.to_masto_date(new_scheduled_at)
3149 |> assign(:user, user)
3150 |> put("/api/v1/scheduled_statuses/404", %{scheduled_at: new_scheduled_at})
3152 assert %{"error" => "Record not found"} = json_response(res_conn, 404)
3155 test "deletes a scheduled activity", %{conn: conn} do
3156 user = insert(:user)
3157 scheduled_activity = insert(:scheduled_activity, user: user)
3161 |> assign(:user, user)
3162 |> delete("/api/v1/scheduled_statuses/#{scheduled_activity.id}")
3164 assert %{} = json_response(res_conn, 200)
3165 assert nil == Repo.get(ScheduledActivity, scheduled_activity.id)
3169 |> assign(:user, user)
3170 |> delete("/api/v1/scheduled_statuses/#{scheduled_activity.id}")
3172 assert %{"error" => "Record not found"} = json_response(res_conn, 404)
3176 test "Repeated posts that are replies incorrectly have in_reply_to_id null", %{conn: conn} do
3177 user1 = insert(:user)
3178 user2 = insert(:user)
3179 user3 = insert(:user)
3181 {:ok, replied_to} = TwitterAPI.create_status(user1, %{"status" => "cofe"})
3183 # Reply to status from another user
3186 |> assign(:user, user2)
3187 |> post("/api/v1/statuses", %{"status" => "xD", "in_reply_to_id" => replied_to.id})
3189 assert %{"content" => "xD", "id" => id} = json_response(conn1, 200)
3191 activity = Activity.get_by_id_with_object(id)
3193 assert Object.normalize(activity).data["inReplyTo"] == Object.normalize(replied_to).data["id"]
3194 assert Activity.get_in_reply_to_activity(activity).id == replied_to.id
3196 # Reblog from the third user
3199 |> assign(:user, user3)
3200 |> post("/api/v1/statuses/#{activity.id}/reblog")
3202 assert %{"reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 1}} =
3203 json_response(conn2, 200)
3205 assert to_string(activity.id) == id
3207 # Getting third user status
3210 |> assign(:user, user3)
3211 |> get("api/v1/timelines/home")
3213 [reblogged_activity] = json_response(conn3, 200)
3215 assert reblogged_activity["reblog"]["in_reply_to_id"] == replied_to.id
3217 replied_to_user = User.get_by_ap_id(replied_to.data["actor"])
3218 assert reblogged_activity["reblog"]["in_reply_to_account_id"] == replied_to_user.id
3221 describe "create account by app" do
3223 enabled = Pleroma.Config.get([:app_account_creation, :enabled])
3224 max_requests = Pleroma.Config.get([:app_account_creation, :max_requests])
3225 interval = Pleroma.Config.get([:app_account_creation, :interval])
3227 Pleroma.Config.put([:app_account_creation, :enabled], true)
3228 Pleroma.Config.put([:app_account_creation, :max_requests], 5)
3229 Pleroma.Config.put([:app_account_creation, :interval], 1)
3232 Pleroma.Config.put([:app_account_creation, :enabled], enabled)
3233 Pleroma.Config.put([:app_account_creation, :max_requests], max_requests)
3234 Pleroma.Config.put([:app_account_creation, :interval], interval)
3240 test "Account registration via Application", %{conn: conn} do
3243 |> post("/api/v1/apps", %{
3244 client_name: "client_name",
3245 redirect_uris: "urn:ietf:wg:oauth:2.0:oob",
3246 scopes: "read, write, follow"
3250 "client_id" => client_id,
3251 "client_secret" => client_secret,
3253 "name" => "client_name",
3254 "redirect_uri" => "urn:ietf:wg:oauth:2.0:oob",
3257 } = json_response(conn, 200)
3261 |> post("/oauth/token", %{
3262 grant_type: "client_credentials",
3263 client_id: client_id,
3264 client_secret: client_secret
3267 assert %{"access_token" => token, "refresh_token" => refresh, "scope" => scope} =
3268 json_response(conn, 200)
3271 token_from_db = Repo.get_by(Token, token: token)
3272 assert token_from_db
3274 assert scope == "read write follow"
3278 |> put_req_header("authorization", "Bearer " <> token)
3279 |> post("/api/v1/accounts", %{
3281 email: "lain@example.org",
3282 password: "PlzDontHackLain",
3287 "access_token" => token,
3288 "created_at" => _created_at,
3290 "token_type" => "Bearer"
3291 } = json_response(conn, 200)
3293 token_from_db = Repo.get_by(Token, token: token)
3294 assert token_from_db
3295 token_from_db = Repo.preload(token_from_db, :user)
3296 assert token_from_db.user
3298 assert token_from_db.user.info.confirmation_pending
3301 test "rate limit", %{conn: conn} do
3302 app_token = insert(:oauth_token, user: nil)
3305 put_req_header(conn, "authorization", "Bearer " <> app_token.token)
3306 |> Map.put(:remote_ip, {15, 15, 15, 15})
3311 |> post("/api/v1/accounts", %{
3312 username: "#{i}lain",
3313 email: "#{i}lain@example.org",
3314 password: "PlzDontHackLain",
3319 "access_token" => token,
3320 "created_at" => _created_at,
3322 "token_type" => "Bearer"
3323 } = json_response(conn, 200)
3325 token_from_db = Repo.get_by(Token, token: token)
3326 assert token_from_db
3327 token_from_db = Repo.preload(token_from_db, :user)
3328 assert token_from_db.user
3330 assert token_from_db.user.info.confirmation_pending
3335 |> post("/api/v1/accounts", %{
3337 email: "6lain@example.org",
3338 password: "PlzDontHackLain",
3342 assert json_response(conn, 403) == %{"error" => "Rate limit exceeded."}