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
14 alias Pleroma.Web.ActivityPub.ActivityPub
15 alias Pleroma.Web.CommonAPI
16 alias Pleroma.Web.MastodonAPI.FilterView
17 alias Pleroma.Web.OAuth.App
18 alias Pleroma.Web.OStatus
19 alias Pleroma.Web.Push
20 alias Pleroma.Web.TwitterAPI.TwitterAPI
21 import Pleroma.Factory
22 import ExUnit.CaptureLog
26 mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
30 test "the home timeline", %{conn: conn} do
32 following = insert(:user)
34 {:ok, _activity} = TwitterAPI.create_status(following, %{"status" => "test"})
38 |> assign(:user, user)
39 |> get("/api/v1/timelines/home")
41 assert Enum.empty?(json_response(conn, 200))
43 {:ok, user} = User.follow(user, following)
47 |> assign(:user, user)
48 |> get("/api/v1/timelines/home")
50 assert [%{"content" => "test"}] = json_response(conn, 200)
53 test "the public timeline", %{conn: conn} do
54 following = insert(:user)
57 {:ok, _activity} = TwitterAPI.create_status(following, %{"status" => "test"})
60 OStatus.fetch_activity_from_url("https://shitposter.club/notice/2827873")
64 |> get("/api/v1/timelines/public", %{"local" => "False"})
66 assert length(json_response(conn, 200)) == 2
70 |> get("/api/v1/timelines/public", %{"local" => "True"})
72 assert [%{"content" => "test"}] = json_response(conn, 200)
76 |> get("/api/v1/timelines/public", %{"local" => "1"})
78 assert [%{"content" => "test"}] = json_response(conn, 200)
82 test "posting a status", %{conn: conn} do
85 idempotency_key = "Pikachu rocks!"
89 |> assign(:user, user)
90 |> put_req_header("idempotency-key", idempotency_key)
91 |> post("/api/v1/statuses", %{
93 "spoiler_text" => "2hu",
94 "sensitive" => "false"
97 {:ok, ttl} = Cachex.ttl(:idempotency_cache, idempotency_key)
99 assert ttl > :timer.seconds(6 * 60 * 60 - 1)
101 assert %{"content" => "cofe", "id" => id, "spoiler_text" => "2hu", "sensitive" => false} =
102 json_response(conn_one, 200)
104 assert Repo.get(Activity, id)
108 |> assign(:user, user)
109 |> put_req_header("idempotency-key", idempotency_key)
110 |> post("/api/v1/statuses", %{
112 "spoiler_text" => "2hu",
113 "sensitive" => "false"
116 assert %{"id" => second_id} = json_response(conn_two, 200)
118 assert id == second_id
122 |> assign(:user, user)
123 |> post("/api/v1/statuses", %{
125 "spoiler_text" => "2hu",
126 "sensitive" => "false"
129 assert %{"id" => third_id} = json_response(conn_three, 200)
131 refute id == third_id
134 test "posting a sensitive status", %{conn: conn} do
139 |> assign(:user, user)
140 |> post("/api/v1/statuses", %{"status" => "cofe", "sensitive" => true})
142 assert %{"content" => "cofe", "id" => id, "sensitive" => true} = json_response(conn, 200)
143 assert Repo.get(Activity, id)
146 test "posting a fake status", %{conn: conn} do
151 |> assign(:user, user)
152 |> post("/api/v1/statuses", %{
154 "\"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 json_response(real_conn, 200)
159 |> Map.put("id", nil)
160 |> Map.put("url", nil)
161 |> Map.put("uri", nil)
162 |> Map.put("created_at", nil)
163 |> Kernel.put_in(["pleroma", "conversation_id"], nil)
169 |> assign(:user, user)
170 |> post("/api/v1/statuses", %{
172 "\"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",
177 json_response(fake_conn, 200)
178 |> Map.put("id", nil)
179 |> Map.put("url", nil)
180 |> Map.put("uri", nil)
181 |> Map.put("created_at", nil)
182 |> Kernel.put_in(["pleroma", "conversation_id"], nil)
185 assert real_status == fake_status
188 test "posting a status with OGP link preview", %{conn: conn} do
189 Pleroma.Config.put([:rich_media, :enabled], true)
194 |> assign(:user, user)
195 |> post("/api/v1/statuses", %{
196 "status" => "http://example.com/ogp"
199 assert %{"id" => id, "card" => %{"title" => "The Rock"}} = json_response(conn, 200)
200 assert Repo.get(Activity, id)
201 Pleroma.Config.put([:rich_media, :enabled], false)
204 test "posting a direct status", %{conn: conn} do
205 user1 = insert(:user)
206 user2 = insert(:user)
207 content = "direct cofe @#{user2.nickname}"
211 |> assign(:user, user1)
212 |> post("api/v1/statuses", %{"status" => content, "visibility" => "direct"})
214 assert %{"id" => id, "visibility" => "direct"} = json_response(conn, 200)
215 assert activity = Repo.get(Activity, id)
216 assert activity.recipients == [user2.ap_id, user1.ap_id]
217 assert activity.data["to"] == [user2.ap_id]
218 assert activity.data["cc"] == []
221 test "direct timeline", %{conn: conn} do
222 user_one = insert(:user)
223 user_two = insert(:user)
225 {:ok, user_two} = User.follow(user_two, user_one)
228 CommonAPI.post(user_one, %{
229 "status" => "Hi @#{user_two.nickname}!",
230 "visibility" => "direct"
233 {:ok, _follower_only} =
234 CommonAPI.post(user_one, %{
235 "status" => "Hi @#{user_two.nickname}!",
236 "visibility" => "private"
239 # Only direct should be visible here
242 |> assign(:user, user_two)
243 |> get("api/v1/timelines/direct")
245 [status] = json_response(res_conn, 200)
247 assert %{"visibility" => "direct"} = status
248 assert status["url"] != direct.data["id"]
250 # User should be able to see his own direct message
253 |> assign(:user, user_one)
254 |> get("api/v1/timelines/direct")
256 [status] = json_response(res_conn, 200)
258 assert %{"visibility" => "direct"} = status
260 # Both should be visible here
263 |> assign(:user, user_two)
264 |> get("api/v1/timelines/home")
266 [_s1, _s2] = json_response(res_conn, 200)
269 Enum.each(1..20, fn _ ->
271 CommonAPI.post(user_one, %{
272 "status" => "Hi @#{user_two.nickname}!",
273 "visibility" => "direct"
279 |> assign(:user, user_two)
280 |> get("api/v1/timelines/direct")
282 statuses = json_response(res_conn, 200)
283 assert length(statuses) == 20
287 |> assign(:user, user_two)
288 |> get("api/v1/timelines/direct", %{max_id: List.last(statuses)["id"]})
290 [status] = json_response(res_conn, 200)
292 assert status["url"] != direct.data["id"]
295 test "doesn't include DMs from blocked users", %{conn: conn} do
296 blocker = insert(:user)
297 blocked = insert(:user)
299 {:ok, blocker} = User.block(blocker, blocked)
301 {:ok, _blocked_direct} =
302 CommonAPI.post(blocked, %{
303 "status" => "Hi @#{blocker.nickname}!",
304 "visibility" => "direct"
308 CommonAPI.post(user, %{
309 "status" => "Hi @#{blocker.nickname}!",
310 "visibility" => "direct"
315 |> assign(:user, user)
316 |> get("api/v1/timelines/direct")
318 [status] = json_response(res_conn, 200)
319 assert status["id"] == direct.id
322 test "replying to a status", %{conn: conn} do
325 {:ok, replied_to} = TwitterAPI.create_status(user, %{"status" => "cofe"})
329 |> assign(:user, user)
330 |> post("/api/v1/statuses", %{"status" => "xD", "in_reply_to_id" => replied_to.id})
332 assert %{"content" => "xD", "id" => id} = json_response(conn, 200)
334 activity = Repo.get(Activity, id)
336 assert activity.data["context"] == replied_to.data["context"]
337 assert activity.data["object"]["inReplyToStatusId"] == replied_to.id
340 test "posting a status with an invalid in_reply_to_id", %{conn: conn} do
345 |> assign(:user, user)
346 |> post("/api/v1/statuses", %{"status" => "xD", "in_reply_to_id" => ""})
348 assert %{"content" => "xD", "id" => id} = json_response(conn, 200)
350 activity = Repo.get(Activity, id)
355 test "verify_credentials", %{conn: conn} do
360 |> assign(:user, user)
361 |> get("/api/v1/accounts/verify_credentials")
363 assert %{"id" => id, "source" => %{"privacy" => "public"}} = json_response(conn, 200)
364 assert id == to_string(user.id)
367 test "verify_credentials default scope unlisted", %{conn: conn} do
368 user = insert(:user, %{info: %Pleroma.User.Info{default_scope: "unlisted"}})
372 |> assign(:user, user)
373 |> get("/api/v1/accounts/verify_credentials")
375 assert %{"id" => id, "source" => %{"privacy" => "unlisted"}} = json_response(conn, 200)
376 assert id == to_string(user.id)
379 test "apps/verify_credentials", %{conn: conn} do
380 token = insert(:oauth_token)
384 |> assign(:user, token.user)
385 |> assign(:token, token)
386 |> get("/api/v1/apps/verify_credentials")
388 app = Repo.preload(token, :app).app
391 "name" => app.client_name,
392 "website" => app.website,
393 "vapid_key" => Push.vapid_config() |> Keyword.get(:public_key)
396 assert expected == json_response(conn, 200)
399 test "creates an oauth app", %{conn: conn} do
401 app_attrs = build(:oauth_app)
405 |> assign(:user, user)
406 |> post("/api/v1/apps", %{
407 client_name: app_attrs.client_name,
408 redirect_uris: app_attrs.redirect_uris
411 [app] = Repo.all(App)
414 "name" => app.client_name,
415 "website" => app.website,
416 "client_id" => app.client_id,
417 "client_secret" => app.client_secret,
418 "id" => app.id |> to_string(),
419 "redirect_uri" => app.redirect_uris,
420 "vapid_key" => Push.vapid_config() |> Keyword.get(:public_key)
423 assert expected == json_response(conn, 200)
426 test "get a status", %{conn: conn} do
427 activity = insert(:note_activity)
431 |> get("/api/v1/statuses/#{activity.id}")
433 assert %{"id" => id} = json_response(conn, 200)
434 assert id == to_string(activity.id)
437 describe "deleting a status" do
438 test "when you created it", %{conn: conn} do
439 activity = insert(:note_activity)
440 author = User.get_by_ap_id(activity.data["actor"])
444 |> assign(:user, author)
445 |> delete("/api/v1/statuses/#{activity.id}")
447 assert %{} = json_response(conn, 200)
449 refute Repo.get(Activity, activity.id)
452 test "when you didn't create it", %{conn: conn} do
453 activity = insert(:note_activity)
458 |> assign(:user, user)
459 |> delete("/api/v1/statuses/#{activity.id}")
461 assert %{"error" => _} = json_response(conn, 403)
463 assert Repo.get(Activity, activity.id) == activity
466 test "when you're an admin or moderator", %{conn: conn} do
467 activity1 = insert(:note_activity)
468 activity2 = insert(:note_activity)
469 admin = insert(:user, info: %{is_admin: true})
470 moderator = insert(:user, info: %{is_moderator: true})
474 |> assign(:user, admin)
475 |> delete("/api/v1/statuses/#{activity1.id}")
477 assert %{} = json_response(res_conn, 200)
481 |> assign(:user, moderator)
482 |> delete("/api/v1/statuses/#{activity2.id}")
484 assert %{} = json_response(res_conn, 200)
486 refute Repo.get(Activity, activity1.id)
487 refute Repo.get(Activity, activity2.id)
491 describe "filters" do
492 test "creating a filter", %{conn: conn} do
495 filter = %Pleroma.Filter{
502 |> assign(:user, user)
503 |> post("/api/v1/filters", %{"phrase" => filter.phrase, context: filter.context})
505 assert response = json_response(conn, 200)
506 assert response["phrase"] == filter.phrase
507 assert response["context"] == filter.context
508 assert response["id"] != nil
509 assert response["id"] != ""
512 test "fetching a list of filters", %{conn: conn} do
515 query_one = %Pleroma.Filter{
522 query_two = %Pleroma.Filter{
529 {:ok, filter_one} = Pleroma.Filter.create(query_one)
530 {:ok, filter_two} = Pleroma.Filter.create(query_two)
534 |> assign(:user, user)
535 |> get("/api/v1/filters")
536 |> json_response(200)
542 filters: [filter_two, filter_one]
546 test "get a filter", %{conn: conn} do
549 query = %Pleroma.Filter{
556 {:ok, filter} = Pleroma.Filter.create(query)
560 |> assign(:user, user)
561 |> get("/api/v1/filters/#{filter.filter_id}")
563 assert _response = json_response(conn, 200)
566 test "update a filter", %{conn: conn} do
569 query = %Pleroma.Filter{
576 {:ok, _filter} = Pleroma.Filter.create(query)
578 new = %Pleroma.Filter{
585 |> assign(:user, user)
586 |> put("/api/v1/filters/#{query.filter_id}", %{
591 assert response = json_response(conn, 200)
592 assert response["phrase"] == new.phrase
593 assert response["context"] == new.context
596 test "delete a filter", %{conn: conn} do
599 query = %Pleroma.Filter{
606 {:ok, filter} = Pleroma.Filter.create(query)
610 |> assign(:user, user)
611 |> delete("/api/v1/filters/#{filter.filter_id}")
613 assert response = json_response(conn, 200)
614 assert response == %{}
619 test "creating a list", %{conn: conn} do
624 |> assign(:user, user)
625 |> post("/api/v1/lists", %{"title" => "cuties"})
627 assert %{"title" => title} = json_response(conn, 200)
628 assert title == "cuties"
631 test "adding users to a list", %{conn: conn} do
633 other_user = insert(:user)
634 {:ok, list} = Pleroma.List.create("name", user)
638 |> assign(:user, user)
639 |> post("/api/v1/lists/#{list.id}/accounts", %{"account_ids" => [other_user.id]})
641 assert %{} == json_response(conn, 200)
642 %Pleroma.List{following: following} = Pleroma.List.get(list.id, user)
643 assert following == [other_user.follower_address]
646 test "removing users from a list", %{conn: conn} do
648 other_user = insert(:user)
649 third_user = insert(:user)
650 {:ok, list} = Pleroma.List.create("name", user)
651 {:ok, list} = Pleroma.List.follow(list, other_user)
652 {:ok, list} = Pleroma.List.follow(list, third_user)
656 |> assign(:user, user)
657 |> delete("/api/v1/lists/#{list.id}/accounts", %{"account_ids" => [other_user.id]})
659 assert %{} == json_response(conn, 200)
660 %Pleroma.List{following: following} = Pleroma.List.get(list.id, user)
661 assert following == [third_user.follower_address]
664 test "listing users in a list", %{conn: conn} do
666 other_user = insert(:user)
667 {:ok, list} = Pleroma.List.create("name", user)
668 {:ok, list} = Pleroma.List.follow(list, other_user)
672 |> assign(:user, user)
673 |> get("/api/v1/lists/#{list.id}/accounts", %{"account_ids" => [other_user.id]})
675 assert [%{"id" => id}] = json_response(conn, 200)
676 assert id == to_string(other_user.id)
679 test "retrieving a list", %{conn: conn} do
681 {:ok, list} = Pleroma.List.create("name", user)
685 |> assign(:user, user)
686 |> get("/api/v1/lists/#{list.id}")
688 assert %{"id" => id} = json_response(conn, 200)
689 assert id == to_string(list.id)
692 test "renaming a list", %{conn: conn} do
694 {:ok, list} = Pleroma.List.create("name", user)
698 |> assign(:user, user)
699 |> put("/api/v1/lists/#{list.id}", %{"title" => "newname"})
701 assert %{"title" => name} = json_response(conn, 200)
702 assert name == "newname"
705 test "deleting a list", %{conn: conn} do
707 {:ok, list} = Pleroma.List.create("name", user)
711 |> assign(:user, user)
712 |> delete("/api/v1/lists/#{list.id}")
714 assert %{} = json_response(conn, 200)
715 assert is_nil(Repo.get(Pleroma.List, list.id))
718 test "list timeline", %{conn: conn} do
720 other_user = insert(:user)
721 {:ok, _activity_one} = TwitterAPI.create_status(user, %{"status" => "Marisa is cute."})
722 {:ok, activity_two} = TwitterAPI.create_status(other_user, %{"status" => "Marisa is cute."})
723 {:ok, list} = Pleroma.List.create("name", user)
724 {:ok, list} = Pleroma.List.follow(list, other_user)
728 |> assign(:user, user)
729 |> get("/api/v1/timelines/list/#{list.id}")
731 assert [%{"id" => id}] = json_response(conn, 200)
733 assert id == to_string(activity_two.id)
736 test "list timeline does not leak non-public statuses for unfollowed users", %{conn: conn} do
738 other_user = insert(:user)
739 {:ok, activity_one} = TwitterAPI.create_status(other_user, %{"status" => "Marisa is cute."})
741 {:ok, _activity_two} =
742 TwitterAPI.create_status(other_user, %{
743 "status" => "Marisa is cute.",
744 "visibility" => "private"
747 {:ok, list} = Pleroma.List.create("name", user)
748 {:ok, list} = Pleroma.List.follow(list, other_user)
752 |> assign(:user, user)
753 |> get("/api/v1/timelines/list/#{list.id}")
755 assert [%{"id" => id}] = json_response(conn, 200)
757 assert id == to_string(activity_one.id)
761 describe "notifications" do
762 test "list of notifications", %{conn: conn} do
764 other_user = insert(:user)
767 TwitterAPI.create_status(other_user, %{"status" => "hi @#{user.nickname}"})
769 {:ok, [_notification]} = Notification.create_notifications(activity)
773 |> assign(:user, user)
774 |> get("/api/v1/notifications")
777 "hi <span class=\"h-card\"><a data-user=\"#{user.id}\" class=\"u-url mention\" href=\"#{
779 }\">@<span>#{user.nickname}</span></a></span>"
781 assert [%{"status" => %{"content" => response}} | _rest] = json_response(conn, 200)
782 assert response == expected_response
785 test "getting a single notification", %{conn: conn} do
787 other_user = insert(:user)
790 TwitterAPI.create_status(other_user, %{"status" => "hi @#{user.nickname}"})
792 {:ok, [notification]} = Notification.create_notifications(activity)
796 |> assign(:user, user)
797 |> get("/api/v1/notifications/#{notification.id}")
800 "hi <span class=\"h-card\"><a data-user=\"#{user.id}\" class=\"u-url mention\" href=\"#{
802 }\">@<span>#{user.nickname}</span></a></span>"
804 assert %{"status" => %{"content" => response}} = json_response(conn, 200)
805 assert response == expected_response
808 test "dismissing a single notification", %{conn: conn} do
810 other_user = insert(:user)
813 TwitterAPI.create_status(other_user, %{"status" => "hi @#{user.nickname}"})
815 {:ok, [notification]} = Notification.create_notifications(activity)
819 |> assign(:user, user)
820 |> post("/api/v1/notifications/dismiss", %{"id" => notification.id})
822 assert %{} = json_response(conn, 200)
825 test "clearing all notifications", %{conn: conn} do
827 other_user = insert(:user)
830 TwitterAPI.create_status(other_user, %{"status" => "hi @#{user.nickname}"})
832 {:ok, [_notification]} = Notification.create_notifications(activity)
836 |> assign(:user, user)
837 |> post("/api/v1/notifications/clear")
839 assert %{} = json_response(conn, 200)
843 |> assign(:user, user)
844 |> get("/api/v1/notifications")
846 assert all = json_response(conn, 200)
850 test "paginates notifications using min_id, since_id, max_id, and limit", %{conn: conn} do
852 other_user = insert(:user)
854 {:ok, activity1} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
855 {:ok, activity2} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
856 {:ok, activity3} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
857 {:ok, activity4} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
859 notification1_id = Repo.get_by(Notification, activity_id: activity1.id).id |> to_string()
860 notification2_id = Repo.get_by(Notification, activity_id: activity2.id).id |> to_string()
861 notification3_id = Repo.get_by(Notification, activity_id: activity3.id).id |> to_string()
862 notification4_id = Repo.get_by(Notification, activity_id: activity4.id).id |> to_string()
866 |> assign(:user, user)
871 |> get("/api/v1/notifications?limit=2&min_id=#{notification1_id}")
873 result = json_response(conn_res, 200)
874 assert [%{"id" => ^notification3_id}, %{"id" => ^notification2_id}] = result
879 |> get("/api/v1/notifications?limit=2&since_id=#{notification1_id}")
881 result = json_response(conn_res, 200)
882 assert [%{"id" => ^notification4_id}, %{"id" => ^notification3_id}] = result
887 |> get("/api/v1/notifications?limit=2&max_id=#{notification4_id}")
889 result = json_response(conn_res, 200)
890 assert [%{"id" => ^notification3_id}, %{"id" => ^notification2_id}] = result
893 test "filters notifications using exclude_types", %{conn: conn} do
895 other_user = insert(:user)
897 {:ok, mention_activity} = CommonAPI.post(other_user, %{"status" => "hey @#{user.nickname}"})
898 {:ok, create_activity} = CommonAPI.post(user, %{"status" => "hey"})
899 {:ok, favorite_activity, _} = CommonAPI.favorite(create_activity.id, other_user)
900 {:ok, reblog_activity, _} = CommonAPI.repeat(create_activity.id, other_user)
901 {:ok, _, _, follow_activity} = CommonAPI.follow(other_user, user)
903 mention_notification_id =
904 Repo.get_by(Notification, activity_id: mention_activity.id).id |> to_string()
906 favorite_notification_id =
907 Repo.get_by(Notification, activity_id: favorite_activity.id).id |> to_string()
909 reblog_notification_id =
910 Repo.get_by(Notification, activity_id: reblog_activity.id).id |> to_string()
912 follow_notification_id =
913 Repo.get_by(Notification, activity_id: follow_activity.id).id |> to_string()
917 |> assign(:user, user)
920 get(conn, "/api/v1/notifications", %{exclude_types: ["mention", "favourite", "reblog"]})
922 assert [%{"id" => ^follow_notification_id}] = json_response(conn_res, 200)
925 get(conn, "/api/v1/notifications", %{exclude_types: ["favourite", "reblog", "follow"]})
927 assert [%{"id" => ^mention_notification_id}] = json_response(conn_res, 200)
930 get(conn, "/api/v1/notifications", %{exclude_types: ["reblog", "follow", "mention"]})
932 assert [%{"id" => ^favorite_notification_id}] = json_response(conn_res, 200)
935 get(conn, "/api/v1/notifications", %{exclude_types: ["follow", "mention", "favourite"]})
937 assert [%{"id" => ^reblog_notification_id}] = json_response(conn_res, 200)
941 describe "reblogging" do
942 test "reblogs and returns the reblogged status", %{conn: conn} do
943 activity = insert(:note_activity)
948 |> assign(:user, user)
949 |> post("/api/v1/statuses/#{activity.id}/reblog")
951 assert %{"reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 1}} =
952 json_response(conn, 200)
954 assert to_string(activity.id) == id
958 describe "unreblogging" do
959 test "unreblogs and returns the unreblogged status", %{conn: conn} do
960 activity = insert(:note_activity)
963 {:ok, _, _} = CommonAPI.repeat(activity.id, user)
967 |> assign(:user, user)
968 |> post("/api/v1/statuses/#{activity.id}/unreblog")
970 assert %{"id" => id, "reblogged" => false, "reblogs_count" => 0} = json_response(conn, 200)
972 assert to_string(activity.id) == id
976 describe "favoriting" do
977 test "favs a status and returns it", %{conn: conn} do
978 activity = insert(:note_activity)
983 |> assign(:user, user)
984 |> post("/api/v1/statuses/#{activity.id}/favourite")
986 assert %{"id" => id, "favourites_count" => 1, "favourited" => true} =
987 json_response(conn, 200)
989 assert to_string(activity.id) == id
992 test "returns 500 for a wrong id", %{conn: conn} do
997 |> assign(:user, user)
998 |> post("/api/v1/statuses/1/favourite")
999 |> json_response(500)
1001 assert resp == "Something went wrong"
1005 describe "unfavoriting" do
1006 test "unfavorites a status and returns it", %{conn: conn} do
1007 activity = insert(:note_activity)
1008 user = insert(:user)
1010 {:ok, _, _} = CommonAPI.favorite(activity.id, user)
1014 |> assign(:user, user)
1015 |> post("/api/v1/statuses/#{activity.id}/unfavourite")
1017 assert %{"id" => id, "favourites_count" => 0, "favourited" => false} =
1018 json_response(conn, 200)
1020 assert to_string(activity.id) == id
1024 describe "user timelines" do
1025 test "gets a users statuses", %{conn: conn} do
1026 user_one = insert(:user)
1027 user_two = insert(:user)
1028 user_three = insert(:user)
1030 {:ok, user_three} = User.follow(user_three, user_one)
1032 {:ok, activity} = CommonAPI.post(user_one, %{"status" => "HI!!!"})
1034 {:ok, direct_activity} =
1035 CommonAPI.post(user_one, %{
1036 "status" => "Hi, @#{user_two.nickname}.",
1037 "visibility" => "direct"
1040 {:ok, private_activity} =
1041 CommonAPI.post(user_one, %{"status" => "private", "visibility" => "private"})
1045 |> get("/api/v1/accounts/#{user_one.id}/statuses")
1047 assert [%{"id" => id}] = json_response(resp, 200)
1048 assert id == to_string(activity.id)
1052 |> assign(:user, user_two)
1053 |> get("/api/v1/accounts/#{user_one.id}/statuses")
1055 assert [%{"id" => id_one}, %{"id" => id_two}] = json_response(resp, 200)
1056 assert id_one == to_string(direct_activity.id)
1057 assert id_two == to_string(activity.id)
1061 |> assign(:user, user_three)
1062 |> get("/api/v1/accounts/#{user_one.id}/statuses")
1064 assert [%{"id" => id_one}, %{"id" => id_two}] = json_response(resp, 200)
1065 assert id_one == to_string(private_activity.id)
1066 assert id_two == to_string(activity.id)
1069 test "unimplemented pinned statuses feature", %{conn: conn} do
1070 note = insert(:note_activity)
1071 user = User.get_by_ap_id(note.data["actor"])
1075 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
1077 assert json_response(conn, 200) == []
1080 test "gets an users media", %{conn: conn} do
1081 note = insert(:note_activity)
1082 user = User.get_by_ap_id(note.data["actor"])
1084 file = %Plug.Upload{
1085 content_type: "image/jpg",
1086 path: Path.absname("test/fixtures/image.jpg"),
1087 filename: "an_image.jpg"
1091 TwitterAPI.upload(file, user, "json")
1095 TwitterAPI.create_status(user, %{"status" => "cofe", "media_ids" => [media["media_id"]]})
1099 |> get("/api/v1/accounts/#{user.id}/statuses", %{"only_media" => "true"})
1101 assert [%{"id" => id}] = json_response(conn, 200)
1102 assert id == to_string(image_post.id)
1106 |> get("/api/v1/accounts/#{user.id}/statuses", %{"only_media" => "1"})
1108 assert [%{"id" => id}] = json_response(conn, 200)
1109 assert id == to_string(image_post.id)
1112 test "gets a user's statuses without reblogs", %{conn: conn} do
1113 user = insert(:user)
1114 {:ok, post} = CommonAPI.post(user, %{"status" => "HI!!!"})
1115 {:ok, _, _} = CommonAPI.repeat(post.id, user)
1119 |> get("/api/v1/accounts/#{user.id}/statuses", %{"exclude_reblogs" => "true"})
1121 assert [%{"id" => id}] = json_response(conn, 200)
1122 assert id == to_string(post.id)
1126 |> get("/api/v1/accounts/#{user.id}/statuses", %{"exclude_reblogs" => "1"})
1128 assert [%{"id" => id}] = json_response(conn, 200)
1129 assert id == to_string(post.id)
1133 describe "user relationships" do
1134 test "returns the relationships for the current user", %{conn: conn} do
1135 user = insert(:user)
1136 other_user = insert(:user)
1137 {:ok, user} = User.follow(user, other_user)
1141 |> assign(:user, user)
1142 |> get("/api/v1/accounts/relationships", %{"id" => [other_user.id]})
1144 assert [relationship] = json_response(conn, 200)
1146 assert to_string(other_user.id) == relationship["id"]
1150 describe "locked accounts" do
1151 test "/api/v1/follow_requests works" do
1152 user = insert(:user, %{info: %Pleroma.User.Info{locked: true}})
1153 other_user = insert(:user)
1155 {:ok, _activity} = ActivityPub.follow(other_user, user)
1157 user = Repo.get(User, user.id)
1158 other_user = Repo.get(User, other_user.id)
1160 assert User.following?(other_user, user) == false
1164 |> assign(:user, user)
1165 |> get("/api/v1/follow_requests")
1167 assert [relationship] = json_response(conn, 200)
1168 assert to_string(other_user.id) == relationship["id"]
1171 test "/api/v1/follow_requests/:id/authorize works" do
1172 user = insert(:user, %{info: %User.Info{locked: true}})
1173 other_user = insert(:user)
1175 {:ok, _activity} = ActivityPub.follow(other_user, user)
1177 user = Repo.get(User, user.id)
1178 other_user = Repo.get(User, other_user.id)
1180 assert User.following?(other_user, user) == false
1184 |> assign(:user, user)
1185 |> post("/api/v1/follow_requests/#{other_user.id}/authorize")
1187 assert relationship = json_response(conn, 200)
1188 assert to_string(other_user.id) == relationship["id"]
1190 user = Repo.get(User, user.id)
1191 other_user = Repo.get(User, other_user.id)
1193 assert User.following?(other_user, user) == true
1196 test "verify_credentials", %{conn: conn} do
1197 user = insert(:user, %{info: %Pleroma.User.Info{default_scope: "private"}})
1201 |> assign(:user, user)
1202 |> get("/api/v1/accounts/verify_credentials")
1204 assert %{"id" => id, "source" => %{"privacy" => "private"}} = json_response(conn, 200)
1205 assert id == to_string(user.id)
1208 test "/api/v1/follow_requests/:id/reject works" do
1209 user = insert(:user, %{info: %Pleroma.User.Info{locked: true}})
1210 other_user = insert(:user)
1212 {:ok, _activity} = ActivityPub.follow(other_user, user)
1214 user = Repo.get(User, user.id)
1218 |> assign(:user, user)
1219 |> post("/api/v1/follow_requests/#{other_user.id}/reject")
1221 assert relationship = json_response(conn, 200)
1222 assert to_string(other_user.id) == relationship["id"]
1224 user = Repo.get(User, user.id)
1225 other_user = Repo.get(User, other_user.id)
1227 assert User.following?(other_user, user) == false
1231 test "account fetching", %{conn: conn} do
1232 user = insert(:user)
1236 |> get("/api/v1/accounts/#{user.id}")
1238 assert %{"id" => id} = json_response(conn, 200)
1239 assert id == to_string(user.id)
1243 |> get("/api/v1/accounts/-1")
1245 assert %{"error" => "Can't find user"} = json_response(conn, 404)
1248 test "account fetching also works nickname", %{conn: conn} do
1249 user = insert(:user)
1253 |> get("/api/v1/accounts/#{user.nickname}")
1255 assert %{"id" => id} = json_response(conn, 200)
1256 assert id == user.id
1259 test "media upload", %{conn: conn} do
1260 file = %Plug.Upload{
1261 content_type: "image/jpg",
1262 path: Path.absname("test/fixtures/image.jpg"),
1263 filename: "an_image.jpg"
1266 desc = "Description of the image"
1268 user = insert(:user)
1272 |> assign(:user, user)
1273 |> post("/api/v1/media", %{"file" => file, "description" => desc})
1275 assert media = json_response(conn, 200)
1277 assert media["type"] == "image"
1278 assert media["description"] == desc
1281 object = Repo.get(Object, media["id"])
1282 assert object.data["actor"] == User.ap_id(user)
1285 test "hashtag timeline", %{conn: conn} do
1286 following = insert(:user)
1289 {:ok, activity} = TwitterAPI.create_status(following, %{"status" => "test #2hu"})
1291 {:ok, [_activity]} =
1292 OStatus.fetch_activity_from_url("https://shitposter.club/notice/2827873")
1296 |> get("/api/v1/timelines/tag/2hu")
1298 assert [%{"id" => id}] = json_response(nconn, 200)
1300 assert id == to_string(activity.id)
1302 # works for different capitalization too
1305 |> get("/api/v1/timelines/tag/2HU")
1307 assert [%{"id" => id}] = json_response(nconn, 200)
1309 assert id == to_string(activity.id)
1313 test "multi-hashtag timeline", %{conn: conn} do
1314 user = insert(:user)
1316 {:ok, activity_test} = CommonAPI.post(user, %{"status" => "#test"})
1317 {:ok, activity_test1} = CommonAPI.post(user, %{"status" => "#test #test1"})
1318 {:ok, activity_none} = CommonAPI.post(user, %{"status" => "#test #none"})
1322 |> get("/api/v1/timelines/tag/test", %{"any" => ["test1"]})
1324 [status_none, status_test1, status_test] = json_response(any_test, 200)
1326 assert to_string(activity_test.id) == status_test["id"]
1327 assert to_string(activity_test1.id) == status_test1["id"]
1328 assert to_string(activity_none.id) == status_none["id"]
1332 |> get("/api/v1/timelines/tag/test", %{"all" => ["test1"], "none" => ["none"]})
1334 assert [status_test1] == json_response(restricted_test, 200)
1336 all_test = conn |> get("/api/v1/timelines/tag/test", %{"all" => ["none"]})
1338 assert [status_none] == json_response(all_test, 200)
1341 test "getting followers", %{conn: conn} do
1342 user = insert(:user)
1343 other_user = insert(:user)
1344 {:ok, user} = User.follow(user, other_user)
1348 |> get("/api/v1/accounts/#{other_user.id}/followers")
1350 assert [%{"id" => id}] = json_response(conn, 200)
1351 assert id == to_string(user.id)
1354 test "getting followers, hide_followers", %{conn: conn} do
1355 user = insert(:user)
1356 other_user = insert(:user, %{info: %{hide_followers: true}})
1357 {:ok, _user} = User.follow(user, other_user)
1361 |> get("/api/v1/accounts/#{other_user.id}/followers")
1363 assert [] == json_response(conn, 200)
1366 test "getting followers, hide_followers, same user requesting", %{conn: conn} do
1367 user = insert(:user)
1368 other_user = insert(:user, %{info: %{hide_followers: true}})
1369 {:ok, _user} = User.follow(user, other_user)
1373 |> assign(:user, other_user)
1374 |> get("/api/v1/accounts/#{other_user.id}/followers")
1376 refute [] == json_response(conn, 200)
1379 test "getting followers, pagination", %{conn: conn} do
1380 user = insert(:user)
1381 follower1 = insert(:user)
1382 follower2 = insert(:user)
1383 follower3 = insert(:user)
1384 {:ok, _} = User.follow(follower1, user)
1385 {:ok, _} = User.follow(follower2, user)
1386 {:ok, _} = User.follow(follower3, user)
1390 |> assign(:user, user)
1394 |> get("/api/v1/accounts/#{user.id}/followers?since_id=#{follower1.id}")
1396 assert [%{"id" => id3}, %{"id" => id2}] = json_response(res_conn, 200)
1397 assert id3 == follower3.id
1398 assert id2 == follower2.id
1402 |> get("/api/v1/accounts/#{user.id}/followers?max_id=#{follower3.id}")
1404 assert [%{"id" => id2}, %{"id" => id1}] = json_response(res_conn, 200)
1405 assert id2 == follower2.id
1406 assert id1 == follower1.id
1410 |> get("/api/v1/accounts/#{user.id}/followers?limit=1&max_id=#{follower3.id}")
1412 assert [%{"id" => id2}] = json_response(res_conn, 200)
1413 assert id2 == follower2.id
1415 assert [link_header] = get_resp_header(res_conn, "link")
1416 assert link_header =~ ~r/since_id=#{follower2.id}/
1417 assert link_header =~ ~r/max_id=#{follower2.id}/
1420 test "getting following", %{conn: conn} do
1421 user = insert(:user)
1422 other_user = insert(:user)
1423 {:ok, user} = User.follow(user, other_user)
1427 |> get("/api/v1/accounts/#{user.id}/following")
1429 assert [%{"id" => id}] = json_response(conn, 200)
1430 assert id == to_string(other_user.id)
1433 test "getting following, hide_follows", %{conn: conn} do
1434 user = insert(:user, %{info: %{hide_follows: true}})
1435 other_user = insert(:user)
1436 {:ok, user} = User.follow(user, other_user)
1440 |> get("/api/v1/accounts/#{user.id}/following")
1442 assert [] == json_response(conn, 200)
1445 test "getting following, hide_follows, same user requesting", %{conn: conn} do
1446 user = insert(:user, %{info: %{hide_follows: true}})
1447 other_user = insert(:user)
1448 {:ok, user} = User.follow(user, other_user)
1452 |> assign(:user, user)
1453 |> get("/api/v1/accounts/#{user.id}/following")
1455 refute [] == json_response(conn, 200)
1458 test "getting following, pagination", %{conn: conn} do
1459 user = insert(:user)
1460 following1 = insert(:user)
1461 following2 = insert(:user)
1462 following3 = insert(:user)
1463 {:ok, _} = User.follow(user, following1)
1464 {:ok, _} = User.follow(user, following2)
1465 {:ok, _} = User.follow(user, following3)
1469 |> assign(:user, user)
1473 |> get("/api/v1/accounts/#{user.id}/following?since_id=#{following1.id}")
1475 assert [%{"id" => id3}, %{"id" => id2}] = json_response(res_conn, 200)
1476 assert id3 == following3.id
1477 assert id2 == following2.id
1481 |> get("/api/v1/accounts/#{user.id}/following?max_id=#{following3.id}")
1483 assert [%{"id" => id2}, %{"id" => id1}] = json_response(res_conn, 200)
1484 assert id2 == following2.id
1485 assert id1 == following1.id
1489 |> get("/api/v1/accounts/#{user.id}/following?limit=1&max_id=#{following3.id}")
1491 assert [%{"id" => id2}] = json_response(res_conn, 200)
1492 assert id2 == following2.id
1494 assert [link_header] = get_resp_header(res_conn, "link")
1495 assert link_header =~ ~r/since_id=#{following2.id}/
1496 assert link_header =~ ~r/max_id=#{following2.id}/
1499 test "following / unfollowing a user", %{conn: conn} do
1500 user = insert(:user)
1501 other_user = insert(:user)
1505 |> assign(:user, user)
1506 |> post("/api/v1/accounts/#{other_user.id}/follow")
1508 assert %{"id" => _id, "following" => true} = json_response(conn, 200)
1510 user = Repo.get(User, user.id)
1514 |> assign(:user, user)
1515 |> post("/api/v1/accounts/#{other_user.id}/unfollow")
1517 assert %{"id" => _id, "following" => false} = json_response(conn, 200)
1519 user = Repo.get(User, user.id)
1523 |> assign(:user, user)
1524 |> post("/api/v1/follows", %{"uri" => other_user.nickname})
1526 assert %{"id" => id} = json_response(conn, 200)
1527 assert id == to_string(other_user.id)
1530 test "muting / unmuting a user", %{conn: conn} do
1531 user = insert(:user)
1532 other_user = insert(:user)
1536 |> assign(:user, user)
1537 |> post("/api/v1/accounts/#{other_user.id}/mute")
1539 assert %{"id" => _id, "muting" => true} = json_response(conn, 200)
1541 user = Repo.get(User, user.id)
1545 |> assign(:user, user)
1546 |> post("/api/v1/accounts/#{other_user.id}/unmute")
1548 assert %{"id" => _id, "muting" => false} = json_response(conn, 200)
1551 test "getting a list of mutes", %{conn: conn} do
1552 user = insert(:user)
1553 other_user = insert(:user)
1555 {:ok, user} = User.mute(user, other_user)
1559 |> assign(:user, user)
1560 |> get("/api/v1/mutes")
1562 other_user_id = to_string(other_user.id)
1563 assert [%{"id" => ^other_user_id}] = json_response(conn, 200)
1566 test "blocking / unblocking a user", %{conn: conn} do
1567 user = insert(:user)
1568 other_user = insert(:user)
1572 |> assign(:user, user)
1573 |> post("/api/v1/accounts/#{other_user.id}/block")
1575 assert %{"id" => _id, "blocking" => true} = json_response(conn, 200)
1577 user = Repo.get(User, user.id)
1581 |> assign(:user, user)
1582 |> post("/api/v1/accounts/#{other_user.id}/unblock")
1584 assert %{"id" => _id, "blocking" => false} = json_response(conn, 200)
1587 test "getting a list of blocks", %{conn: conn} do
1588 user = insert(:user)
1589 other_user = insert(:user)
1591 {:ok, user} = User.block(user, other_user)
1595 |> assign(:user, user)
1596 |> get("/api/v1/blocks")
1598 other_user_id = to_string(other_user.id)
1599 assert [%{"id" => ^other_user_id}] = json_response(conn, 200)
1602 test "blocking / unblocking a domain", %{conn: conn} do
1603 user = insert(:user)
1604 other_user = insert(:user, %{ap_id: "https://dogwhistle.zone/@pundit"})
1608 |> assign(:user, user)
1609 |> post("/api/v1/domain_blocks", %{"domain" => "dogwhistle.zone"})
1611 assert %{} = json_response(conn, 200)
1612 user = User.get_cached_by_ap_id(user.ap_id)
1613 assert User.blocks?(user, other_user)
1617 |> assign(:user, user)
1618 |> delete("/api/v1/domain_blocks", %{"domain" => "dogwhistle.zone"})
1620 assert %{} = json_response(conn, 200)
1621 user = User.get_cached_by_ap_id(user.ap_id)
1622 refute User.blocks?(user, other_user)
1625 test "getting a list of domain blocks", %{conn: conn} do
1626 user = insert(:user)
1628 {:ok, user} = User.block_domain(user, "bad.site")
1629 {:ok, user} = User.block_domain(user, "even.worse.site")
1633 |> assign(:user, user)
1634 |> get("/api/v1/domain_blocks")
1636 domain_blocks = json_response(conn, 200)
1638 assert "bad.site" in domain_blocks
1639 assert "even.worse.site" in domain_blocks
1642 test "unimplemented follow_requests, blocks, domain blocks" do
1643 user = insert(:user)
1645 ["blocks", "domain_blocks", "follow_requests"]
1646 |> Enum.each(fn endpoint ->
1649 |> assign(:user, user)
1650 |> get("/api/v1/#{endpoint}")
1652 assert [] = json_response(conn, 200)
1656 test "account search", %{conn: conn} do
1657 user = insert(:user)
1658 user_two = insert(:user, %{nickname: "shp@shitposter.club"})
1659 user_three = insert(:user, %{nickname: "shp@heldscal.la", name: "I love 2hu"})
1663 |> assign(:user, user)
1664 |> get("/api/v1/accounts/search", %{"q" => "shp"})
1665 |> json_response(200)
1667 result_ids = for result <- results, do: result["acct"]
1669 assert user_two.nickname in result_ids
1670 assert user_three.nickname in result_ids
1674 |> assign(:user, user)
1675 |> get("/api/v1/accounts/search", %{"q" => "2hu"})
1676 |> json_response(200)
1678 result_ids = for result <- results, do: result["acct"]
1680 assert user_three.nickname in result_ids
1683 test "search", %{conn: conn} do
1684 user = insert(:user)
1685 user_two = insert(:user, %{nickname: "shp@shitposter.club"})
1686 user_three = insert(:user, %{nickname: "shp@heldscal.la", name: "I love 2hu"})
1688 {:ok, activity} = CommonAPI.post(user, %{"status" => "This is about 2hu"})
1691 CommonAPI.post(user, %{
1692 "status" => "This is about 2hu, but private",
1693 "visibility" => "private"
1696 {:ok, _} = CommonAPI.post(user_two, %{"status" => "This isn't"})
1700 |> get("/api/v1/search", %{"q" => "2hu"})
1702 assert results = json_response(conn, 200)
1704 [account | _] = results["accounts"]
1705 assert account["id"] == to_string(user_three.id)
1707 assert results["hashtags"] == []
1709 [status] = results["statuses"]
1710 assert status["id"] == to_string(activity.id)
1713 test "search fetches remote statuses", %{conn: conn} do
1717 |> get("/api/v1/search", %{"q" => "https://shitposter.club/notice/2827873"})
1719 assert results = json_response(conn, 200)
1721 [status] = results["statuses"]
1722 assert status["uri"] == "tag:shitposter.club,2017-05-05:noticeId=2827873:objectType=comment"
1726 test "search doesn't show statuses that it shouldn't", %{conn: conn} do
1728 CommonAPI.post(insert(:user), %{
1729 "status" => "This is about 2hu, but private",
1730 "visibility" => "private"
1736 |> get("/api/v1/search", %{"q" => activity.data["object"]["id"]})
1738 assert results = json_response(conn, 200)
1740 [] = results["statuses"]
1744 test "search fetches remote accounts", %{conn: conn} do
1747 |> get("/api/v1/search", %{"q" => "shp@social.heldscal.la", "resolve" => "true"})
1749 assert results = json_response(conn, 200)
1750 [account] = results["accounts"]
1751 assert account["acct"] == "shp@social.heldscal.la"
1754 test "returns the favorites of a user", %{conn: conn} do
1755 user = insert(:user)
1756 other_user = insert(:user)
1758 {:ok, _} = CommonAPI.post(other_user, %{"status" => "bla"})
1759 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "traps are happy"})
1761 {:ok, _, _} = CommonAPI.favorite(activity.id, user)
1765 |> assign(:user, user)
1766 |> get("/api/v1/favourites")
1768 assert [status] = json_response(first_conn, 200)
1769 assert status["id"] == to_string(activity.id)
1771 assert [{"link", _link_header}] =
1772 Enum.filter(first_conn.resp_headers, fn element -> match?({"link", _}, element) end)
1774 # Honours query params
1775 {:ok, second_activity} =
1776 CommonAPI.post(other_user, %{
1778 "Trees Are Never Sad Look At Them Every Once In Awhile They're Quite Beautiful."
1781 {:ok, _, _} = CommonAPI.favorite(second_activity.id, user)
1783 last_like = status["id"]
1787 |> assign(:user, user)
1788 |> get("/api/v1/favourites?since_id=#{last_like}")
1790 assert [second_status] = json_response(second_conn, 200)
1791 assert second_status["id"] == to_string(second_activity.id)
1795 |> assign(:user, user)
1796 |> get("/api/v1/favourites?limit=0")
1798 assert [] = json_response(third_conn, 200)
1801 describe "updating credentials" do
1802 test "updates the user's bio", %{conn: conn} do
1803 user = insert(:user)
1804 user2 = insert(:user)
1808 |> assign(:user, user)
1809 |> patch("/api/v1/accounts/update_credentials", %{
1810 "note" => "I drink #cofe with @#{user2.nickname}"
1813 assert user = json_response(conn, 200)
1815 assert user["note"] ==
1816 ~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=") <>
1818 ~s(" class="u-url mention" href=") <>
1819 user2.ap_id <> ~s(">@<span>) <> user2.nickname <> ~s(</span></a></span>)
1822 test "updates the user's locking status", %{conn: conn} do
1823 user = insert(:user)
1827 |> assign(:user, user)
1828 |> patch("/api/v1/accounts/update_credentials", %{locked: "true"})
1830 assert user = json_response(conn, 200)
1831 assert user["locked"] == true
1834 test "updates the user's name", %{conn: conn} do
1835 user = insert(:user)
1839 |> assign(:user, user)
1840 |> patch("/api/v1/accounts/update_credentials", %{"display_name" => "markorepairs"})
1842 assert user = json_response(conn, 200)
1843 assert user["display_name"] == "markorepairs"
1846 test "updates the user's avatar", %{conn: conn} do
1847 user = insert(:user)
1849 new_avatar = %Plug.Upload{
1850 content_type: "image/jpg",
1851 path: Path.absname("test/fixtures/image.jpg"),
1852 filename: "an_image.jpg"
1857 |> assign(:user, user)
1858 |> patch("/api/v1/accounts/update_credentials", %{"avatar" => new_avatar})
1860 assert user_response = json_response(conn, 200)
1861 assert user_response["avatar"] != User.avatar_url(user)
1864 test "updates the user's banner", %{conn: conn} do
1865 user = insert(:user)
1867 new_header = %Plug.Upload{
1868 content_type: "image/jpg",
1869 path: Path.absname("test/fixtures/image.jpg"),
1870 filename: "an_image.jpg"
1875 |> assign(:user, user)
1876 |> patch("/api/v1/accounts/update_credentials", %{"header" => new_header})
1878 assert user_response = json_response(conn, 200)
1879 assert user_response["header"] != User.banner_url(user)
1882 test "requires 'write' permission", %{conn: conn} do
1883 token1 = insert(:oauth_token, scopes: ["read"])
1884 token2 = insert(:oauth_token, scopes: ["write", "follow"])
1886 for token <- [token1, token2] do
1889 |> put_req_header("authorization", "Bearer #{token.token}")
1890 |> patch("/api/v1/accounts/update_credentials", %{})
1892 if token == token1 do
1893 assert %{"error" => "Insufficient permissions: write."} == json_response(conn, 403)
1895 assert json_response(conn, 200)
1901 test "get instance information", %{conn: conn} do
1902 conn = get(conn, "/api/v1/instance")
1903 assert result = json_response(conn, 200)
1905 # Note: not checking for "max_toot_chars" since it's optional
1913 "streaming_api" => _
1918 "registrations" => _
1922 test "get instance stats", %{conn: conn} do
1923 user = insert(:user, %{local: true})
1925 user2 = insert(:user, %{local: true})
1926 {:ok, _user2} = User.deactivate(user2, !user2.info.deactivated)
1928 insert(:user, %{local: false, nickname: "u@peer1.com"})
1929 insert(:user, %{local: false, nickname: "u@peer2.com"})
1931 {:ok, _} = TwitterAPI.create_status(user, %{"status" => "cofe"})
1933 # Stats should count users with missing or nil `info.deactivated` value
1934 user = Repo.get(User, user.id)
1935 info_change = Changeset.change(user.info, %{deactivated: nil})
1939 |> Changeset.change()
1940 |> Changeset.put_embed(:info, info_change)
1941 |> User.update_and_set_cache()
1943 Pleroma.Stats.update_stats()
1945 conn = get(conn, "/api/v1/instance")
1947 assert result = json_response(conn, 200)
1949 stats = result["stats"]
1952 assert stats["user_count"] == 1
1953 assert stats["status_count"] == 1
1954 assert stats["domain_count"] == 2
1957 test "get peers", %{conn: conn} do
1958 insert(:user, %{local: false, nickname: "u@peer1.com"})
1959 insert(:user, %{local: false, nickname: "u@peer2.com"})
1961 Pleroma.Stats.update_stats()
1963 conn = get(conn, "/api/v1/instance/peers")
1965 assert result = json_response(conn, 200)
1967 assert ["peer1.com", "peer2.com"] == Enum.sort(result)
1970 test "put settings", %{conn: conn} do
1971 user = insert(:user)
1975 |> assign(:user, user)
1976 |> put("/api/web/settings", %{"data" => %{"programming" => "socks"}})
1978 assert _result = json_response(conn, 200)
1980 user = User.get_cached_by_ap_id(user.ap_id)
1981 assert user.info.settings == %{"programming" => "socks"}
1984 describe "pinned statuses" do
1986 Pleroma.Config.put([:instance, :max_pinned_statuses], 1)
1988 user = insert(:user)
1989 {:ok, activity} = CommonAPI.post(user, %{"status" => "HI!!!"})
1991 [user: user, activity: activity]
1994 test "returns pinned statuses", %{conn: conn, user: user, activity: activity} do
1995 {:ok, _} = CommonAPI.pin(activity.id, user)
1999 |> assign(:user, user)
2000 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
2001 |> json_response(200)
2003 id_str = to_string(activity.id)
2005 assert [%{"id" => ^id_str, "pinned" => true}] = result
2008 test "pin status", %{conn: conn, user: user, activity: activity} do
2009 id_str = to_string(activity.id)
2011 assert %{"id" => ^id_str, "pinned" => true} =
2013 |> assign(:user, user)
2014 |> post("/api/v1/statuses/#{activity.id}/pin")
2015 |> json_response(200)
2017 assert [%{"id" => ^id_str, "pinned" => true}] =
2019 |> assign(:user, user)
2020 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
2021 |> json_response(200)
2024 test "unpin status", %{conn: conn, user: user, activity: activity} do
2025 {:ok, _} = CommonAPI.pin(activity.id, user)
2027 id_str = to_string(activity.id)
2028 user = refresh_record(user)
2030 assert %{"id" => ^id_str, "pinned" => false} =
2032 |> assign(:user, user)
2033 |> post("/api/v1/statuses/#{activity.id}/unpin")
2034 |> json_response(200)
2038 |> assign(:user, user)
2039 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
2040 |> json_response(200)
2043 test "max pinned statuses", %{conn: conn, user: user, activity: activity_one} do
2044 {:ok, activity_two} = CommonAPI.post(user, %{"status" => "HI!!!"})
2046 id_str_one = to_string(activity_one.id)
2048 assert %{"id" => ^id_str_one, "pinned" => true} =
2050 |> assign(:user, user)
2051 |> post("/api/v1/statuses/#{id_str_one}/pin")
2052 |> json_response(200)
2054 user = refresh_record(user)
2056 assert %{"error" => "You have already pinned the maximum number of statuses"} =
2058 |> assign(:user, user)
2059 |> post("/api/v1/statuses/#{activity_two.id}/pin")
2060 |> json_response(400)
2063 test "Status rich-media Card", %{conn: conn, user: user} do
2064 Pleroma.Config.put([:rich_media, :enabled], true)
2065 {:ok, activity} = CommonAPI.post(user, %{"status" => "http://example.com/ogp"})
2069 |> get("/api/v1/statuses/#{activity.id}/card")
2070 |> json_response(200)
2072 assert response == %{
2073 "image" => "http://ia.media-imdb.com/images/rock.jpg",
2074 "provider_name" => "www.imdb.com",
2075 "provider_url" => "http://www.imdb.com",
2076 "title" => "The Rock",
2078 "url" => "http://www.imdb.com/title/tt0117500/",
2079 "description" => nil,
2082 "image" => "http://ia.media-imdb.com/images/rock.jpg",
2083 "title" => "The Rock",
2084 "type" => "video.movie",
2085 "url" => "http://www.imdb.com/title/tt0117500/"
2090 # works with private posts
2092 CommonAPI.post(user, %{"status" => "http://example.com/ogp", "visibility" => "direct"})
2096 |> assign(:user, user)
2097 |> get("/api/v1/statuses/#{activity.id}/card")
2098 |> json_response(200)
2100 assert response_two == response
2102 Pleroma.Config.put([:rich_media, :enabled], false)
2107 user = insert(:user)
2108 for_user = insert(:user)
2111 CommonAPI.post(user, %{
2112 "status" => "heweoo?"
2116 CommonAPI.post(user, %{
2117 "status" => "heweoo!"
2122 |> assign(:user, for_user)
2123 |> post("/api/v1/statuses/#{activity1.id}/bookmark")
2125 assert json_response(response1, 200)["bookmarked"] == true
2129 |> assign(:user, for_user)
2130 |> post("/api/v1/statuses/#{activity2.id}/bookmark")
2132 assert json_response(response2, 200)["bookmarked"] == true
2136 |> assign(:user, for_user)
2137 |> get("/api/v1/bookmarks")
2139 assert [json_response(response2, 200), json_response(response1, 200)] ==
2140 json_response(bookmarks, 200)
2144 |> assign(:user, for_user)
2145 |> post("/api/v1/statuses/#{activity1.id}/unbookmark")
2147 assert json_response(response1, 200)["bookmarked"] == false
2151 |> assign(:user, for_user)
2152 |> get("/api/v1/bookmarks")
2154 assert [json_response(response2, 200)] == json_response(bookmarks, 200)
2157 describe "conversation muting" do
2159 user = insert(:user)
2160 {:ok, activity} = CommonAPI.post(user, %{"status" => "HIE"})
2162 [user: user, activity: activity]
2165 test "mute conversation", %{conn: conn, user: user, activity: activity} do
2166 id_str = to_string(activity.id)
2168 assert %{"id" => ^id_str, "muted" => true} =
2170 |> assign(:user, user)
2171 |> post("/api/v1/statuses/#{activity.id}/mute")
2172 |> json_response(200)
2175 test "unmute conversation", %{conn: conn, user: user, activity: activity} do
2176 {:ok, _} = CommonAPI.add_mute(user, activity)
2178 id_str = to_string(activity.id)
2179 user = refresh_record(user)
2181 assert %{"id" => ^id_str, "muted" => false} =
2183 |> assign(:user, user)
2184 |> post("/api/v1/statuses/#{activity.id}/unmute")
2185 |> json_response(200)
2189 test "flavours switching (Pleroma Extension)", %{conn: conn} do
2190 user = insert(:user)
2194 |> assign(:user, user)
2195 |> get("/api/v1/pleroma/flavour")
2197 assert "glitch" == json_response(get_old_flavour, 200)
2201 |> assign(:user, user)
2202 |> post("/api/v1/pleroma/flavour/vanilla")
2204 assert "vanilla" == json_response(set_flavour, 200)
2208 |> assign(:user, user)
2209 |> post("/api/v1/pleroma/flavour/vanilla")
2211 assert json_response(set_flavour, 200) == json_response(get_new_flavour, 200)
2214 describe "reports" do
2216 reporter = insert(:user)
2217 target_user = insert(:user)
2219 {:ok, activity} = CommonAPI.post(target_user, %{"status" => "foobar"})
2221 [reporter: reporter, target_user: target_user, activity: activity]
2224 test "submit a basic report", %{conn: conn, reporter: reporter, target_user: target_user} do
2225 assert %{"action_taken" => false, "id" => _} =
2227 |> assign(:user, reporter)
2228 |> post("/api/v1/reports", %{"account_id" => target_user.id})
2229 |> json_response(200)
2232 test "submit a report with statuses and comment", %{
2235 target_user: target_user,
2238 assert %{"action_taken" => false, "id" => _} =
2240 |> assign(:user, reporter)
2241 |> post("/api/v1/reports", %{
2242 "account_id" => target_user.id,
2243 "status_ids" => [activity.id],
2244 "comment" => "bad status!"
2246 |> json_response(200)
2249 test "account_id is required", %{
2254 assert %{"error" => "Valid `account_id` required"} =
2256 |> assign(:user, reporter)
2257 |> post("/api/v1/reports", %{"status_ids" => [activity.id]})
2258 |> json_response(400)
2261 test "comment must be up to the size specified in the config", %{
2264 target_user: target_user
2266 max_size = Pleroma.Config.get([:instance, :max_report_comment_size], 1000)
2267 comment = String.pad_trailing("a", max_size + 1, "a")
2269 error = %{"error" => "Comment must be up to #{max_size} characters"}
2273 |> assign(:user, reporter)
2274 |> post("/api/v1/reports", %{"account_id" => target_user.id, "comment" => comment})
2275 |> json_response(400)
2279 describe "link headers" do
2280 test "preserves parameters in link headers", %{conn: conn} do
2281 user = insert(:user)
2282 other_user = insert(:user)
2285 CommonAPI.post(other_user, %{
2286 "status" => "hi @#{user.nickname}",
2287 "visibility" => "public"
2291 CommonAPI.post(other_user, %{
2292 "status" => "hi @#{user.nickname}",
2293 "visibility" => "public"
2296 notification1 = Repo.get_by(Notification, activity_id: activity1.id)
2297 notification2 = Repo.get_by(Notification, activity_id: activity2.id)
2301 |> assign(:user, user)
2302 |> get("/api/v1/notifications", %{media_only: true})
2304 assert [link_header] = get_resp_header(conn, "link")
2305 assert link_header =~ ~r/media_only=true/
2306 assert link_header =~ ~r/since_id=#{notification2.id}/
2307 assert link_header =~ ~r/max_id=#{notification1.id}/