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 Activity.get_by_id(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 Activity.get_by_id(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"
157 real_status = json_response(real_conn, 200)
160 assert Object.get_by_ap_id(real_status["uri"])
164 |> Map.put("id", nil)
165 |> Map.put("url", nil)
166 |> Map.put("uri", nil)
167 |> Map.put("created_at", nil)
168 |> Kernel.put_in(["pleroma", "conversation_id"], nil)
172 |> assign(:user, user)
173 |> post("/api/v1/statuses", %{
175 "\"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",
179 fake_status = json_response(fake_conn, 200)
182 refute Object.get_by_ap_id(fake_status["uri"])
186 |> Map.put("id", nil)
187 |> Map.put("url", nil)
188 |> Map.put("uri", nil)
189 |> Map.put("created_at", nil)
190 |> Kernel.put_in(["pleroma", "conversation_id"], nil)
192 assert real_status == fake_status
195 test "posting a status with OGP link preview", %{conn: conn} do
196 Pleroma.Config.put([:rich_media, :enabled], true)
201 |> assign(:user, user)
202 |> post("/api/v1/statuses", %{
203 "status" => "http://example.com/ogp"
206 assert %{"id" => id, "card" => %{"title" => "The Rock"}} = json_response(conn, 200)
207 assert Activity.get_by_id(id)
208 Pleroma.Config.put([:rich_media, :enabled], false)
211 test "posting a direct status", %{conn: conn} do
212 user1 = insert(:user)
213 user2 = insert(:user)
214 content = "direct cofe @#{user2.nickname}"
218 |> assign(:user, user1)
219 |> post("api/v1/statuses", %{"status" => content, "visibility" => "direct"})
221 assert %{"id" => id, "visibility" => "direct"} = json_response(conn, 200)
222 assert activity = Activity.get_by_id(id)
223 assert activity.recipients == [user2.ap_id, user1.ap_id]
224 assert activity.data["to"] == [user2.ap_id]
225 assert activity.data["cc"] == []
228 test "direct timeline", %{conn: conn} do
229 user_one = insert(:user)
230 user_two = insert(:user)
232 {:ok, user_two} = User.follow(user_two, user_one)
235 CommonAPI.post(user_one, %{
236 "status" => "Hi @#{user_two.nickname}!",
237 "visibility" => "direct"
240 {:ok, _follower_only} =
241 CommonAPI.post(user_one, %{
242 "status" => "Hi @#{user_two.nickname}!",
243 "visibility" => "private"
246 # Only direct should be visible here
249 |> assign(:user, user_two)
250 |> get("api/v1/timelines/direct")
252 [status] = json_response(res_conn, 200)
254 assert %{"visibility" => "direct"} = status
255 assert status["url"] != direct.data["id"]
257 # User should be able to see his own direct message
260 |> assign(:user, user_one)
261 |> get("api/v1/timelines/direct")
263 [status] = json_response(res_conn, 200)
265 assert %{"visibility" => "direct"} = status
267 # Both should be visible here
270 |> assign(:user, user_two)
271 |> get("api/v1/timelines/home")
273 [_s1, _s2] = json_response(res_conn, 200)
276 Enum.each(1..20, fn _ ->
278 CommonAPI.post(user_one, %{
279 "status" => "Hi @#{user_two.nickname}!",
280 "visibility" => "direct"
286 |> assign(:user, user_two)
287 |> get("api/v1/timelines/direct")
289 statuses = json_response(res_conn, 200)
290 assert length(statuses) == 20
294 |> assign(:user, user_two)
295 |> get("api/v1/timelines/direct", %{max_id: List.last(statuses)["id"]})
297 [status] = json_response(res_conn, 200)
299 assert status["url"] != direct.data["id"]
302 test "doesn't include DMs from blocked users", %{conn: conn} do
303 blocker = insert(:user)
304 blocked = insert(:user)
306 {:ok, blocker} = User.block(blocker, blocked)
308 {:ok, _blocked_direct} =
309 CommonAPI.post(blocked, %{
310 "status" => "Hi @#{blocker.nickname}!",
311 "visibility" => "direct"
315 CommonAPI.post(user, %{
316 "status" => "Hi @#{blocker.nickname}!",
317 "visibility" => "direct"
322 |> assign(:user, user)
323 |> get("api/v1/timelines/direct")
325 [status] = json_response(res_conn, 200)
326 assert status["id"] == direct.id
329 test "replying to a status", %{conn: conn} do
332 {:ok, replied_to} = TwitterAPI.create_status(user, %{"status" => "cofe"})
336 |> assign(:user, user)
337 |> post("/api/v1/statuses", %{"status" => "xD", "in_reply_to_id" => replied_to.id})
339 assert %{"content" => "xD", "id" => id} = json_response(conn, 200)
341 activity = Activity.get_by_id(id)
343 assert activity.data["context"] == replied_to.data["context"]
344 assert activity.data["object"]["inReplyToStatusId"] == replied_to.id
347 test "posting a status with an invalid in_reply_to_id", %{conn: conn} do
352 |> assign(:user, user)
353 |> post("/api/v1/statuses", %{"status" => "xD", "in_reply_to_id" => ""})
355 assert %{"content" => "xD", "id" => id} = json_response(conn, 200)
357 activity = Activity.get_by_id(id)
362 test "verify_credentials", %{conn: conn} do
367 |> assign(:user, user)
368 |> get("/api/v1/accounts/verify_credentials")
370 assert %{"id" => id, "source" => %{"privacy" => "public"}} = json_response(conn, 200)
371 assert id == to_string(user.id)
374 test "verify_credentials default scope unlisted", %{conn: conn} do
375 user = insert(:user, %{info: %Pleroma.User.Info{default_scope: "unlisted"}})
379 |> assign(:user, user)
380 |> get("/api/v1/accounts/verify_credentials")
382 assert %{"id" => id, "source" => %{"privacy" => "unlisted"}} = json_response(conn, 200)
383 assert id == to_string(user.id)
386 test "apps/verify_credentials", %{conn: conn} do
387 token = insert(:oauth_token)
391 |> assign(:user, token.user)
392 |> assign(:token, token)
393 |> get("/api/v1/apps/verify_credentials")
395 app = Repo.preload(token, :app).app
398 "name" => app.client_name,
399 "website" => app.website,
400 "vapid_key" => Push.vapid_config() |> Keyword.get(:public_key)
403 assert expected == json_response(conn, 200)
406 test "creates an oauth app", %{conn: conn} do
408 app_attrs = build(:oauth_app)
412 |> assign(:user, user)
413 |> post("/api/v1/apps", %{
414 client_name: app_attrs.client_name,
415 redirect_uris: app_attrs.redirect_uris
418 [app] = Repo.all(App)
421 "name" => app.client_name,
422 "website" => app.website,
423 "client_id" => app.client_id,
424 "client_secret" => app.client_secret,
425 "id" => app.id |> to_string(),
426 "redirect_uri" => app.redirect_uris,
427 "vapid_key" => Push.vapid_config() |> Keyword.get(:public_key)
430 assert expected == json_response(conn, 200)
433 test "get a status", %{conn: conn} do
434 activity = insert(:note_activity)
438 |> get("/api/v1/statuses/#{activity.id}")
440 assert %{"id" => id} = json_response(conn, 200)
441 assert id == to_string(activity.id)
444 describe "deleting a status" do
445 test "when you created it", %{conn: conn} do
446 activity = insert(:note_activity)
447 author = User.get_by_ap_id(activity.data["actor"])
451 |> assign(:user, author)
452 |> delete("/api/v1/statuses/#{activity.id}")
454 assert %{} = json_response(conn, 200)
456 refute Activity.get_by_id(activity.id)
459 test "when you didn't create it", %{conn: conn} do
460 activity = insert(:note_activity)
465 |> assign(:user, user)
466 |> delete("/api/v1/statuses/#{activity.id}")
468 assert %{"error" => _} = json_response(conn, 403)
470 assert Activity.get_by_id(activity.id) == activity
473 test "when you're an admin or moderator", %{conn: conn} do
474 activity1 = insert(:note_activity)
475 activity2 = insert(:note_activity)
476 admin = insert(:user, info: %{is_admin: true})
477 moderator = insert(:user, info: %{is_moderator: true})
481 |> assign(:user, admin)
482 |> delete("/api/v1/statuses/#{activity1.id}")
484 assert %{} = json_response(res_conn, 200)
488 |> assign(:user, moderator)
489 |> delete("/api/v1/statuses/#{activity2.id}")
491 assert %{} = json_response(res_conn, 200)
493 refute Activity.get_by_id(activity1.id)
494 refute Activity.get_by_id(activity2.id)
498 describe "filters" do
499 test "creating a filter", %{conn: conn} do
502 filter = %Pleroma.Filter{
509 |> assign(:user, user)
510 |> post("/api/v1/filters", %{"phrase" => filter.phrase, context: filter.context})
512 assert response = json_response(conn, 200)
513 assert response["phrase"] == filter.phrase
514 assert response["context"] == filter.context
515 assert response["id"] != nil
516 assert response["id"] != ""
519 test "fetching a list of filters", %{conn: conn} do
522 query_one = %Pleroma.Filter{
529 query_two = %Pleroma.Filter{
536 {:ok, filter_one} = Pleroma.Filter.create(query_one)
537 {:ok, filter_two} = Pleroma.Filter.create(query_two)
541 |> assign(:user, user)
542 |> get("/api/v1/filters")
543 |> json_response(200)
549 filters: [filter_two, filter_one]
553 test "get a filter", %{conn: conn} do
556 query = %Pleroma.Filter{
563 {:ok, filter} = Pleroma.Filter.create(query)
567 |> assign(:user, user)
568 |> get("/api/v1/filters/#{filter.filter_id}")
570 assert _response = json_response(conn, 200)
573 test "update a filter", %{conn: conn} do
576 query = %Pleroma.Filter{
583 {:ok, _filter} = Pleroma.Filter.create(query)
585 new = %Pleroma.Filter{
592 |> assign(:user, user)
593 |> put("/api/v1/filters/#{query.filter_id}", %{
598 assert response = json_response(conn, 200)
599 assert response["phrase"] == new.phrase
600 assert response["context"] == new.context
603 test "delete a filter", %{conn: conn} do
606 query = %Pleroma.Filter{
613 {:ok, filter} = Pleroma.Filter.create(query)
617 |> assign(:user, user)
618 |> delete("/api/v1/filters/#{filter.filter_id}")
620 assert response = json_response(conn, 200)
621 assert response == %{}
626 test "creating a list", %{conn: conn} do
631 |> assign(:user, user)
632 |> post("/api/v1/lists", %{"title" => "cuties"})
634 assert %{"title" => title} = json_response(conn, 200)
635 assert title == "cuties"
638 test "adding users to a list", %{conn: conn} do
640 other_user = insert(:user)
641 {:ok, list} = Pleroma.List.create("name", user)
645 |> assign(:user, user)
646 |> post("/api/v1/lists/#{list.id}/accounts", %{"account_ids" => [other_user.id]})
648 assert %{} == json_response(conn, 200)
649 %Pleroma.List{following: following} = Pleroma.List.get(list.id, user)
650 assert following == [other_user.follower_address]
653 test "removing users from a list", %{conn: conn} do
655 other_user = insert(:user)
656 third_user = insert(:user)
657 {:ok, list} = Pleroma.List.create("name", user)
658 {:ok, list} = Pleroma.List.follow(list, other_user)
659 {:ok, list} = Pleroma.List.follow(list, third_user)
663 |> assign(:user, user)
664 |> delete("/api/v1/lists/#{list.id}/accounts", %{"account_ids" => [other_user.id]})
666 assert %{} == json_response(conn, 200)
667 %Pleroma.List{following: following} = Pleroma.List.get(list.id, user)
668 assert following == [third_user.follower_address]
671 test "listing users in a list", %{conn: conn} do
673 other_user = insert(:user)
674 {:ok, list} = Pleroma.List.create("name", user)
675 {:ok, list} = Pleroma.List.follow(list, other_user)
679 |> assign(:user, user)
680 |> get("/api/v1/lists/#{list.id}/accounts", %{"account_ids" => [other_user.id]})
682 assert [%{"id" => id}] = json_response(conn, 200)
683 assert id == to_string(other_user.id)
686 test "retrieving a list", %{conn: conn} do
688 {:ok, list} = Pleroma.List.create("name", user)
692 |> assign(:user, user)
693 |> get("/api/v1/lists/#{list.id}")
695 assert %{"id" => id} = json_response(conn, 200)
696 assert id == to_string(list.id)
699 test "renaming a list", %{conn: conn} do
701 {:ok, list} = Pleroma.List.create("name", user)
705 |> assign(:user, user)
706 |> put("/api/v1/lists/#{list.id}", %{"title" => "newname"})
708 assert %{"title" => name} = json_response(conn, 200)
709 assert name == "newname"
712 test "deleting a list", %{conn: conn} do
714 {:ok, list} = Pleroma.List.create("name", user)
718 |> assign(:user, user)
719 |> delete("/api/v1/lists/#{list.id}")
721 assert %{} = json_response(conn, 200)
722 assert is_nil(Repo.get(Pleroma.List, list.id))
725 test "list timeline", %{conn: conn} do
727 other_user = insert(:user)
728 {:ok, _activity_one} = TwitterAPI.create_status(user, %{"status" => "Marisa is cute."})
729 {:ok, activity_two} = TwitterAPI.create_status(other_user, %{"status" => "Marisa is cute."})
730 {:ok, list} = Pleroma.List.create("name", user)
731 {:ok, list} = Pleroma.List.follow(list, other_user)
735 |> assign(:user, user)
736 |> get("/api/v1/timelines/list/#{list.id}")
738 assert [%{"id" => id}] = json_response(conn, 200)
740 assert id == to_string(activity_two.id)
743 test "list timeline does not leak non-public statuses for unfollowed users", %{conn: conn} do
745 other_user = insert(:user)
746 {:ok, activity_one} = TwitterAPI.create_status(other_user, %{"status" => "Marisa is cute."})
748 {:ok, _activity_two} =
749 TwitterAPI.create_status(other_user, %{
750 "status" => "Marisa is cute.",
751 "visibility" => "private"
754 {:ok, list} = Pleroma.List.create("name", user)
755 {:ok, list} = Pleroma.List.follow(list, other_user)
759 |> assign(:user, user)
760 |> get("/api/v1/timelines/list/#{list.id}")
762 assert [%{"id" => id}] = json_response(conn, 200)
764 assert id == to_string(activity_one.id)
768 describe "notifications" do
769 test "list of notifications", %{conn: conn} do
771 other_user = insert(:user)
774 TwitterAPI.create_status(other_user, %{"status" => "hi @#{user.nickname}"})
776 {:ok, [_notification]} = Notification.create_notifications(activity)
780 |> assign(:user, user)
781 |> get("/api/v1/notifications")
784 "hi <span class=\"h-card\"><a data-user=\"#{user.id}\" class=\"u-url mention\" href=\"#{
786 }\">@<span>#{user.nickname}</span></a></span>"
788 assert [%{"status" => %{"content" => response}} | _rest] = json_response(conn, 200)
789 assert response == expected_response
792 test "getting a single notification", %{conn: conn} do
794 other_user = insert(:user)
797 TwitterAPI.create_status(other_user, %{"status" => "hi @#{user.nickname}"})
799 {:ok, [notification]} = Notification.create_notifications(activity)
803 |> assign(:user, user)
804 |> get("/api/v1/notifications/#{notification.id}")
807 "hi <span class=\"h-card\"><a data-user=\"#{user.id}\" class=\"u-url mention\" href=\"#{
809 }\">@<span>#{user.nickname}</span></a></span>"
811 assert %{"status" => %{"content" => response}} = json_response(conn, 200)
812 assert response == expected_response
815 test "dismissing a single notification", %{conn: conn} do
817 other_user = insert(:user)
820 TwitterAPI.create_status(other_user, %{"status" => "hi @#{user.nickname}"})
822 {:ok, [notification]} = Notification.create_notifications(activity)
826 |> assign(:user, user)
827 |> post("/api/v1/notifications/dismiss", %{"id" => notification.id})
829 assert %{} = json_response(conn, 200)
832 test "clearing all notifications", %{conn: conn} do
834 other_user = insert(:user)
837 TwitterAPI.create_status(other_user, %{"status" => "hi @#{user.nickname}"})
839 {:ok, [_notification]} = Notification.create_notifications(activity)
843 |> assign(:user, user)
844 |> post("/api/v1/notifications/clear")
846 assert %{} = json_response(conn, 200)
850 |> assign(:user, user)
851 |> get("/api/v1/notifications")
853 assert all = json_response(conn, 200)
857 test "paginates notifications using min_id, since_id, max_id, and limit", %{conn: conn} do
859 other_user = insert(:user)
861 {:ok, activity1} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
862 {:ok, activity2} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
863 {:ok, activity3} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
864 {:ok, activity4} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
866 notification1_id = Repo.get_by(Notification, activity_id: activity1.id).id |> to_string()
867 notification2_id = Repo.get_by(Notification, activity_id: activity2.id).id |> to_string()
868 notification3_id = Repo.get_by(Notification, activity_id: activity3.id).id |> to_string()
869 notification4_id = Repo.get_by(Notification, activity_id: activity4.id).id |> to_string()
873 |> assign(:user, user)
878 |> get("/api/v1/notifications?limit=2&min_id=#{notification1_id}")
880 result = json_response(conn_res, 200)
881 assert [%{"id" => ^notification3_id}, %{"id" => ^notification2_id}] = result
886 |> get("/api/v1/notifications?limit=2&since_id=#{notification1_id}")
888 result = json_response(conn_res, 200)
889 assert [%{"id" => ^notification4_id}, %{"id" => ^notification3_id}] = result
894 |> get("/api/v1/notifications?limit=2&max_id=#{notification4_id}")
896 result = json_response(conn_res, 200)
897 assert [%{"id" => ^notification3_id}, %{"id" => ^notification2_id}] = result
900 test "filters notifications using exclude_types", %{conn: conn} do
902 other_user = insert(:user)
904 {:ok, mention_activity} = CommonAPI.post(other_user, %{"status" => "hey @#{user.nickname}"})
905 {:ok, create_activity} = CommonAPI.post(user, %{"status" => "hey"})
906 {:ok, favorite_activity, _} = CommonAPI.favorite(create_activity.id, other_user)
907 {:ok, reblog_activity, _} = CommonAPI.repeat(create_activity.id, other_user)
908 {:ok, _, _, follow_activity} = CommonAPI.follow(other_user, user)
910 mention_notification_id =
911 Repo.get_by(Notification, activity_id: mention_activity.id).id |> to_string()
913 favorite_notification_id =
914 Repo.get_by(Notification, activity_id: favorite_activity.id).id |> to_string()
916 reblog_notification_id =
917 Repo.get_by(Notification, activity_id: reblog_activity.id).id |> to_string()
919 follow_notification_id =
920 Repo.get_by(Notification, activity_id: follow_activity.id).id |> to_string()
924 |> assign(:user, user)
927 get(conn, "/api/v1/notifications", %{exclude_types: ["mention", "favourite", "reblog"]})
929 assert [%{"id" => ^follow_notification_id}] = json_response(conn_res, 200)
932 get(conn, "/api/v1/notifications", %{exclude_types: ["favourite", "reblog", "follow"]})
934 assert [%{"id" => ^mention_notification_id}] = json_response(conn_res, 200)
937 get(conn, "/api/v1/notifications", %{exclude_types: ["reblog", "follow", "mention"]})
939 assert [%{"id" => ^favorite_notification_id}] = json_response(conn_res, 200)
942 get(conn, "/api/v1/notifications", %{exclude_types: ["follow", "mention", "favourite"]})
944 assert [%{"id" => ^reblog_notification_id}] = json_response(conn_res, 200)
948 describe "reblogging" do
949 test "reblogs and returns the reblogged status", %{conn: conn} do
950 activity = insert(:note_activity)
955 |> assign(:user, user)
956 |> post("/api/v1/statuses/#{activity.id}/reblog")
958 assert %{"reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 1}} =
959 json_response(conn, 200)
961 assert to_string(activity.id) == id
965 describe "unreblogging" do
966 test "unreblogs and returns the unreblogged status", %{conn: conn} do
967 activity = insert(:note_activity)
970 {:ok, _, _} = CommonAPI.repeat(activity.id, user)
974 |> assign(:user, user)
975 |> post("/api/v1/statuses/#{activity.id}/unreblog")
977 assert %{"id" => id, "reblogged" => false, "reblogs_count" => 0} = json_response(conn, 200)
979 assert to_string(activity.id) == id
983 describe "favoriting" do
984 test "favs a status and returns it", %{conn: conn} do
985 activity = insert(:note_activity)
990 |> assign(:user, user)
991 |> post("/api/v1/statuses/#{activity.id}/favourite")
993 assert %{"id" => id, "favourites_count" => 1, "favourited" => true} =
994 json_response(conn, 200)
996 assert to_string(activity.id) == id
999 test "returns 500 for a wrong id", %{conn: conn} do
1000 user = insert(:user)
1004 |> assign(:user, user)
1005 |> post("/api/v1/statuses/1/favourite")
1006 |> json_response(500)
1008 assert resp == "Something went wrong"
1012 describe "unfavoriting" do
1013 test "unfavorites a status and returns it", %{conn: conn} do
1014 activity = insert(:note_activity)
1015 user = insert(:user)
1017 {:ok, _, _} = CommonAPI.favorite(activity.id, user)
1021 |> assign(:user, user)
1022 |> post("/api/v1/statuses/#{activity.id}/unfavourite")
1024 assert %{"id" => id, "favourites_count" => 0, "favourited" => false} =
1025 json_response(conn, 200)
1027 assert to_string(activity.id) == id
1031 describe "user timelines" do
1032 test "gets a users statuses", %{conn: conn} do
1033 user_one = insert(:user)
1034 user_two = insert(:user)
1035 user_three = insert(:user)
1037 {:ok, user_three} = User.follow(user_three, user_one)
1039 {:ok, activity} = CommonAPI.post(user_one, %{"status" => "HI!!!"})
1041 {:ok, direct_activity} =
1042 CommonAPI.post(user_one, %{
1043 "status" => "Hi, @#{user_two.nickname}.",
1044 "visibility" => "direct"
1047 {:ok, private_activity} =
1048 CommonAPI.post(user_one, %{"status" => "private", "visibility" => "private"})
1052 |> get("/api/v1/accounts/#{user_one.id}/statuses")
1054 assert [%{"id" => id}] = json_response(resp, 200)
1055 assert id == to_string(activity.id)
1059 |> assign(:user, user_two)
1060 |> get("/api/v1/accounts/#{user_one.id}/statuses")
1062 assert [%{"id" => id_one}, %{"id" => id_two}] = json_response(resp, 200)
1063 assert id_one == to_string(direct_activity.id)
1064 assert id_two == to_string(activity.id)
1068 |> assign(:user, user_three)
1069 |> get("/api/v1/accounts/#{user_one.id}/statuses")
1071 assert [%{"id" => id_one}, %{"id" => id_two}] = json_response(resp, 200)
1072 assert id_one == to_string(private_activity.id)
1073 assert id_two == to_string(activity.id)
1076 test "unimplemented pinned statuses feature", %{conn: conn} do
1077 note = insert(:note_activity)
1078 user = User.get_by_ap_id(note.data["actor"])
1082 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
1084 assert json_response(conn, 200) == []
1087 test "gets an users media", %{conn: conn} do
1088 note = insert(:note_activity)
1089 user = User.get_by_ap_id(note.data["actor"])
1091 file = %Plug.Upload{
1092 content_type: "image/jpg",
1093 path: Path.absname("test/fixtures/image.jpg"),
1094 filename: "an_image.jpg"
1098 TwitterAPI.upload(file, user, "json")
1102 TwitterAPI.create_status(user, %{"status" => "cofe", "media_ids" => [media["media_id"]]})
1106 |> get("/api/v1/accounts/#{user.id}/statuses", %{"only_media" => "true"})
1108 assert [%{"id" => id}] = json_response(conn, 200)
1109 assert id == to_string(image_post.id)
1113 |> get("/api/v1/accounts/#{user.id}/statuses", %{"only_media" => "1"})
1115 assert [%{"id" => id}] = json_response(conn, 200)
1116 assert id == to_string(image_post.id)
1119 test "gets a user's statuses without reblogs", %{conn: conn} do
1120 user = insert(:user)
1121 {:ok, post} = CommonAPI.post(user, %{"status" => "HI!!!"})
1122 {:ok, _, _} = CommonAPI.repeat(post.id, user)
1126 |> get("/api/v1/accounts/#{user.id}/statuses", %{"exclude_reblogs" => "true"})
1128 assert [%{"id" => id}] = json_response(conn, 200)
1129 assert id == to_string(post.id)
1133 |> get("/api/v1/accounts/#{user.id}/statuses", %{"exclude_reblogs" => "1"})
1135 assert [%{"id" => id}] = json_response(conn, 200)
1136 assert id == to_string(post.id)
1140 describe "user relationships" do
1141 test "returns the relationships for the current user", %{conn: conn} do
1142 user = insert(:user)
1143 other_user = insert(:user)
1144 {:ok, user} = User.follow(user, other_user)
1148 |> assign(:user, user)
1149 |> get("/api/v1/accounts/relationships", %{"id" => [other_user.id]})
1151 assert [relationship] = json_response(conn, 200)
1153 assert to_string(other_user.id) == relationship["id"]
1157 describe "locked accounts" do
1158 test "/api/v1/follow_requests works" do
1159 user = insert(:user, %{info: %Pleroma.User.Info{locked: true}})
1160 other_user = insert(:user)
1162 {:ok, _activity} = ActivityPub.follow(other_user, user)
1164 user = User.get_by_id(user.id)
1165 other_user = User.get_by_id(other_user.id)
1167 assert User.following?(other_user, user) == false
1171 |> assign(:user, user)
1172 |> get("/api/v1/follow_requests")
1174 assert [relationship] = json_response(conn, 200)
1175 assert to_string(other_user.id) == relationship["id"]
1178 test "/api/v1/follow_requests/:id/authorize works" do
1179 user = insert(:user, %{info: %User.Info{locked: true}})
1180 other_user = insert(:user)
1182 {:ok, _activity} = ActivityPub.follow(other_user, user)
1184 user = User.get_by_id(user.id)
1185 other_user = User.get_by_id(other_user.id)
1187 assert User.following?(other_user, user) == false
1191 |> assign(:user, user)
1192 |> post("/api/v1/follow_requests/#{other_user.id}/authorize")
1194 assert relationship = json_response(conn, 200)
1195 assert to_string(other_user.id) == relationship["id"]
1197 user = User.get_by_id(user.id)
1198 other_user = User.get_by_id(other_user.id)
1200 assert User.following?(other_user, user) == true
1203 test "verify_credentials", %{conn: conn} do
1204 user = insert(:user, %{info: %Pleroma.User.Info{default_scope: "private"}})
1208 |> assign(:user, user)
1209 |> get("/api/v1/accounts/verify_credentials")
1211 assert %{"id" => id, "source" => %{"privacy" => "private"}} = json_response(conn, 200)
1212 assert id == to_string(user.id)
1215 test "/api/v1/follow_requests/:id/reject works" do
1216 user = insert(:user, %{info: %Pleroma.User.Info{locked: true}})
1217 other_user = insert(:user)
1219 {:ok, _activity} = ActivityPub.follow(other_user, user)
1221 user = User.get_by_id(user.id)
1225 |> assign(:user, user)
1226 |> post("/api/v1/follow_requests/#{other_user.id}/reject")
1228 assert relationship = json_response(conn, 200)
1229 assert to_string(other_user.id) == relationship["id"]
1231 user = User.get_by_id(user.id)
1232 other_user = User.get_by_id(other_user.id)
1234 assert User.following?(other_user, user) == false
1238 test "account fetching", %{conn: conn} do
1239 user = insert(:user)
1243 |> get("/api/v1/accounts/#{user.id}")
1245 assert %{"id" => id} = json_response(conn, 200)
1246 assert id == to_string(user.id)
1250 |> get("/api/v1/accounts/-1")
1252 assert %{"error" => "Can't find user"} = json_response(conn, 404)
1255 test "account fetching also works nickname", %{conn: conn} do
1256 user = insert(:user)
1260 |> get("/api/v1/accounts/#{user.nickname}")
1262 assert %{"id" => id} = json_response(conn, 200)
1263 assert id == user.id
1266 test "media upload", %{conn: conn} do
1267 file = %Plug.Upload{
1268 content_type: "image/jpg",
1269 path: Path.absname("test/fixtures/image.jpg"),
1270 filename: "an_image.jpg"
1273 desc = "Description of the image"
1275 user = insert(:user)
1279 |> assign(:user, user)
1280 |> post("/api/v1/media", %{"file" => file, "description" => desc})
1282 assert media = json_response(conn, 200)
1284 assert media["type"] == "image"
1285 assert media["description"] == desc
1288 object = Repo.get(Object, media["id"])
1289 assert object.data["actor"] == User.ap_id(user)
1292 test "hashtag timeline", %{conn: conn} do
1293 following = insert(:user)
1296 {:ok, activity} = TwitterAPI.create_status(following, %{"status" => "test #2hu"})
1298 {:ok, [_activity]} =
1299 OStatus.fetch_activity_from_url("https://shitposter.club/notice/2827873")
1303 |> get("/api/v1/timelines/tag/2hu")
1305 assert [%{"id" => id}] = json_response(nconn, 200)
1307 assert id == to_string(activity.id)
1309 # works for different capitalization too
1312 |> get("/api/v1/timelines/tag/2HU")
1314 assert [%{"id" => id}] = json_response(nconn, 200)
1316 assert id == to_string(activity.id)
1320 test "multi-hashtag timeline", %{conn: conn} do
1321 user = insert(:user)
1323 {:ok, activity_test} = CommonAPI.post(user, %{"status" => "#test"})
1324 {:ok, activity_test1} = CommonAPI.post(user, %{"status" => "#test #test1"})
1325 {:ok, activity_none} = CommonAPI.post(user, %{"status" => "#test #none"})
1329 |> get("/api/v1/timelines/tag/test", %{"any" => ["test1"]})
1331 [status_none, status_test1, status_test] = json_response(any_test, 200)
1333 assert to_string(activity_test.id) == status_test["id"]
1334 assert to_string(activity_test1.id) == status_test1["id"]
1335 assert to_string(activity_none.id) == status_none["id"]
1339 |> get("/api/v1/timelines/tag/test", %{"all" => ["test1"], "none" => ["none"]})
1341 assert [status_test1] == json_response(restricted_test, 200)
1343 all_test = conn |> get("/api/v1/timelines/tag/test", %{"all" => ["none"]})
1345 assert [status_none] == json_response(all_test, 200)
1348 test "getting followers", %{conn: conn} do
1349 user = insert(:user)
1350 other_user = insert(:user)
1351 {:ok, user} = User.follow(user, other_user)
1355 |> get("/api/v1/accounts/#{other_user.id}/followers")
1357 assert [%{"id" => id}] = json_response(conn, 200)
1358 assert id == to_string(user.id)
1361 test "getting followers, hide_followers", %{conn: conn} do
1362 user = insert(:user)
1363 other_user = insert(:user, %{info: %{hide_followers: true}})
1364 {:ok, _user} = User.follow(user, other_user)
1368 |> get("/api/v1/accounts/#{other_user.id}/followers")
1370 assert [] == json_response(conn, 200)
1373 test "getting followers, hide_followers, same user requesting", %{conn: conn} do
1374 user = insert(:user)
1375 other_user = insert(:user, %{info: %{hide_followers: true}})
1376 {:ok, _user} = User.follow(user, other_user)
1380 |> assign(:user, other_user)
1381 |> get("/api/v1/accounts/#{other_user.id}/followers")
1383 refute [] == json_response(conn, 200)
1386 test "getting followers, pagination", %{conn: conn} do
1387 user = insert(:user)
1388 follower1 = insert(:user)
1389 follower2 = insert(:user)
1390 follower3 = insert(:user)
1391 {:ok, _} = User.follow(follower1, user)
1392 {:ok, _} = User.follow(follower2, user)
1393 {:ok, _} = User.follow(follower3, user)
1397 |> assign(:user, user)
1401 |> get("/api/v1/accounts/#{user.id}/followers?since_id=#{follower1.id}")
1403 assert [%{"id" => id3}, %{"id" => id2}] = json_response(res_conn, 200)
1404 assert id3 == follower3.id
1405 assert id2 == follower2.id
1409 |> get("/api/v1/accounts/#{user.id}/followers?max_id=#{follower3.id}")
1411 assert [%{"id" => id2}, %{"id" => id1}] = json_response(res_conn, 200)
1412 assert id2 == follower2.id
1413 assert id1 == follower1.id
1417 |> get("/api/v1/accounts/#{user.id}/followers?limit=1&max_id=#{follower3.id}")
1419 assert [%{"id" => id2}] = json_response(res_conn, 200)
1420 assert id2 == follower2.id
1422 assert [link_header] = get_resp_header(res_conn, "link")
1423 assert link_header =~ ~r/since_id=#{follower2.id}/
1424 assert link_header =~ ~r/max_id=#{follower2.id}/
1427 test "getting following", %{conn: conn} do
1428 user = insert(:user)
1429 other_user = insert(:user)
1430 {:ok, user} = User.follow(user, other_user)
1434 |> get("/api/v1/accounts/#{user.id}/following")
1436 assert [%{"id" => id}] = json_response(conn, 200)
1437 assert id == to_string(other_user.id)
1440 test "getting following, hide_follows", %{conn: conn} do
1441 user = insert(:user, %{info: %{hide_follows: true}})
1442 other_user = insert(:user)
1443 {:ok, user} = User.follow(user, other_user)
1447 |> get("/api/v1/accounts/#{user.id}/following")
1449 assert [] == json_response(conn, 200)
1452 test "getting following, hide_follows, same user requesting", %{conn: conn} do
1453 user = insert(:user, %{info: %{hide_follows: true}})
1454 other_user = insert(:user)
1455 {:ok, user} = User.follow(user, other_user)
1459 |> assign(:user, user)
1460 |> get("/api/v1/accounts/#{user.id}/following")
1462 refute [] == json_response(conn, 200)
1465 test "getting following, pagination", %{conn: conn} do
1466 user = insert(:user)
1467 following1 = insert(:user)
1468 following2 = insert(:user)
1469 following3 = insert(:user)
1470 {:ok, _} = User.follow(user, following1)
1471 {:ok, _} = User.follow(user, following2)
1472 {:ok, _} = User.follow(user, following3)
1476 |> assign(:user, user)
1480 |> get("/api/v1/accounts/#{user.id}/following?since_id=#{following1.id}")
1482 assert [%{"id" => id3}, %{"id" => id2}] = json_response(res_conn, 200)
1483 assert id3 == following3.id
1484 assert id2 == following2.id
1488 |> get("/api/v1/accounts/#{user.id}/following?max_id=#{following3.id}")
1490 assert [%{"id" => id2}, %{"id" => id1}] = json_response(res_conn, 200)
1491 assert id2 == following2.id
1492 assert id1 == following1.id
1496 |> get("/api/v1/accounts/#{user.id}/following?limit=1&max_id=#{following3.id}")
1498 assert [%{"id" => id2}] = json_response(res_conn, 200)
1499 assert id2 == following2.id
1501 assert [link_header] = get_resp_header(res_conn, "link")
1502 assert link_header =~ ~r/since_id=#{following2.id}/
1503 assert link_header =~ ~r/max_id=#{following2.id}/
1506 test "following / unfollowing a user", %{conn: conn} do
1507 user = insert(:user)
1508 other_user = insert(:user)
1512 |> assign(:user, user)
1513 |> post("/api/v1/accounts/#{other_user.id}/follow")
1515 assert %{"id" => _id, "following" => true} = json_response(conn, 200)
1517 user = User.get_by_id(user.id)
1521 |> assign(:user, user)
1522 |> post("/api/v1/accounts/#{other_user.id}/unfollow")
1524 assert %{"id" => _id, "following" => false} = json_response(conn, 200)
1526 user = User.get_by_id(user.id)
1530 |> assign(:user, user)
1531 |> post("/api/v1/follows", %{"uri" => other_user.nickname})
1533 assert %{"id" => id} = json_response(conn, 200)
1534 assert id == to_string(other_user.id)
1537 test "muting / unmuting a user", %{conn: conn} do
1538 user = insert(:user)
1539 other_user = insert(:user)
1543 |> assign(:user, user)
1544 |> post("/api/v1/accounts/#{other_user.id}/mute")
1546 assert %{"id" => _id, "muting" => true} = json_response(conn, 200)
1548 user = User.get_by_id(user.id)
1552 |> assign(:user, user)
1553 |> post("/api/v1/accounts/#{other_user.id}/unmute")
1555 assert %{"id" => _id, "muting" => false} = json_response(conn, 200)
1558 test "subscribing / unsubscribing to a user", %{conn: conn} do
1559 user = insert(:user)
1560 subscription_target = insert(:user)
1564 |> assign(:user, user)
1565 |> post("/api/v1/pleroma/accounts/#{subscription_target.id}/subscribe")
1567 assert %{"id" => _id, "subscribing" => true} = json_response(conn, 200)
1571 |> assign(:user, user)
1572 |> post("/api/v1/pleroma/accounts/#{subscription_target.id}/unsubscribe")
1574 assert %{"id" => _id, "subscribing" => false} = json_response(conn, 200)
1577 test "getting a list of mutes", %{conn: conn} do
1578 user = insert(:user)
1579 other_user = insert(:user)
1581 {:ok, user} = User.mute(user, other_user)
1585 |> assign(:user, user)
1586 |> get("/api/v1/mutes")
1588 other_user_id = to_string(other_user.id)
1589 assert [%{"id" => ^other_user_id}] = json_response(conn, 200)
1592 test "blocking / unblocking a user", %{conn: conn} do
1593 user = insert(:user)
1594 other_user = insert(:user)
1598 |> assign(:user, user)
1599 |> post("/api/v1/accounts/#{other_user.id}/block")
1601 assert %{"id" => _id, "blocking" => true} = json_response(conn, 200)
1603 user = User.get_by_id(user.id)
1607 |> assign(:user, user)
1608 |> post("/api/v1/accounts/#{other_user.id}/unblock")
1610 assert %{"id" => _id, "blocking" => false} = json_response(conn, 200)
1613 test "getting a list of blocks", %{conn: conn} do
1614 user = insert(:user)
1615 other_user = insert(:user)
1617 {:ok, user} = User.block(user, other_user)
1621 |> assign(:user, user)
1622 |> get("/api/v1/blocks")
1624 other_user_id = to_string(other_user.id)
1625 assert [%{"id" => ^other_user_id}] = json_response(conn, 200)
1628 test "blocking / unblocking a domain", %{conn: conn} do
1629 user = insert(:user)
1630 other_user = insert(:user, %{ap_id: "https://dogwhistle.zone/@pundit"})
1634 |> assign(:user, user)
1635 |> post("/api/v1/domain_blocks", %{"domain" => "dogwhistle.zone"})
1637 assert %{} = json_response(conn, 200)
1638 user = User.get_cached_by_ap_id(user.ap_id)
1639 assert User.blocks?(user, other_user)
1643 |> assign(:user, user)
1644 |> delete("/api/v1/domain_blocks", %{"domain" => "dogwhistle.zone"})
1646 assert %{} = json_response(conn, 200)
1647 user = User.get_cached_by_ap_id(user.ap_id)
1648 refute User.blocks?(user, other_user)
1651 test "getting a list of domain blocks", %{conn: conn} do
1652 user = insert(:user)
1654 {:ok, user} = User.block_domain(user, "bad.site")
1655 {:ok, user} = User.block_domain(user, "even.worse.site")
1659 |> assign(:user, user)
1660 |> get("/api/v1/domain_blocks")
1662 domain_blocks = json_response(conn, 200)
1664 assert "bad.site" in domain_blocks
1665 assert "even.worse.site" in domain_blocks
1668 test "unimplemented follow_requests, blocks, domain blocks" do
1669 user = insert(:user)
1671 ["blocks", "domain_blocks", "follow_requests"]
1672 |> Enum.each(fn endpoint ->
1675 |> assign(:user, user)
1676 |> get("/api/v1/#{endpoint}")
1678 assert [] = json_response(conn, 200)
1682 test "account search", %{conn: conn} do
1683 user = insert(:user)
1684 user_two = insert(:user, %{nickname: "shp@shitposter.club"})
1685 user_three = insert(:user, %{nickname: "shp@heldscal.la", name: "I love 2hu"})
1689 |> assign(:user, user)
1690 |> get("/api/v1/accounts/search", %{"q" => "shp"})
1691 |> json_response(200)
1693 result_ids = for result <- results, do: result["acct"]
1695 assert user_two.nickname in result_ids
1696 assert user_three.nickname in result_ids
1700 |> assign(:user, user)
1701 |> get("/api/v1/accounts/search", %{"q" => "2hu"})
1702 |> json_response(200)
1704 result_ids = for result <- results, do: result["acct"]
1706 assert user_three.nickname in result_ids
1709 test "search", %{conn: conn} do
1710 user = insert(:user)
1711 user_two = insert(:user, %{nickname: "shp@shitposter.club"})
1712 user_three = insert(:user, %{nickname: "shp@heldscal.la", name: "I love 2hu"})
1714 {:ok, activity} = CommonAPI.post(user, %{"status" => "This is about 2hu"})
1717 CommonAPI.post(user, %{
1718 "status" => "This is about 2hu, but private",
1719 "visibility" => "private"
1722 {:ok, _} = CommonAPI.post(user_two, %{"status" => "This isn't"})
1726 |> get("/api/v1/search", %{"q" => "2hu"})
1728 assert results = json_response(conn, 200)
1730 [account | _] = results["accounts"]
1731 assert account["id"] == to_string(user_three.id)
1733 assert results["hashtags"] == []
1735 [status] = results["statuses"]
1736 assert status["id"] == to_string(activity.id)
1739 test "search fetches remote statuses", %{conn: conn} do
1743 |> get("/api/v1/search", %{"q" => "https://shitposter.club/notice/2827873"})
1745 assert results = json_response(conn, 200)
1747 [status] = results["statuses"]
1748 assert status["uri"] == "tag:shitposter.club,2017-05-05:noticeId=2827873:objectType=comment"
1752 test "search doesn't show statuses that it shouldn't", %{conn: conn} do
1754 CommonAPI.post(insert(:user), %{
1755 "status" => "This is about 2hu, but private",
1756 "visibility" => "private"
1762 |> get("/api/v1/search", %{"q" => activity.data["object"]["id"]})
1764 assert results = json_response(conn, 200)
1766 [] = results["statuses"]
1770 test "search fetches remote accounts", %{conn: conn} do
1773 |> get("/api/v1/search", %{"q" => "shp@social.heldscal.la", "resolve" => "true"})
1775 assert results = json_response(conn, 200)
1776 [account] = results["accounts"]
1777 assert account["acct"] == "shp@social.heldscal.la"
1780 test "returns the favorites of a user", %{conn: conn} do
1781 user = insert(:user)
1782 other_user = insert(:user)
1784 {:ok, _} = CommonAPI.post(other_user, %{"status" => "bla"})
1785 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "traps are happy"})
1787 {:ok, _, _} = CommonAPI.favorite(activity.id, user)
1791 |> assign(:user, user)
1792 |> get("/api/v1/favourites")
1794 assert [status] = json_response(first_conn, 200)
1795 assert status["id"] == to_string(activity.id)
1797 assert [{"link", _link_header}] =
1798 Enum.filter(first_conn.resp_headers, fn element -> match?({"link", _}, element) end)
1800 # Honours query params
1801 {:ok, second_activity} =
1802 CommonAPI.post(other_user, %{
1804 "Trees Are Never Sad Look At Them Every Once In Awhile They're Quite Beautiful."
1807 {:ok, _, _} = CommonAPI.favorite(second_activity.id, user)
1809 last_like = status["id"]
1813 |> assign(:user, user)
1814 |> get("/api/v1/favourites?since_id=#{last_like}")
1816 assert [second_status] = json_response(second_conn, 200)
1817 assert second_status["id"] == to_string(second_activity.id)
1821 |> assign(:user, user)
1822 |> get("/api/v1/favourites?limit=0")
1824 assert [] = json_response(third_conn, 200)
1827 describe "updating credentials" do
1828 test "updates the user's bio", %{conn: conn} do
1829 user = insert(:user)
1830 user2 = insert(:user)
1834 |> assign(:user, user)
1835 |> patch("/api/v1/accounts/update_credentials", %{
1836 "note" => "I drink #cofe with @#{user2.nickname}"
1839 assert user = json_response(conn, 200)
1841 assert user["note"] ==
1842 ~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=") <>
1844 ~s(" class="u-url mention" href=") <>
1845 user2.ap_id <> ~s(">@<span>) <> user2.nickname <> ~s(</span></a></span>)
1848 test "updates the user's locking status", %{conn: conn} do
1849 user = insert(:user)
1853 |> assign(:user, user)
1854 |> patch("/api/v1/accounts/update_credentials", %{locked: "true"})
1856 assert user = json_response(conn, 200)
1857 assert user["locked"] == true
1860 test "updates the user's name", %{conn: conn} do
1861 user = insert(:user)
1865 |> assign(:user, user)
1866 |> patch("/api/v1/accounts/update_credentials", %{"display_name" => "markorepairs"})
1868 assert user = json_response(conn, 200)
1869 assert user["display_name"] == "markorepairs"
1872 test "updates the user's avatar", %{conn: conn} do
1873 user = insert(:user)
1875 new_avatar = %Plug.Upload{
1876 content_type: "image/jpg",
1877 path: Path.absname("test/fixtures/image.jpg"),
1878 filename: "an_image.jpg"
1883 |> assign(:user, user)
1884 |> patch("/api/v1/accounts/update_credentials", %{"avatar" => new_avatar})
1886 assert user_response = json_response(conn, 200)
1887 assert user_response["avatar"] != User.avatar_url(user)
1890 test "updates the user's banner", %{conn: conn} do
1891 user = insert(:user)
1893 new_header = %Plug.Upload{
1894 content_type: "image/jpg",
1895 path: Path.absname("test/fixtures/image.jpg"),
1896 filename: "an_image.jpg"
1901 |> assign(:user, user)
1902 |> patch("/api/v1/accounts/update_credentials", %{"header" => new_header})
1904 assert user_response = json_response(conn, 200)
1905 assert user_response["header"] != User.banner_url(user)
1908 test "requires 'write' permission", %{conn: conn} do
1909 token1 = insert(:oauth_token, scopes: ["read"])
1910 token2 = insert(:oauth_token, scopes: ["write", "follow"])
1912 for token <- [token1, token2] do
1915 |> put_req_header("authorization", "Bearer #{token.token}")
1916 |> patch("/api/v1/accounts/update_credentials", %{})
1918 if token == token1 do
1919 assert %{"error" => "Insufficient permissions: write."} == json_response(conn, 403)
1921 assert json_response(conn, 200)
1927 test "get instance information", %{conn: conn} do
1928 conn = get(conn, "/api/v1/instance")
1929 assert result = json_response(conn, 200)
1931 # Note: not checking for "max_toot_chars" since it's optional
1939 "streaming_api" => _
1944 "registrations" => _
1948 test "get instance stats", %{conn: conn} do
1949 user = insert(:user, %{local: true})
1951 user2 = insert(:user, %{local: true})
1952 {:ok, _user2} = User.deactivate(user2, !user2.info.deactivated)
1954 insert(:user, %{local: false, nickname: "u@peer1.com"})
1955 insert(:user, %{local: false, nickname: "u@peer2.com"})
1957 {:ok, _} = TwitterAPI.create_status(user, %{"status" => "cofe"})
1959 # Stats should count users with missing or nil `info.deactivated` value
1960 user = User.get_by_id(user.id)
1961 info_change = Changeset.change(user.info, %{deactivated: nil})
1965 |> Changeset.change()
1966 |> Changeset.put_embed(:info, info_change)
1967 |> User.update_and_set_cache()
1969 Pleroma.Stats.update_stats()
1971 conn = get(conn, "/api/v1/instance")
1973 assert result = json_response(conn, 200)
1975 stats = result["stats"]
1978 assert stats["user_count"] == 1
1979 assert stats["status_count"] == 1
1980 assert stats["domain_count"] == 2
1983 test "get peers", %{conn: conn} do
1984 insert(:user, %{local: false, nickname: "u@peer1.com"})
1985 insert(:user, %{local: false, nickname: "u@peer2.com"})
1987 Pleroma.Stats.update_stats()
1989 conn = get(conn, "/api/v1/instance/peers")
1991 assert result = json_response(conn, 200)
1993 assert ["peer1.com", "peer2.com"] == Enum.sort(result)
1996 test "put settings", %{conn: conn} do
1997 user = insert(:user)
2001 |> assign(:user, user)
2002 |> put("/api/web/settings", %{"data" => %{"programming" => "socks"}})
2004 assert _result = json_response(conn, 200)
2006 user = User.get_cached_by_ap_id(user.ap_id)
2007 assert user.info.settings == %{"programming" => "socks"}
2010 describe "pinned statuses" do
2012 Pleroma.Config.put([:instance, :max_pinned_statuses], 1)
2014 user = insert(:user)
2015 {:ok, activity} = CommonAPI.post(user, %{"status" => "HI!!!"})
2017 [user: user, activity: activity]
2020 test "returns pinned statuses", %{conn: conn, user: user, activity: activity} do
2021 {:ok, _} = CommonAPI.pin(activity.id, user)
2025 |> assign(:user, user)
2026 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
2027 |> json_response(200)
2029 id_str = to_string(activity.id)
2031 assert [%{"id" => ^id_str, "pinned" => true}] = result
2034 test "pin status", %{conn: conn, user: user, activity: activity} do
2035 id_str = to_string(activity.id)
2037 assert %{"id" => ^id_str, "pinned" => true} =
2039 |> assign(:user, user)
2040 |> post("/api/v1/statuses/#{activity.id}/pin")
2041 |> json_response(200)
2043 assert [%{"id" => ^id_str, "pinned" => true}] =
2045 |> assign(:user, user)
2046 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
2047 |> json_response(200)
2050 test "unpin status", %{conn: conn, user: user, activity: activity} do
2051 {:ok, _} = CommonAPI.pin(activity.id, user)
2053 id_str = to_string(activity.id)
2054 user = refresh_record(user)
2056 assert %{"id" => ^id_str, "pinned" => false} =
2058 |> assign(:user, user)
2059 |> post("/api/v1/statuses/#{activity.id}/unpin")
2060 |> json_response(200)
2064 |> assign(:user, user)
2065 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
2066 |> json_response(200)
2069 test "max pinned statuses", %{conn: conn, user: user, activity: activity_one} do
2070 {:ok, activity_two} = CommonAPI.post(user, %{"status" => "HI!!!"})
2072 id_str_one = to_string(activity_one.id)
2074 assert %{"id" => ^id_str_one, "pinned" => true} =
2076 |> assign(:user, user)
2077 |> post("/api/v1/statuses/#{id_str_one}/pin")
2078 |> json_response(200)
2080 user = refresh_record(user)
2082 assert %{"error" => "You have already pinned the maximum number of statuses"} =
2084 |> assign(:user, user)
2085 |> post("/api/v1/statuses/#{activity_two.id}/pin")
2086 |> json_response(400)
2089 test "Status rich-media Card", %{conn: conn, user: user} do
2090 Pleroma.Config.put([:rich_media, :enabled], true)
2091 {:ok, activity} = CommonAPI.post(user, %{"status" => "http://example.com/ogp"})
2095 |> get("/api/v1/statuses/#{activity.id}/card")
2096 |> json_response(200)
2098 assert response == %{
2099 "image" => "http://ia.media-imdb.com/images/rock.jpg",
2100 "provider_name" => "www.imdb.com",
2101 "provider_url" => "http://www.imdb.com",
2102 "title" => "The Rock",
2104 "url" => "http://www.imdb.com/title/tt0117500/",
2105 "description" => nil,
2108 "image" => "http://ia.media-imdb.com/images/rock.jpg",
2109 "title" => "The Rock",
2110 "type" => "video.movie",
2111 "url" => "http://www.imdb.com/title/tt0117500/"
2116 # works with private posts
2118 CommonAPI.post(user, %{"status" => "http://example.com/ogp", "visibility" => "direct"})
2122 |> assign(:user, user)
2123 |> get("/api/v1/statuses/#{activity.id}/card")
2124 |> json_response(200)
2126 assert response_two == response
2128 Pleroma.Config.put([:rich_media, :enabled], false)
2133 user = insert(:user)
2134 for_user = insert(:user)
2137 CommonAPI.post(user, %{
2138 "status" => "heweoo?"
2142 CommonAPI.post(user, %{
2143 "status" => "heweoo!"
2148 |> assign(:user, for_user)
2149 |> post("/api/v1/statuses/#{activity1.id}/bookmark")
2151 assert json_response(response1, 200)["bookmarked"] == true
2155 |> assign(:user, for_user)
2156 |> post("/api/v1/statuses/#{activity2.id}/bookmark")
2158 assert json_response(response2, 200)["bookmarked"] == true
2162 |> assign(:user, for_user)
2163 |> get("/api/v1/bookmarks")
2165 assert [json_response(response2, 200), json_response(response1, 200)] ==
2166 json_response(bookmarks, 200)
2170 |> assign(:user, for_user)
2171 |> post("/api/v1/statuses/#{activity1.id}/unbookmark")
2173 assert json_response(response1, 200)["bookmarked"] == false
2177 |> assign(:user, for_user)
2178 |> get("/api/v1/bookmarks")
2180 assert [json_response(response2, 200)] == json_response(bookmarks, 200)
2183 describe "conversation muting" do
2185 user = insert(:user)
2186 {:ok, activity} = CommonAPI.post(user, %{"status" => "HIE"})
2188 [user: user, activity: activity]
2191 test "mute conversation", %{conn: conn, user: user, activity: activity} do
2192 id_str = to_string(activity.id)
2194 assert %{"id" => ^id_str, "muted" => true} =
2196 |> assign(:user, user)
2197 |> post("/api/v1/statuses/#{activity.id}/mute")
2198 |> json_response(200)
2201 test "unmute conversation", %{conn: conn, user: user, activity: activity} do
2202 {:ok, _} = CommonAPI.add_mute(user, activity)
2204 id_str = to_string(activity.id)
2205 user = refresh_record(user)
2207 assert %{"id" => ^id_str, "muted" => false} =
2209 |> assign(:user, user)
2210 |> post("/api/v1/statuses/#{activity.id}/unmute")
2211 |> json_response(200)
2215 test "flavours switching (Pleroma Extension)", %{conn: conn} do
2216 user = insert(:user)
2220 |> assign(:user, user)
2221 |> get("/api/v1/pleroma/flavour")
2223 assert "glitch" == json_response(get_old_flavour, 200)
2227 |> assign(:user, user)
2228 |> post("/api/v1/pleroma/flavour/vanilla")
2230 assert "vanilla" == json_response(set_flavour, 200)
2234 |> assign(:user, user)
2235 |> post("/api/v1/pleroma/flavour/vanilla")
2237 assert json_response(set_flavour, 200) == json_response(get_new_flavour, 200)
2240 describe "reports" do
2242 reporter = insert(:user)
2243 target_user = insert(:user)
2245 {:ok, activity} = CommonAPI.post(target_user, %{"status" => "foobar"})
2247 [reporter: reporter, target_user: target_user, activity: activity]
2250 test "submit a basic report", %{conn: conn, reporter: reporter, target_user: target_user} do
2251 assert %{"action_taken" => false, "id" => _} =
2253 |> assign(:user, reporter)
2254 |> post("/api/v1/reports", %{"account_id" => target_user.id})
2255 |> json_response(200)
2258 test "submit a report with statuses and comment", %{
2261 target_user: target_user,
2264 assert %{"action_taken" => false, "id" => _} =
2266 |> assign(:user, reporter)
2267 |> post("/api/v1/reports", %{
2268 "account_id" => target_user.id,
2269 "status_ids" => [activity.id],
2270 "comment" => "bad status!"
2272 |> json_response(200)
2275 test "account_id is required", %{
2280 assert %{"error" => "Valid `account_id` required"} =
2282 |> assign(:user, reporter)
2283 |> post("/api/v1/reports", %{"status_ids" => [activity.id]})
2284 |> json_response(400)
2287 test "comment must be up to the size specified in the config", %{
2290 target_user: target_user
2292 max_size = Pleroma.Config.get([:instance, :max_report_comment_size], 1000)
2293 comment = String.pad_trailing("a", max_size + 1, "a")
2295 error = %{"error" => "Comment must be up to #{max_size} characters"}
2299 |> assign(:user, reporter)
2300 |> post("/api/v1/reports", %{"account_id" => target_user.id, "comment" => comment})
2301 |> json_response(400)
2305 describe "link headers" do
2306 test "preserves parameters in link headers", %{conn: conn} do
2307 user = insert(:user)
2308 other_user = insert(:user)
2311 CommonAPI.post(other_user, %{
2312 "status" => "hi @#{user.nickname}",
2313 "visibility" => "public"
2317 CommonAPI.post(other_user, %{
2318 "status" => "hi @#{user.nickname}",
2319 "visibility" => "public"
2322 notification1 = Repo.get_by(Notification, activity_id: activity1.id)
2323 notification2 = Repo.get_by(Notification, activity_id: activity2.id)
2327 |> assign(:user, user)
2328 |> get("/api/v1/notifications", %{media_only: true})
2330 assert [link_header] = get_resp_header(conn, "link")
2331 assert link_header =~ ~r/media_only=true/
2332 assert link_header =~ ~r/since_id=#{notification2.id}/
2333 assert link_header =~ ~r/max_id=#{notification1.id}/
2337 test "accounts fetches correct account for nicknames beginning with numbers", %{conn: conn} do
2338 # Need to set an old-style integer ID to reproduce the problem
2339 # (these are no longer assigned to new accounts but were preserved
2340 # for existing accounts during the migration to flakeIDs)
2341 user_one = insert(:user, %{id: 1212})
2342 user_two = insert(:user, %{nickname: "#{user_one.id}garbage"})
2346 |> get("/api/v1/accounts/#{user_one.id}")
2350 |> get("/api/v1/accounts/#{user_two.nickname}")
2354 |> get("/api/v1/accounts/#{user_two.id}")
2356 acc_one = json_response(resp_one, 200)
2357 acc_two = json_response(resp_two, 200)
2358 acc_three = json_response(resp_three, 200)
2359 refute acc_one == acc_two
2360 assert acc_two == acc_three