Merge branch 'pleroma-conversations' into 'develop'
[akkoma] / test / web / mastodon_api / mastodon_api_controller_test.exs
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
5 defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
6 use Pleroma.Web.ConnCase
7
8 alias Ecto.Changeset
9 alias Pleroma.Activity
10 alias Pleroma.Config
11 alias Pleroma.Notification
12 alias Pleroma.Object
13 alias Pleroma.Repo
14 alias Pleroma.ScheduledActivity
15 alias Pleroma.User
16 alias Pleroma.Web.ActivityPub.ActivityPub
17 alias Pleroma.Web.CommonAPI
18 alias Pleroma.Web.MastodonAPI.FilterView
19 alias Pleroma.Web.OAuth.App
20 alias Pleroma.Web.OAuth.Token
21 alias Pleroma.Web.OStatus
22 alias Pleroma.Web.Push
23 alias Pleroma.Web.TwitterAPI.TwitterAPI
24 import Pleroma.Factory
25 import ExUnit.CaptureLog
26 import Tesla.Mock
27 import Swoosh.TestAssertions
28
29 @image "data:image/gif;base64,R0lGODlhEAAQAMQAAORHHOVSKudfOulrSOp3WOyDZu6QdvCchPGolfO0o/XBs/fNwfjZ0frl3/zy7////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkAABAALAAAAAAQABAAAAVVICSOZGlCQAosJ6mu7fiyZeKqNKToQGDsM8hBADgUXoGAiqhSvp5QAnQKGIgUhwFUYLCVDFCrKUE1lBavAViFIDlTImbKC5Gm2hB0SlBCBMQiB0UjIQA7"
30
31 setup do
32 mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
33 :ok
34 end
35
36 test "the home timeline", %{conn: conn} do
37 user = insert(:user)
38 following = insert(:user)
39
40 {:ok, _activity} = CommonAPI.post(following, %{"status" => "test"})
41
42 conn =
43 conn
44 |> assign(:user, user)
45 |> get("/api/v1/timelines/home")
46
47 assert Enum.empty?(json_response(conn, 200))
48
49 {:ok, user} = User.follow(user, following)
50
51 conn =
52 build_conn()
53 |> assign(:user, user)
54 |> get("/api/v1/timelines/home")
55
56 assert [%{"content" => "test"}] = json_response(conn, 200)
57 end
58
59 test "the public timeline", %{conn: conn} do
60 following = insert(:user)
61
62 capture_log(fn ->
63 {:ok, _activity} = CommonAPI.post(following, %{"status" => "test"})
64
65 {:ok, [_activity]} =
66 OStatus.fetch_activity_from_url("https://shitposter.club/notice/2827873")
67
68 conn =
69 conn
70 |> get("/api/v1/timelines/public", %{"local" => "False"})
71
72 assert length(json_response(conn, 200)) == 2
73
74 conn =
75 build_conn()
76 |> get("/api/v1/timelines/public", %{"local" => "True"})
77
78 assert [%{"content" => "test"}] = json_response(conn, 200)
79
80 conn =
81 build_conn()
82 |> get("/api/v1/timelines/public", %{"local" => "1"})
83
84 assert [%{"content" => "test"}] = json_response(conn, 200)
85 end)
86 end
87
88 test "the public timeline when public is set to false", %{conn: conn} do
89 public = Config.get([:instance, :public])
90 Config.put([:instance, :public], false)
91
92 on_exit(fn ->
93 Config.put([:instance, :public], public)
94 end)
95
96 assert conn
97 |> get("/api/v1/timelines/public", %{"local" => "False"})
98 |> json_response(403) == %{"error" => "This resource requires authentication."}
99 end
100
101 describe "posting statuses" do
102 setup do
103 user = insert(:user)
104
105 conn =
106 build_conn()
107 |> assign(:user, user)
108
109 [conn: conn]
110 end
111
112 test "posting a status", %{conn: conn} do
113 idempotency_key = "Pikachu rocks!"
114
115 conn_one =
116 conn
117 |> put_req_header("idempotency-key", idempotency_key)
118 |> post("/api/v1/statuses", %{
119 "status" => "cofe",
120 "spoiler_text" => "2hu",
121 "sensitive" => "false"
122 })
123
124 {:ok, ttl} = Cachex.ttl(:idempotency_cache, idempotency_key)
125 # Six hours
126 assert ttl > :timer.seconds(6 * 60 * 60 - 1)
127
128 assert %{"content" => "cofe", "id" => id, "spoiler_text" => "2hu", "sensitive" => false} =
129 json_response(conn_one, 200)
130
131 assert Activity.get_by_id(id)
132
133 conn_two =
134 conn
135 |> put_req_header("idempotency-key", idempotency_key)
136 |> post("/api/v1/statuses", %{
137 "status" => "cofe",
138 "spoiler_text" => "2hu",
139 "sensitive" => "false"
140 })
141
142 assert %{"id" => second_id} = json_response(conn_two, 200)
143 assert id == second_id
144
145 conn_three =
146 conn
147 |> post("/api/v1/statuses", %{
148 "status" => "cofe",
149 "spoiler_text" => "2hu",
150 "sensitive" => "false"
151 })
152
153 assert %{"id" => third_id} = json_response(conn_three, 200)
154 refute id == third_id
155 end
156
157 test "replying to a status", %{conn: conn} do
158 user = insert(:user)
159 {:ok, replied_to} = CommonAPI.post(user, %{"status" => "cofe"})
160
161 conn =
162 conn
163 |> post("/api/v1/statuses", %{"status" => "xD", "in_reply_to_id" => replied_to.id})
164
165 assert %{"content" => "xD", "id" => id} = json_response(conn, 200)
166
167 activity = Activity.get_by_id(id)
168
169 assert activity.data["context"] == replied_to.data["context"]
170 assert Activity.get_in_reply_to_activity(activity).id == replied_to.id
171 end
172
173 test "replying to a direct message with visibility other than direct", %{conn: conn} do
174 user = insert(:user)
175 {:ok, replied_to} = CommonAPI.post(user, %{"status" => "suya..", "visibility" => "direct"})
176
177 Enum.each(["public", "private", "unlisted"], fn visibility ->
178 conn =
179 conn
180 |> post("/api/v1/statuses", %{
181 "status" => "@#{user.nickname} hey",
182 "in_reply_to_id" => replied_to.id,
183 "visibility" => visibility
184 })
185
186 assert json_response(conn, 422) == %{"error" => "The message visibility must be direct"}
187 end)
188 end
189
190 test "posting a status with an invalid in_reply_to_id", %{conn: conn} do
191 conn =
192 conn
193 |> post("/api/v1/statuses", %{"status" => "xD", "in_reply_to_id" => ""})
194
195 assert %{"content" => "xD", "id" => id} = json_response(conn, 200)
196 assert Activity.get_by_id(id)
197 end
198
199 test "posting a sensitive status", %{conn: conn} do
200 conn =
201 conn
202 |> post("/api/v1/statuses", %{"status" => "cofe", "sensitive" => true})
203
204 assert %{"content" => "cofe", "id" => id, "sensitive" => true} = json_response(conn, 200)
205 assert Activity.get_by_id(id)
206 end
207
208 test "posting a fake status", %{conn: conn} do
209 real_conn =
210 conn
211 |> post("/api/v1/statuses", %{
212 "status" =>
213 "\"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"
214 })
215
216 real_status = json_response(real_conn, 200)
217
218 assert real_status
219 assert Object.get_by_ap_id(real_status["uri"])
220
221 real_status =
222 real_status
223 |> Map.put("id", nil)
224 |> Map.put("url", nil)
225 |> Map.put("uri", nil)
226 |> Map.put("created_at", nil)
227 |> Kernel.put_in(["pleroma", "conversation_id"], nil)
228
229 fake_conn =
230 conn
231 |> post("/api/v1/statuses", %{
232 "status" =>
233 "\"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",
234 "preview" => true
235 })
236
237 fake_status = json_response(fake_conn, 200)
238
239 assert fake_status
240 refute Object.get_by_ap_id(fake_status["uri"])
241
242 fake_status =
243 fake_status
244 |> Map.put("id", nil)
245 |> Map.put("url", nil)
246 |> Map.put("uri", nil)
247 |> Map.put("created_at", nil)
248 |> Kernel.put_in(["pleroma", "conversation_id"], nil)
249
250 assert real_status == fake_status
251 end
252
253 test "posting a status with OGP link preview", %{conn: conn} do
254 Config.put([:rich_media, :enabled], true)
255
256 conn =
257 conn
258 |> post("/api/v1/statuses", %{
259 "status" => "https://example.com/ogp"
260 })
261
262 assert %{"id" => id, "card" => %{"title" => "The Rock"}} = json_response(conn, 200)
263 assert Activity.get_by_id(id)
264 Config.put([:rich_media, :enabled], false)
265 end
266
267 test "posting a direct status", %{conn: conn} do
268 user2 = insert(:user)
269 content = "direct cofe @#{user2.nickname}"
270
271 conn =
272 conn
273 |> post("api/v1/statuses", %{"status" => content, "visibility" => "direct"})
274
275 assert %{"id" => id, "visibility" => "direct"} = json_response(conn, 200)
276 assert activity = Activity.get_by_id(id)
277 assert activity.recipients == [user2.ap_id, conn.assigns[:user].ap_id]
278 assert activity.data["to"] == [user2.ap_id]
279 assert activity.data["cc"] == []
280 end
281 end
282
283 describe "posting polls" do
284 test "posting a poll", %{conn: conn} do
285 user = insert(:user)
286 time = NaiveDateTime.utc_now()
287
288 conn =
289 conn
290 |> assign(:user, user)
291 |> post("/api/v1/statuses", %{
292 "status" => "Who is the #bestgrill?",
293 "poll" => %{"options" => ["Rei", "Asuka", "Misato"], "expires_in" => 420}
294 })
295
296 response = json_response(conn, 200)
297
298 assert Enum.all?(response["poll"]["options"], fn %{"title" => title} ->
299 title in ["Rei", "Asuka", "Misato"]
300 end)
301
302 assert NaiveDateTime.diff(NaiveDateTime.from_iso8601!(response["poll"]["expires_at"]), time) in 420..430
303 refute response["poll"]["expred"]
304 end
305
306 test "option limit is enforced", %{conn: conn} do
307 user = insert(:user)
308 limit = Config.get([:instance, :poll_limits, :max_options])
309
310 conn =
311 conn
312 |> assign(:user, user)
313 |> post("/api/v1/statuses", %{
314 "status" => "desu~",
315 "poll" => %{"options" => Enum.map(0..limit, fn _ -> "desu" end), "expires_in" => 1}
316 })
317
318 %{"error" => error} = json_response(conn, 422)
319 assert error == "Poll can't contain more than #{limit} options"
320 end
321
322 test "option character limit is enforced", %{conn: conn} do
323 user = insert(:user)
324 limit = Config.get([:instance, :poll_limits, :max_option_chars])
325
326 conn =
327 conn
328 |> assign(:user, user)
329 |> post("/api/v1/statuses", %{
330 "status" => "...",
331 "poll" => %{
332 "options" => [Enum.reduce(0..limit, "", fn _, acc -> acc <> "." end)],
333 "expires_in" => 1
334 }
335 })
336
337 %{"error" => error} = json_response(conn, 422)
338 assert error == "Poll options cannot be longer than #{limit} characters each"
339 end
340
341 test "minimal date limit is enforced", %{conn: conn} do
342 user = insert(:user)
343 limit = Config.get([:instance, :poll_limits, :min_expiration])
344
345 conn =
346 conn
347 |> assign(:user, user)
348 |> post("/api/v1/statuses", %{
349 "status" => "imagine arbitrary limits",
350 "poll" => %{
351 "options" => ["this post was made by pleroma gang"],
352 "expires_in" => limit - 1
353 }
354 })
355
356 %{"error" => error} = json_response(conn, 422)
357 assert error == "Expiration date is too soon"
358 end
359
360 test "maximum date limit is enforced", %{conn: conn} do
361 user = insert(:user)
362 limit = Config.get([:instance, :poll_limits, :max_expiration])
363
364 conn =
365 conn
366 |> assign(:user, user)
367 |> post("/api/v1/statuses", %{
368 "status" => "imagine arbitrary limits",
369 "poll" => %{
370 "options" => ["this post was made by pleroma gang"],
371 "expires_in" => limit + 1
372 }
373 })
374
375 %{"error" => error} = json_response(conn, 422)
376 assert error == "Expiration date is too far in the future"
377 end
378 end
379
380 test "direct timeline", %{conn: conn} do
381 user_one = insert(:user)
382 user_two = insert(:user)
383
384 {:ok, user_two} = User.follow(user_two, user_one)
385
386 {:ok, direct} =
387 CommonAPI.post(user_one, %{
388 "status" => "Hi @#{user_two.nickname}!",
389 "visibility" => "direct"
390 })
391
392 {:ok, _follower_only} =
393 CommonAPI.post(user_one, %{
394 "status" => "Hi @#{user_two.nickname}!",
395 "visibility" => "private"
396 })
397
398 # Only direct should be visible here
399 res_conn =
400 conn
401 |> assign(:user, user_two)
402 |> get("api/v1/timelines/direct")
403
404 [status] = json_response(res_conn, 200)
405
406 assert %{"visibility" => "direct"} = status
407 assert status["url"] != direct.data["id"]
408
409 # User should be able to see his own direct message
410 res_conn =
411 build_conn()
412 |> assign(:user, user_one)
413 |> get("api/v1/timelines/direct")
414
415 [status] = json_response(res_conn, 200)
416
417 assert %{"visibility" => "direct"} = status
418
419 # Both should be visible here
420 res_conn =
421 conn
422 |> assign(:user, user_two)
423 |> get("api/v1/timelines/home")
424
425 [_s1, _s2] = json_response(res_conn, 200)
426
427 # Test pagination
428 Enum.each(1..20, fn _ ->
429 {:ok, _} =
430 CommonAPI.post(user_one, %{
431 "status" => "Hi @#{user_two.nickname}!",
432 "visibility" => "direct"
433 })
434 end)
435
436 res_conn =
437 conn
438 |> assign(:user, user_two)
439 |> get("api/v1/timelines/direct")
440
441 statuses = json_response(res_conn, 200)
442 assert length(statuses) == 20
443
444 res_conn =
445 conn
446 |> assign(:user, user_two)
447 |> get("api/v1/timelines/direct", %{max_id: List.last(statuses)["id"]})
448
449 [status] = json_response(res_conn, 200)
450
451 assert status["url"] != direct.data["id"]
452 end
453
454 test "Conversations", %{conn: conn} do
455 user_one = insert(:user)
456 user_two = insert(:user)
457 user_three = insert(:user)
458
459 {:ok, user_two} = User.follow(user_two, user_one)
460
461 {:ok, direct} =
462 CommonAPI.post(user_one, %{
463 "status" => "Hi @#{user_two.nickname}, @#{user_three.nickname}!",
464 "visibility" => "direct"
465 })
466
467 {:ok, _follower_only} =
468 CommonAPI.post(user_one, %{
469 "status" => "Hi @#{user_two.nickname}!",
470 "visibility" => "private"
471 })
472
473 res_conn =
474 conn
475 |> assign(:user, user_one)
476 |> get("/api/v1/conversations")
477
478 assert response = json_response(res_conn, 200)
479
480 assert [
481 %{
482 "id" => res_id,
483 "accounts" => res_accounts,
484 "last_status" => res_last_status,
485 "unread" => unread
486 }
487 ] = response
488
489 account_ids = Enum.map(res_accounts, & &1["id"])
490 assert length(res_accounts) == 2
491 assert user_two.id in account_ids
492 assert user_three.id in account_ids
493 assert is_binary(res_id)
494 assert unread == true
495 assert res_last_status["id"] == direct.id
496
497 # Apparently undocumented API endpoint
498 res_conn =
499 conn
500 |> assign(:user, user_one)
501 |> post("/api/v1/conversations/#{res_id}/read")
502
503 assert response = json_response(res_conn, 200)
504 assert length(response["accounts"]) == 2
505 assert response["last_status"]["id"] == direct.id
506 assert response["unread"] == false
507
508 # (vanilla) Mastodon frontend behaviour
509 res_conn =
510 conn
511 |> assign(:user, user_one)
512 |> get("/api/v1/statuses/#{res_last_status["id"]}/context")
513
514 assert %{"ancestors" => [], "descendants" => []} == json_response(res_conn, 200)
515 end
516
517 test "doesn't include DMs from blocked users", %{conn: conn} do
518 blocker = insert(:user)
519 blocked = insert(:user)
520 user = insert(:user)
521 {:ok, blocker} = User.block(blocker, blocked)
522
523 {:ok, _blocked_direct} =
524 CommonAPI.post(blocked, %{
525 "status" => "Hi @#{blocker.nickname}!",
526 "visibility" => "direct"
527 })
528
529 {:ok, direct} =
530 CommonAPI.post(user, %{
531 "status" => "Hi @#{blocker.nickname}!",
532 "visibility" => "direct"
533 })
534
535 res_conn =
536 conn
537 |> assign(:user, user)
538 |> get("api/v1/timelines/direct")
539
540 [status] = json_response(res_conn, 200)
541 assert status["id"] == direct.id
542 end
543
544 test "verify_credentials", %{conn: conn} do
545 user = insert(:user)
546
547 conn =
548 conn
549 |> assign(:user, user)
550 |> get("/api/v1/accounts/verify_credentials")
551
552 response = json_response(conn, 200)
553
554 assert %{"id" => id, "source" => %{"privacy" => "public"}} = response
555 assert response["pleroma"]["chat_token"]
556 assert id == to_string(user.id)
557 end
558
559 test "verify_credentials default scope unlisted", %{conn: conn} do
560 user = insert(:user, %{info: %User.Info{default_scope: "unlisted"}})
561
562 conn =
563 conn
564 |> assign(:user, user)
565 |> get("/api/v1/accounts/verify_credentials")
566
567 assert %{"id" => id, "source" => %{"privacy" => "unlisted"}} = json_response(conn, 200)
568 assert id == to_string(user.id)
569 end
570
571 test "apps/verify_credentials", %{conn: conn} do
572 token = insert(:oauth_token)
573
574 conn =
575 conn
576 |> assign(:user, token.user)
577 |> assign(:token, token)
578 |> get("/api/v1/apps/verify_credentials")
579
580 app = Repo.preload(token, :app).app
581
582 expected = %{
583 "name" => app.client_name,
584 "website" => app.website,
585 "vapid_key" => Push.vapid_config() |> Keyword.get(:public_key)
586 }
587
588 assert expected == json_response(conn, 200)
589 end
590
591 test "user avatar can be set", %{conn: conn} do
592 user = insert(:user)
593 avatar_image = File.read!("test/fixtures/avatar_data_uri")
594
595 conn =
596 conn
597 |> assign(:user, user)
598 |> patch("/api/v1/pleroma/accounts/update_avatar", %{img: avatar_image})
599
600 user = refresh_record(user)
601
602 assert %{
603 "name" => _,
604 "type" => _,
605 "url" => [
606 %{
607 "href" => _,
608 "mediaType" => _,
609 "type" => _
610 }
611 ]
612 } = user.avatar
613
614 assert %{"url" => _} = json_response(conn, 200)
615 end
616
617 test "user avatar can be reset", %{conn: conn} do
618 user = insert(:user)
619
620 conn =
621 conn
622 |> assign(:user, user)
623 |> patch("/api/v1/pleroma/accounts/update_avatar", %{img: ""})
624
625 user = User.get_cached_by_id(user.id)
626
627 assert user.avatar == nil
628
629 assert %{"url" => nil} = json_response(conn, 200)
630 end
631
632 test "can set profile banner", %{conn: conn} do
633 user = insert(:user)
634
635 conn =
636 conn
637 |> assign(:user, user)
638 |> patch("/api/v1/pleroma/accounts/update_banner", %{"banner" => @image})
639
640 user = refresh_record(user)
641 assert user.info.banner["type"] == "Image"
642
643 assert %{"url" => _} = json_response(conn, 200)
644 end
645
646 test "can reset profile banner", %{conn: conn} do
647 user = insert(:user)
648
649 conn =
650 conn
651 |> assign(:user, user)
652 |> patch("/api/v1/pleroma/accounts/update_banner", %{"banner" => ""})
653
654 user = refresh_record(user)
655 assert user.info.banner == %{}
656
657 assert %{"url" => nil} = json_response(conn, 200)
658 end
659
660 test "background image can be set", %{conn: conn} do
661 user = insert(:user)
662
663 conn =
664 conn
665 |> assign(:user, user)
666 |> patch("/api/v1/pleroma/accounts/update_background", %{"img" => @image})
667
668 user = refresh_record(user)
669 assert user.info.background["type"] == "Image"
670 assert %{"url" => _} = json_response(conn, 200)
671 end
672
673 test "background image can be reset", %{conn: conn} do
674 user = insert(:user)
675
676 conn =
677 conn
678 |> assign(:user, user)
679 |> patch("/api/v1/pleroma/accounts/update_background", %{"img" => ""})
680
681 user = refresh_record(user)
682 assert user.info.background == %{}
683 assert %{"url" => nil} = json_response(conn, 200)
684 end
685
686 test "creates an oauth app", %{conn: conn} do
687 user = insert(:user)
688 app_attrs = build(:oauth_app)
689
690 conn =
691 conn
692 |> assign(:user, user)
693 |> post("/api/v1/apps", %{
694 client_name: app_attrs.client_name,
695 redirect_uris: app_attrs.redirect_uris
696 })
697
698 [app] = Repo.all(App)
699
700 expected = %{
701 "name" => app.client_name,
702 "website" => app.website,
703 "client_id" => app.client_id,
704 "client_secret" => app.client_secret,
705 "id" => app.id |> to_string(),
706 "redirect_uri" => app.redirect_uris,
707 "vapid_key" => Push.vapid_config() |> Keyword.get(:public_key)
708 }
709
710 assert expected == json_response(conn, 200)
711 end
712
713 test "get a status", %{conn: conn} do
714 activity = insert(:note_activity)
715
716 conn =
717 conn
718 |> get("/api/v1/statuses/#{activity.id}")
719
720 assert %{"id" => id} = json_response(conn, 200)
721 assert id == to_string(activity.id)
722 end
723
724 describe "deleting a status" do
725 test "when you created it", %{conn: conn} do
726 activity = insert(:note_activity)
727 author = User.get_cached_by_ap_id(activity.data["actor"])
728
729 conn =
730 conn
731 |> assign(:user, author)
732 |> delete("/api/v1/statuses/#{activity.id}")
733
734 assert %{} = json_response(conn, 200)
735
736 refute Activity.get_by_id(activity.id)
737 end
738
739 test "when you didn't create it", %{conn: conn} do
740 activity = insert(:note_activity)
741 user = insert(:user)
742
743 conn =
744 conn
745 |> assign(:user, user)
746 |> delete("/api/v1/statuses/#{activity.id}")
747
748 assert %{"error" => _} = json_response(conn, 403)
749
750 assert Activity.get_by_id(activity.id) == activity
751 end
752
753 test "when you're an admin or moderator", %{conn: conn} do
754 activity1 = insert(:note_activity)
755 activity2 = insert(:note_activity)
756 admin = insert(:user, info: %{is_admin: true})
757 moderator = insert(:user, info: %{is_moderator: true})
758
759 res_conn =
760 conn
761 |> assign(:user, admin)
762 |> delete("/api/v1/statuses/#{activity1.id}")
763
764 assert %{} = json_response(res_conn, 200)
765
766 res_conn =
767 conn
768 |> assign(:user, moderator)
769 |> delete("/api/v1/statuses/#{activity2.id}")
770
771 assert %{} = json_response(res_conn, 200)
772
773 refute Activity.get_by_id(activity1.id)
774 refute Activity.get_by_id(activity2.id)
775 end
776 end
777
778 describe "filters" do
779 test "creating a filter", %{conn: conn} do
780 user = insert(:user)
781
782 filter = %Pleroma.Filter{
783 phrase: "knights",
784 context: ["home"]
785 }
786
787 conn =
788 conn
789 |> assign(:user, user)
790 |> post("/api/v1/filters", %{"phrase" => filter.phrase, context: filter.context})
791
792 assert response = json_response(conn, 200)
793 assert response["phrase"] == filter.phrase
794 assert response["context"] == filter.context
795 assert response["irreversible"] == false
796 assert response["id"] != nil
797 assert response["id"] != ""
798 end
799
800 test "fetching a list of filters", %{conn: conn} do
801 user = insert(:user)
802
803 query_one = %Pleroma.Filter{
804 user_id: user.id,
805 filter_id: 1,
806 phrase: "knights",
807 context: ["home"]
808 }
809
810 query_two = %Pleroma.Filter{
811 user_id: user.id,
812 filter_id: 2,
813 phrase: "who",
814 context: ["home"]
815 }
816
817 {:ok, filter_one} = Pleroma.Filter.create(query_one)
818 {:ok, filter_two} = Pleroma.Filter.create(query_two)
819
820 response =
821 conn
822 |> assign(:user, user)
823 |> get("/api/v1/filters")
824 |> json_response(200)
825
826 assert response ==
827 render_json(
828 FilterView,
829 "filters.json",
830 filters: [filter_two, filter_one]
831 )
832 end
833
834 test "get a filter", %{conn: conn} do
835 user = insert(:user)
836
837 query = %Pleroma.Filter{
838 user_id: user.id,
839 filter_id: 2,
840 phrase: "knight",
841 context: ["home"]
842 }
843
844 {:ok, filter} = Pleroma.Filter.create(query)
845
846 conn =
847 conn
848 |> assign(:user, user)
849 |> get("/api/v1/filters/#{filter.filter_id}")
850
851 assert _response = json_response(conn, 200)
852 end
853
854 test "update a filter", %{conn: conn} do
855 user = insert(:user)
856
857 query = %Pleroma.Filter{
858 user_id: user.id,
859 filter_id: 2,
860 phrase: "knight",
861 context: ["home"]
862 }
863
864 {:ok, _filter} = Pleroma.Filter.create(query)
865
866 new = %Pleroma.Filter{
867 phrase: "nii",
868 context: ["home"]
869 }
870
871 conn =
872 conn
873 |> assign(:user, user)
874 |> put("/api/v1/filters/#{query.filter_id}", %{
875 phrase: new.phrase,
876 context: new.context
877 })
878
879 assert response = json_response(conn, 200)
880 assert response["phrase"] == new.phrase
881 assert response["context"] == new.context
882 end
883
884 test "delete a filter", %{conn: conn} do
885 user = insert(:user)
886
887 query = %Pleroma.Filter{
888 user_id: user.id,
889 filter_id: 2,
890 phrase: "knight",
891 context: ["home"]
892 }
893
894 {:ok, filter} = Pleroma.Filter.create(query)
895
896 conn =
897 conn
898 |> assign(:user, user)
899 |> delete("/api/v1/filters/#{filter.filter_id}")
900
901 assert response = json_response(conn, 200)
902 assert response == %{}
903 end
904 end
905
906 describe "lists" do
907 test "creating a list", %{conn: conn} do
908 user = insert(:user)
909
910 conn =
911 conn
912 |> assign(:user, user)
913 |> post("/api/v1/lists", %{"title" => "cuties"})
914
915 assert %{"title" => title} = json_response(conn, 200)
916 assert title == "cuties"
917 end
918
919 test "adding users to a list", %{conn: conn} do
920 user = insert(:user)
921 other_user = insert(:user)
922 {:ok, list} = Pleroma.List.create("name", user)
923
924 conn =
925 conn
926 |> assign(:user, user)
927 |> post("/api/v1/lists/#{list.id}/accounts", %{"account_ids" => [other_user.id]})
928
929 assert %{} == json_response(conn, 200)
930 %Pleroma.List{following: following} = Pleroma.List.get(list.id, user)
931 assert following == [other_user.follower_address]
932 end
933
934 test "removing users from a list", %{conn: conn} do
935 user = insert(:user)
936 other_user = insert(:user)
937 third_user = insert(:user)
938 {:ok, list} = Pleroma.List.create("name", user)
939 {:ok, list} = Pleroma.List.follow(list, other_user)
940 {:ok, list} = Pleroma.List.follow(list, third_user)
941
942 conn =
943 conn
944 |> assign(:user, user)
945 |> delete("/api/v1/lists/#{list.id}/accounts", %{"account_ids" => [other_user.id]})
946
947 assert %{} == json_response(conn, 200)
948 %Pleroma.List{following: following} = Pleroma.List.get(list.id, user)
949 assert following == [third_user.follower_address]
950 end
951
952 test "listing users in a list", %{conn: conn} do
953 user = insert(:user)
954 other_user = insert(:user)
955 {:ok, list} = Pleroma.List.create("name", user)
956 {:ok, list} = Pleroma.List.follow(list, other_user)
957
958 conn =
959 conn
960 |> assign(:user, user)
961 |> get("/api/v1/lists/#{list.id}/accounts", %{"account_ids" => [other_user.id]})
962
963 assert [%{"id" => id}] = json_response(conn, 200)
964 assert id == to_string(other_user.id)
965 end
966
967 test "retrieving a list", %{conn: conn} do
968 user = insert(:user)
969 {:ok, list} = Pleroma.List.create("name", user)
970
971 conn =
972 conn
973 |> assign(:user, user)
974 |> get("/api/v1/lists/#{list.id}")
975
976 assert %{"id" => id} = json_response(conn, 200)
977 assert id == to_string(list.id)
978 end
979
980 test "renaming a list", %{conn: conn} do
981 user = insert(:user)
982 {:ok, list} = Pleroma.List.create("name", user)
983
984 conn =
985 conn
986 |> assign(:user, user)
987 |> put("/api/v1/lists/#{list.id}", %{"title" => "newname"})
988
989 assert %{"title" => name} = json_response(conn, 200)
990 assert name == "newname"
991 end
992
993 test "deleting a list", %{conn: conn} do
994 user = insert(:user)
995 {:ok, list} = Pleroma.List.create("name", user)
996
997 conn =
998 conn
999 |> assign(:user, user)
1000 |> delete("/api/v1/lists/#{list.id}")
1001
1002 assert %{} = json_response(conn, 200)
1003 assert is_nil(Repo.get(Pleroma.List, list.id))
1004 end
1005
1006 test "list timeline", %{conn: conn} do
1007 user = insert(:user)
1008 other_user = insert(:user)
1009 {:ok, _activity_one} = CommonAPI.post(user, %{"status" => "Marisa is cute."})
1010 {:ok, activity_two} = CommonAPI.post(other_user, %{"status" => "Marisa is cute."})
1011 {:ok, list} = Pleroma.List.create("name", user)
1012 {:ok, list} = Pleroma.List.follow(list, other_user)
1013
1014 conn =
1015 conn
1016 |> assign(:user, user)
1017 |> get("/api/v1/timelines/list/#{list.id}")
1018
1019 assert [%{"id" => id}] = json_response(conn, 200)
1020
1021 assert id == to_string(activity_two.id)
1022 end
1023
1024 test "list timeline does not leak non-public statuses for unfollowed users", %{conn: conn} do
1025 user = insert(:user)
1026 other_user = insert(:user)
1027 {:ok, activity_one} = CommonAPI.post(other_user, %{"status" => "Marisa is cute."})
1028
1029 {:ok, _activity_two} =
1030 CommonAPI.post(other_user, %{
1031 "status" => "Marisa is cute.",
1032 "visibility" => "private"
1033 })
1034
1035 {:ok, list} = Pleroma.List.create("name", user)
1036 {:ok, list} = Pleroma.List.follow(list, other_user)
1037
1038 conn =
1039 conn
1040 |> assign(:user, user)
1041 |> get("/api/v1/timelines/list/#{list.id}")
1042
1043 assert [%{"id" => id}] = json_response(conn, 200)
1044
1045 assert id == to_string(activity_one.id)
1046 end
1047 end
1048
1049 describe "notifications" do
1050 test "list of notifications", %{conn: conn} do
1051 user = insert(:user)
1052 other_user = insert(:user)
1053
1054 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
1055
1056 {:ok, [_notification]} = Notification.create_notifications(activity)
1057
1058 conn =
1059 conn
1060 |> assign(:user, user)
1061 |> get("/api/v1/notifications")
1062
1063 expected_response =
1064 "hi <span class=\"h-card\"><a data-user=\"#{user.id}\" class=\"u-url mention\" href=\"#{
1065 user.ap_id
1066 }\">@<span>#{user.nickname}</span></a></span>"
1067
1068 assert [%{"status" => %{"content" => response}} | _rest] = json_response(conn, 200)
1069 assert response == expected_response
1070 end
1071
1072 test "getting a single notification", %{conn: conn} do
1073 user = insert(:user)
1074 other_user = insert(:user)
1075
1076 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
1077
1078 {:ok, [notification]} = Notification.create_notifications(activity)
1079
1080 conn =
1081 conn
1082 |> assign(:user, user)
1083 |> get("/api/v1/notifications/#{notification.id}")
1084
1085 expected_response =
1086 "hi <span class=\"h-card\"><a data-user=\"#{user.id}\" class=\"u-url mention\" href=\"#{
1087 user.ap_id
1088 }\">@<span>#{user.nickname}</span></a></span>"
1089
1090 assert %{"status" => %{"content" => response}} = json_response(conn, 200)
1091 assert response == expected_response
1092 end
1093
1094 test "dismissing a single notification", %{conn: conn} do
1095 user = insert(:user)
1096 other_user = insert(:user)
1097
1098 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
1099
1100 {:ok, [notification]} = Notification.create_notifications(activity)
1101
1102 conn =
1103 conn
1104 |> assign(:user, user)
1105 |> post("/api/v1/notifications/dismiss", %{"id" => notification.id})
1106
1107 assert %{} = json_response(conn, 200)
1108 end
1109
1110 test "clearing all notifications", %{conn: conn} do
1111 user = insert(:user)
1112 other_user = insert(:user)
1113
1114 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
1115
1116 {:ok, [_notification]} = Notification.create_notifications(activity)
1117
1118 conn =
1119 conn
1120 |> assign(:user, user)
1121 |> post("/api/v1/notifications/clear")
1122
1123 assert %{} = json_response(conn, 200)
1124
1125 conn =
1126 build_conn()
1127 |> assign(:user, user)
1128 |> get("/api/v1/notifications")
1129
1130 assert all = json_response(conn, 200)
1131 assert all == []
1132 end
1133
1134 test "paginates notifications using min_id, since_id, max_id, and limit", %{conn: conn} do
1135 user = insert(:user)
1136 other_user = insert(:user)
1137
1138 {:ok, activity1} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
1139 {:ok, activity2} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
1140 {:ok, activity3} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
1141 {:ok, activity4} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
1142
1143 notification1_id = Repo.get_by(Notification, activity_id: activity1.id).id |> to_string()
1144 notification2_id = Repo.get_by(Notification, activity_id: activity2.id).id |> to_string()
1145 notification3_id = Repo.get_by(Notification, activity_id: activity3.id).id |> to_string()
1146 notification4_id = Repo.get_by(Notification, activity_id: activity4.id).id |> to_string()
1147
1148 conn =
1149 conn
1150 |> assign(:user, user)
1151
1152 # min_id
1153 conn_res =
1154 conn
1155 |> get("/api/v1/notifications?limit=2&min_id=#{notification1_id}")
1156
1157 result = json_response(conn_res, 200)
1158 assert [%{"id" => ^notification3_id}, %{"id" => ^notification2_id}] = result
1159
1160 # since_id
1161 conn_res =
1162 conn
1163 |> get("/api/v1/notifications?limit=2&since_id=#{notification1_id}")
1164
1165 result = json_response(conn_res, 200)
1166 assert [%{"id" => ^notification4_id}, %{"id" => ^notification3_id}] = result
1167
1168 # max_id
1169 conn_res =
1170 conn
1171 |> get("/api/v1/notifications?limit=2&max_id=#{notification4_id}")
1172
1173 result = json_response(conn_res, 200)
1174 assert [%{"id" => ^notification3_id}, %{"id" => ^notification2_id}] = result
1175 end
1176
1177 test "filters notifications using exclude_types", %{conn: conn} do
1178 user = insert(:user)
1179 other_user = insert(:user)
1180
1181 {:ok, mention_activity} = CommonAPI.post(other_user, %{"status" => "hey @#{user.nickname}"})
1182 {:ok, create_activity} = CommonAPI.post(user, %{"status" => "hey"})
1183 {:ok, favorite_activity, _} = CommonAPI.favorite(create_activity.id, other_user)
1184 {:ok, reblog_activity, _} = CommonAPI.repeat(create_activity.id, other_user)
1185 {:ok, _, _, follow_activity} = CommonAPI.follow(other_user, user)
1186
1187 mention_notification_id =
1188 Repo.get_by(Notification, activity_id: mention_activity.id).id |> to_string()
1189
1190 favorite_notification_id =
1191 Repo.get_by(Notification, activity_id: favorite_activity.id).id |> to_string()
1192
1193 reblog_notification_id =
1194 Repo.get_by(Notification, activity_id: reblog_activity.id).id |> to_string()
1195
1196 follow_notification_id =
1197 Repo.get_by(Notification, activity_id: follow_activity.id).id |> to_string()
1198
1199 conn =
1200 conn
1201 |> assign(:user, user)
1202
1203 conn_res =
1204 get(conn, "/api/v1/notifications", %{exclude_types: ["mention", "favourite", "reblog"]})
1205
1206 assert [%{"id" => ^follow_notification_id}] = json_response(conn_res, 200)
1207
1208 conn_res =
1209 get(conn, "/api/v1/notifications", %{exclude_types: ["favourite", "reblog", "follow"]})
1210
1211 assert [%{"id" => ^mention_notification_id}] = json_response(conn_res, 200)
1212
1213 conn_res =
1214 get(conn, "/api/v1/notifications", %{exclude_types: ["reblog", "follow", "mention"]})
1215
1216 assert [%{"id" => ^favorite_notification_id}] = json_response(conn_res, 200)
1217
1218 conn_res =
1219 get(conn, "/api/v1/notifications", %{exclude_types: ["follow", "mention", "favourite"]})
1220
1221 assert [%{"id" => ^reblog_notification_id}] = json_response(conn_res, 200)
1222 end
1223
1224 test "destroy multiple", %{conn: conn} do
1225 user = insert(:user)
1226 other_user = insert(:user)
1227
1228 {:ok, activity1} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
1229 {:ok, activity2} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
1230 {:ok, activity3} = CommonAPI.post(user, %{"status" => "hi @#{other_user.nickname}"})
1231 {:ok, activity4} = CommonAPI.post(user, %{"status" => "hi @#{other_user.nickname}"})
1232
1233 notification1_id = Repo.get_by(Notification, activity_id: activity1.id).id |> to_string()
1234 notification2_id = Repo.get_by(Notification, activity_id: activity2.id).id |> to_string()
1235 notification3_id = Repo.get_by(Notification, activity_id: activity3.id).id |> to_string()
1236 notification4_id = Repo.get_by(Notification, activity_id: activity4.id).id |> to_string()
1237
1238 conn =
1239 conn
1240 |> assign(:user, user)
1241
1242 conn_res =
1243 conn
1244 |> get("/api/v1/notifications")
1245
1246 result = json_response(conn_res, 200)
1247 assert [%{"id" => ^notification2_id}, %{"id" => ^notification1_id}] = result
1248
1249 conn2 =
1250 conn
1251 |> assign(:user, other_user)
1252
1253 conn_res =
1254 conn2
1255 |> get("/api/v1/notifications")
1256
1257 result = json_response(conn_res, 200)
1258 assert [%{"id" => ^notification4_id}, %{"id" => ^notification3_id}] = result
1259
1260 conn_destroy =
1261 conn
1262 |> delete("/api/v1/notifications/destroy_multiple", %{
1263 "ids" => [notification1_id, notification2_id]
1264 })
1265
1266 assert json_response(conn_destroy, 200) == %{}
1267
1268 conn_res =
1269 conn2
1270 |> get("/api/v1/notifications")
1271
1272 result = json_response(conn_res, 200)
1273 assert [%{"id" => ^notification4_id}, %{"id" => ^notification3_id}] = result
1274 end
1275
1276 test "doesn't see notifications after muting user with notifications", %{conn: conn} do
1277 user = insert(:user)
1278 user2 = insert(:user)
1279
1280 {:ok, _, _, _} = CommonAPI.follow(user, user2)
1281 {:ok, _} = CommonAPI.post(user2, %{"status" => "hey @#{user.nickname}"})
1282
1283 conn = assign(conn, :user, user)
1284
1285 conn = get(conn, "/api/v1/notifications")
1286
1287 assert length(json_response(conn, 200)) == 1
1288
1289 {:ok, user} = User.mute(user, user2)
1290
1291 conn = assign(build_conn(), :user, user)
1292 conn = get(conn, "/api/v1/notifications")
1293
1294 assert json_response(conn, 200) == []
1295 end
1296
1297 test "see notifications after muting user without notifications", %{conn: conn} do
1298 user = insert(:user)
1299 user2 = insert(:user)
1300
1301 {:ok, _, _, _} = CommonAPI.follow(user, user2)
1302 {:ok, _} = CommonAPI.post(user2, %{"status" => "hey @#{user.nickname}"})
1303
1304 conn = assign(conn, :user, user)
1305
1306 conn = get(conn, "/api/v1/notifications")
1307
1308 assert length(json_response(conn, 200)) == 1
1309
1310 {:ok, user} = User.mute(user, user2, false)
1311
1312 conn = assign(build_conn(), :user, user)
1313 conn = get(conn, "/api/v1/notifications")
1314
1315 assert length(json_response(conn, 200)) == 1
1316 end
1317
1318 test "see notifications after muting user with notifications and with_muted parameter", %{
1319 conn: conn
1320 } do
1321 user = insert(:user)
1322 user2 = insert(:user)
1323
1324 {:ok, _, _, _} = CommonAPI.follow(user, user2)
1325 {:ok, _} = CommonAPI.post(user2, %{"status" => "hey @#{user.nickname}"})
1326
1327 conn = assign(conn, :user, user)
1328
1329 conn = get(conn, "/api/v1/notifications")
1330
1331 assert length(json_response(conn, 200)) == 1
1332
1333 {:ok, user} = User.mute(user, user2)
1334
1335 conn = assign(build_conn(), :user, user)
1336 conn = get(conn, "/api/v1/notifications", %{"with_muted" => "true"})
1337
1338 assert length(json_response(conn, 200)) == 1
1339 end
1340 end
1341
1342 describe "reblogging" do
1343 test "reblogs and returns the reblogged status", %{conn: conn} do
1344 activity = insert(:note_activity)
1345 user = insert(:user)
1346
1347 conn =
1348 conn
1349 |> assign(:user, user)
1350 |> post("/api/v1/statuses/#{activity.id}/reblog")
1351
1352 assert %{
1353 "reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 1},
1354 "reblogged" => true
1355 } = json_response(conn, 200)
1356
1357 assert to_string(activity.id) == id
1358 end
1359
1360 test "reblogged status for another user", %{conn: conn} do
1361 activity = insert(:note_activity)
1362 user1 = insert(:user)
1363 user2 = insert(:user)
1364 user3 = insert(:user)
1365 CommonAPI.favorite(activity.id, user2)
1366 {:ok, _bookmark} = Pleroma.Bookmark.create(user2.id, activity.id)
1367 {:ok, reblog_activity1, _object} = CommonAPI.repeat(activity.id, user1)
1368 {:ok, _, _object} = CommonAPI.repeat(activity.id, user2)
1369
1370 conn_res =
1371 conn
1372 |> assign(:user, user3)
1373 |> get("/api/v1/statuses/#{reblog_activity1.id}")
1374
1375 assert %{
1376 "reblog" => %{"id" => id, "reblogged" => false, "reblogs_count" => 2},
1377 "reblogged" => false,
1378 "favourited" => false,
1379 "bookmarked" => false
1380 } = json_response(conn_res, 200)
1381
1382 conn_res =
1383 conn
1384 |> assign(:user, user2)
1385 |> get("/api/v1/statuses/#{reblog_activity1.id}")
1386
1387 assert %{
1388 "reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 2},
1389 "reblogged" => true,
1390 "favourited" => true,
1391 "bookmarked" => true
1392 } = json_response(conn_res, 200)
1393
1394 assert to_string(activity.id) == id
1395 end
1396
1397 test "returns 400 error when activity is not exist", %{conn: conn} do
1398 user = insert(:user)
1399
1400 conn =
1401 conn
1402 |> assign(:user, user)
1403 |> post("/api/v1/statuses/foo/reblog")
1404
1405 assert json_response(conn, 400) == %{"error" => "Could not repeat"}
1406 end
1407 end
1408
1409 describe "unreblogging" do
1410 test "unreblogs and returns the unreblogged status", %{conn: conn} do
1411 activity = insert(:note_activity)
1412 user = insert(:user)
1413
1414 {:ok, _, _} = CommonAPI.repeat(activity.id, user)
1415
1416 conn =
1417 conn
1418 |> assign(:user, user)
1419 |> post("/api/v1/statuses/#{activity.id}/unreblog")
1420
1421 assert %{"id" => id, "reblogged" => false, "reblogs_count" => 0} = json_response(conn, 200)
1422
1423 assert to_string(activity.id) == id
1424 end
1425
1426 test "returns 400 error when activity is not exist", %{conn: conn} do
1427 user = insert(:user)
1428
1429 conn =
1430 conn
1431 |> assign(:user, user)
1432 |> post("/api/v1/statuses/foo/unreblog")
1433
1434 assert json_response(conn, 400) == %{"error" => "Could not unrepeat"}
1435 end
1436 end
1437
1438 describe "favoriting" do
1439 test "favs a status and returns it", %{conn: conn} do
1440 activity = insert(:note_activity)
1441 user = insert(:user)
1442
1443 conn =
1444 conn
1445 |> assign(:user, user)
1446 |> post("/api/v1/statuses/#{activity.id}/favourite")
1447
1448 assert %{"id" => id, "favourites_count" => 1, "favourited" => true} =
1449 json_response(conn, 200)
1450
1451 assert to_string(activity.id) == id
1452 end
1453
1454 test "returns 400 error for a wrong id", %{conn: conn} do
1455 user = insert(:user)
1456
1457 conn =
1458 conn
1459 |> assign(:user, user)
1460 |> post("/api/v1/statuses/1/favourite")
1461
1462 assert json_response(conn, 400) == %{"error" => "Could not favorite"}
1463 end
1464 end
1465
1466 describe "unfavoriting" do
1467 test "unfavorites a status and returns it", %{conn: conn} do
1468 activity = insert(:note_activity)
1469 user = insert(:user)
1470
1471 {:ok, _, _} = CommonAPI.favorite(activity.id, user)
1472
1473 conn =
1474 conn
1475 |> assign(:user, user)
1476 |> post("/api/v1/statuses/#{activity.id}/unfavourite")
1477
1478 assert %{"id" => id, "favourites_count" => 0, "favourited" => false} =
1479 json_response(conn, 200)
1480
1481 assert to_string(activity.id) == id
1482 end
1483
1484 test "returns 400 error for a wrong id", %{conn: conn} do
1485 user = insert(:user)
1486
1487 conn =
1488 conn
1489 |> assign(:user, user)
1490 |> post("/api/v1/statuses/1/unfavourite")
1491
1492 assert json_response(conn, 400) == %{"error" => "Could not unfavorite"}
1493 end
1494 end
1495
1496 describe "user timelines" do
1497 test "gets a users statuses", %{conn: conn} do
1498 user_one = insert(:user)
1499 user_two = insert(:user)
1500 user_three = insert(:user)
1501
1502 {:ok, user_three} = User.follow(user_three, user_one)
1503
1504 {:ok, activity} = CommonAPI.post(user_one, %{"status" => "HI!!!"})
1505
1506 {:ok, direct_activity} =
1507 CommonAPI.post(user_one, %{
1508 "status" => "Hi, @#{user_two.nickname}.",
1509 "visibility" => "direct"
1510 })
1511
1512 {:ok, private_activity} =
1513 CommonAPI.post(user_one, %{"status" => "private", "visibility" => "private"})
1514
1515 resp =
1516 conn
1517 |> get("/api/v1/accounts/#{user_one.id}/statuses")
1518
1519 assert [%{"id" => id}] = json_response(resp, 200)
1520 assert id == to_string(activity.id)
1521
1522 resp =
1523 conn
1524 |> assign(:user, user_two)
1525 |> get("/api/v1/accounts/#{user_one.id}/statuses")
1526
1527 assert [%{"id" => id_one}, %{"id" => id_two}] = json_response(resp, 200)
1528 assert id_one == to_string(direct_activity.id)
1529 assert id_two == to_string(activity.id)
1530
1531 resp =
1532 conn
1533 |> assign(:user, user_three)
1534 |> get("/api/v1/accounts/#{user_one.id}/statuses")
1535
1536 assert [%{"id" => id_one}, %{"id" => id_two}] = json_response(resp, 200)
1537 assert id_one == to_string(private_activity.id)
1538 assert id_two == to_string(activity.id)
1539 end
1540
1541 test "unimplemented pinned statuses feature", %{conn: conn} do
1542 note = insert(:note_activity)
1543 user = User.get_cached_by_ap_id(note.data["actor"])
1544
1545 conn =
1546 conn
1547 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
1548
1549 assert json_response(conn, 200) == []
1550 end
1551
1552 test "gets an users media", %{conn: conn} do
1553 note = insert(:note_activity)
1554 user = User.get_cached_by_ap_id(note.data["actor"])
1555
1556 file = %Plug.Upload{
1557 content_type: "image/jpg",
1558 path: Path.absname("test/fixtures/image.jpg"),
1559 filename: "an_image.jpg"
1560 }
1561
1562 media =
1563 TwitterAPI.upload(file, user, "json")
1564 |> Jason.decode!()
1565
1566 {:ok, image_post} =
1567 CommonAPI.post(user, %{"status" => "cofe", "media_ids" => [media["media_id"]]})
1568
1569 conn =
1570 conn
1571 |> get("/api/v1/accounts/#{user.id}/statuses", %{"only_media" => "true"})
1572
1573 assert [%{"id" => id}] = json_response(conn, 200)
1574 assert id == to_string(image_post.id)
1575
1576 conn =
1577 build_conn()
1578 |> get("/api/v1/accounts/#{user.id}/statuses", %{"only_media" => "1"})
1579
1580 assert [%{"id" => id}] = json_response(conn, 200)
1581 assert id == to_string(image_post.id)
1582 end
1583
1584 test "gets a user's statuses without reblogs", %{conn: conn} do
1585 user = insert(:user)
1586 {:ok, post} = CommonAPI.post(user, %{"status" => "HI!!!"})
1587 {:ok, _, _} = CommonAPI.repeat(post.id, user)
1588
1589 conn =
1590 conn
1591 |> get("/api/v1/accounts/#{user.id}/statuses", %{"exclude_reblogs" => "true"})
1592
1593 assert [%{"id" => id}] = json_response(conn, 200)
1594 assert id == to_string(post.id)
1595
1596 conn =
1597 conn
1598 |> get("/api/v1/accounts/#{user.id}/statuses", %{"exclude_reblogs" => "1"})
1599
1600 assert [%{"id" => id}] = json_response(conn, 200)
1601 assert id == to_string(post.id)
1602 end
1603
1604 test "filters user's statuses by a hashtag", %{conn: conn} do
1605 user = insert(:user)
1606 {:ok, post} = CommonAPI.post(user, %{"status" => "#hashtag"})
1607 {:ok, _post} = CommonAPI.post(user, %{"status" => "hashtag"})
1608
1609 conn =
1610 conn
1611 |> get("/api/v1/accounts/#{user.id}/statuses", %{"tagged" => "hashtag"})
1612
1613 assert [%{"id" => id}] = json_response(conn, 200)
1614 assert id == to_string(post.id)
1615 end
1616 end
1617
1618 describe "user relationships" do
1619 test "returns the relationships for the current user", %{conn: conn} do
1620 user = insert(:user)
1621 other_user = insert(:user)
1622 {:ok, user} = User.follow(user, other_user)
1623
1624 conn =
1625 conn
1626 |> assign(:user, user)
1627 |> get("/api/v1/accounts/relationships", %{"id" => [other_user.id]})
1628
1629 assert [relationship] = json_response(conn, 200)
1630
1631 assert to_string(other_user.id) == relationship["id"]
1632 end
1633 end
1634
1635 describe "media upload" do
1636 setup do
1637 upload_config = Config.get([Pleroma.Upload])
1638 proxy_config = Config.get([:media_proxy])
1639
1640 on_exit(fn ->
1641 Config.put([Pleroma.Upload], upload_config)
1642 Config.put([:media_proxy], proxy_config)
1643 end)
1644
1645 user = insert(:user)
1646
1647 conn =
1648 build_conn()
1649 |> assign(:user, user)
1650
1651 image = %Plug.Upload{
1652 content_type: "image/jpg",
1653 path: Path.absname("test/fixtures/image.jpg"),
1654 filename: "an_image.jpg"
1655 }
1656
1657 [conn: conn, image: image]
1658 end
1659
1660 test "returns uploaded image", %{conn: conn, image: image} do
1661 desc = "Description of the image"
1662
1663 media =
1664 conn
1665 |> post("/api/v1/media", %{"file" => image, "description" => desc})
1666 |> json_response(:ok)
1667
1668 assert media["type"] == "image"
1669 assert media["description"] == desc
1670 assert media["id"]
1671
1672 object = Repo.get(Object, media["id"])
1673 assert object.data["actor"] == User.ap_id(conn.assigns[:user])
1674 end
1675 end
1676
1677 describe "locked accounts" do
1678 test "/api/v1/follow_requests works" do
1679 user = insert(:user, %{info: %User.Info{locked: true}})
1680 other_user = insert(:user)
1681
1682 {:ok, _activity} = ActivityPub.follow(other_user, user)
1683
1684 user = User.get_cached_by_id(user.id)
1685 other_user = User.get_cached_by_id(other_user.id)
1686
1687 assert User.following?(other_user, user) == false
1688
1689 conn =
1690 build_conn()
1691 |> assign(:user, user)
1692 |> get("/api/v1/follow_requests")
1693
1694 assert [relationship] = json_response(conn, 200)
1695 assert to_string(other_user.id) == relationship["id"]
1696 end
1697
1698 test "/api/v1/follow_requests/:id/authorize works" do
1699 user = insert(:user, %{info: %User.Info{locked: true}})
1700 other_user = insert(:user)
1701
1702 {:ok, _activity} = ActivityPub.follow(other_user, user)
1703
1704 user = User.get_cached_by_id(user.id)
1705 other_user = User.get_cached_by_id(other_user.id)
1706
1707 assert User.following?(other_user, user) == false
1708
1709 conn =
1710 build_conn()
1711 |> assign(:user, user)
1712 |> post("/api/v1/follow_requests/#{other_user.id}/authorize")
1713
1714 assert relationship = json_response(conn, 200)
1715 assert to_string(other_user.id) == relationship["id"]
1716
1717 user = User.get_cached_by_id(user.id)
1718 other_user = User.get_cached_by_id(other_user.id)
1719
1720 assert User.following?(other_user, user) == true
1721 end
1722
1723 test "verify_credentials", %{conn: conn} do
1724 user = insert(:user, %{info: %User.Info{default_scope: "private"}})
1725
1726 conn =
1727 conn
1728 |> assign(:user, user)
1729 |> get("/api/v1/accounts/verify_credentials")
1730
1731 assert %{"id" => id, "source" => %{"privacy" => "private"}} = json_response(conn, 200)
1732 assert id == to_string(user.id)
1733 end
1734
1735 test "/api/v1/follow_requests/:id/reject works" do
1736 user = insert(:user, %{info: %User.Info{locked: true}})
1737 other_user = insert(:user)
1738
1739 {:ok, _activity} = ActivityPub.follow(other_user, user)
1740
1741 user = User.get_cached_by_id(user.id)
1742
1743 conn =
1744 build_conn()
1745 |> assign(:user, user)
1746 |> post("/api/v1/follow_requests/#{other_user.id}/reject")
1747
1748 assert relationship = json_response(conn, 200)
1749 assert to_string(other_user.id) == relationship["id"]
1750
1751 user = User.get_cached_by_id(user.id)
1752 other_user = User.get_cached_by_id(other_user.id)
1753
1754 assert User.following?(other_user, user) == false
1755 end
1756 end
1757
1758 test "account fetching", %{conn: conn} do
1759 user = insert(:user)
1760
1761 conn =
1762 conn
1763 |> get("/api/v1/accounts/#{user.id}")
1764
1765 assert %{"id" => id} = json_response(conn, 200)
1766 assert id == to_string(user.id)
1767
1768 conn =
1769 build_conn()
1770 |> get("/api/v1/accounts/-1")
1771
1772 assert %{"error" => "Can't find user"} = json_response(conn, 404)
1773 end
1774
1775 test "account fetching also works nickname", %{conn: conn} do
1776 user = insert(:user)
1777
1778 conn =
1779 conn
1780 |> get("/api/v1/accounts/#{user.nickname}")
1781
1782 assert %{"id" => id} = json_response(conn, 200)
1783 assert id == user.id
1784 end
1785
1786 test "mascot upload", %{conn: conn} do
1787 user = insert(:user)
1788
1789 non_image_file = %Plug.Upload{
1790 content_type: "audio/mpeg",
1791 path: Path.absname("test/fixtures/sound.mp3"),
1792 filename: "sound.mp3"
1793 }
1794
1795 conn =
1796 conn
1797 |> assign(:user, user)
1798 |> put("/api/v1/pleroma/mascot", %{"file" => non_image_file})
1799
1800 assert json_response(conn, 415)
1801
1802 file = %Plug.Upload{
1803 content_type: "image/jpg",
1804 path: Path.absname("test/fixtures/image.jpg"),
1805 filename: "an_image.jpg"
1806 }
1807
1808 conn =
1809 build_conn()
1810 |> assign(:user, user)
1811 |> put("/api/v1/pleroma/mascot", %{"file" => file})
1812
1813 assert %{"id" => _, "type" => image} = json_response(conn, 200)
1814 end
1815
1816 test "mascot retrieving", %{conn: conn} do
1817 user = insert(:user)
1818 # When user hasn't set a mascot, we should just get pleroma tan back
1819 conn =
1820 conn
1821 |> assign(:user, user)
1822 |> get("/api/v1/pleroma/mascot")
1823
1824 assert %{"url" => url} = json_response(conn, 200)
1825 assert url =~ "pleroma-fox-tan-smol"
1826
1827 # When a user sets their mascot, we should get that back
1828 file = %Plug.Upload{
1829 content_type: "image/jpg",
1830 path: Path.absname("test/fixtures/image.jpg"),
1831 filename: "an_image.jpg"
1832 }
1833
1834 conn =
1835 build_conn()
1836 |> assign(:user, user)
1837 |> put("/api/v1/pleroma/mascot", %{"file" => file})
1838
1839 assert json_response(conn, 200)
1840
1841 user = User.get_cached_by_id(user.id)
1842
1843 conn =
1844 build_conn()
1845 |> assign(:user, user)
1846 |> get("/api/v1/pleroma/mascot")
1847
1848 assert %{"url" => url, "type" => "image"} = json_response(conn, 200)
1849 assert url =~ "an_image"
1850 end
1851
1852 test "hashtag timeline", %{conn: conn} do
1853 following = insert(:user)
1854
1855 capture_log(fn ->
1856 {:ok, activity} = CommonAPI.post(following, %{"status" => "test #2hu"})
1857
1858 {:ok, [_activity]} =
1859 OStatus.fetch_activity_from_url("https://shitposter.club/notice/2827873")
1860
1861 nconn =
1862 conn
1863 |> get("/api/v1/timelines/tag/2hu")
1864
1865 assert [%{"id" => id}] = json_response(nconn, 200)
1866
1867 assert id == to_string(activity.id)
1868
1869 # works for different capitalization too
1870 nconn =
1871 conn
1872 |> get("/api/v1/timelines/tag/2HU")
1873
1874 assert [%{"id" => id}] = json_response(nconn, 200)
1875
1876 assert id == to_string(activity.id)
1877 end)
1878 end
1879
1880 test "multi-hashtag timeline", %{conn: conn} do
1881 user = insert(:user)
1882
1883 {:ok, activity_test} = CommonAPI.post(user, %{"status" => "#test"})
1884 {:ok, activity_test1} = CommonAPI.post(user, %{"status" => "#test #test1"})
1885 {:ok, activity_none} = CommonAPI.post(user, %{"status" => "#test #none"})
1886
1887 any_test =
1888 conn
1889 |> get("/api/v1/timelines/tag/test", %{"any" => ["test1"]})
1890
1891 [status_none, status_test1, status_test] = json_response(any_test, 200)
1892
1893 assert to_string(activity_test.id) == status_test["id"]
1894 assert to_string(activity_test1.id) == status_test1["id"]
1895 assert to_string(activity_none.id) == status_none["id"]
1896
1897 restricted_test =
1898 conn
1899 |> get("/api/v1/timelines/tag/test", %{"all" => ["test1"], "none" => ["none"]})
1900
1901 assert [status_test1] == json_response(restricted_test, 200)
1902
1903 all_test = conn |> get("/api/v1/timelines/tag/test", %{"all" => ["none"]})
1904
1905 assert [status_none] == json_response(all_test, 200)
1906 end
1907
1908 test "getting followers", %{conn: conn} do
1909 user = insert(:user)
1910 other_user = insert(:user)
1911 {:ok, user} = User.follow(user, other_user)
1912
1913 conn =
1914 conn
1915 |> get("/api/v1/accounts/#{other_user.id}/followers")
1916
1917 assert [%{"id" => id}] = json_response(conn, 200)
1918 assert id == to_string(user.id)
1919 end
1920
1921 test "getting followers, hide_followers", %{conn: conn} do
1922 user = insert(:user)
1923 other_user = insert(:user, %{info: %{hide_followers: true}})
1924 {:ok, _user} = User.follow(user, other_user)
1925
1926 conn =
1927 conn
1928 |> get("/api/v1/accounts/#{other_user.id}/followers")
1929
1930 assert [] == json_response(conn, 200)
1931 end
1932
1933 test "getting followers, hide_followers, same user requesting", %{conn: conn} do
1934 user = insert(:user)
1935 other_user = insert(:user, %{info: %{hide_followers: true}})
1936 {:ok, _user} = User.follow(user, other_user)
1937
1938 conn =
1939 conn
1940 |> assign(:user, other_user)
1941 |> get("/api/v1/accounts/#{other_user.id}/followers")
1942
1943 refute [] == json_response(conn, 200)
1944 end
1945
1946 test "getting followers, pagination", %{conn: conn} do
1947 user = insert(:user)
1948 follower1 = insert(:user)
1949 follower2 = insert(:user)
1950 follower3 = insert(:user)
1951 {:ok, _} = User.follow(follower1, user)
1952 {:ok, _} = User.follow(follower2, user)
1953 {:ok, _} = User.follow(follower3, user)
1954
1955 conn =
1956 conn
1957 |> assign(:user, user)
1958
1959 res_conn =
1960 conn
1961 |> get("/api/v1/accounts/#{user.id}/followers?since_id=#{follower1.id}")
1962
1963 assert [%{"id" => id3}, %{"id" => id2}] = json_response(res_conn, 200)
1964 assert id3 == follower3.id
1965 assert id2 == follower2.id
1966
1967 res_conn =
1968 conn
1969 |> get("/api/v1/accounts/#{user.id}/followers?max_id=#{follower3.id}")
1970
1971 assert [%{"id" => id2}, %{"id" => id1}] = json_response(res_conn, 200)
1972 assert id2 == follower2.id
1973 assert id1 == follower1.id
1974
1975 res_conn =
1976 conn
1977 |> get("/api/v1/accounts/#{user.id}/followers?limit=1&max_id=#{follower3.id}")
1978
1979 assert [%{"id" => id2}] = json_response(res_conn, 200)
1980 assert id2 == follower2.id
1981
1982 assert [link_header] = get_resp_header(res_conn, "link")
1983 assert link_header =~ ~r/min_id=#{follower2.id}/
1984 assert link_header =~ ~r/max_id=#{follower2.id}/
1985 end
1986
1987 test "getting following", %{conn: conn} do
1988 user = insert(:user)
1989 other_user = insert(:user)
1990 {:ok, user} = User.follow(user, other_user)
1991
1992 conn =
1993 conn
1994 |> get("/api/v1/accounts/#{user.id}/following")
1995
1996 assert [%{"id" => id}] = json_response(conn, 200)
1997 assert id == to_string(other_user.id)
1998 end
1999
2000 test "getting following, hide_follows", %{conn: conn} do
2001 user = insert(:user, %{info: %{hide_follows: true}})
2002 other_user = insert(:user)
2003 {:ok, user} = User.follow(user, other_user)
2004
2005 conn =
2006 conn
2007 |> get("/api/v1/accounts/#{user.id}/following")
2008
2009 assert [] == json_response(conn, 200)
2010 end
2011
2012 test "getting following, hide_follows, same user requesting", %{conn: conn} do
2013 user = insert(:user, %{info: %{hide_follows: true}})
2014 other_user = insert(:user)
2015 {:ok, user} = User.follow(user, other_user)
2016
2017 conn =
2018 conn
2019 |> assign(:user, user)
2020 |> get("/api/v1/accounts/#{user.id}/following")
2021
2022 refute [] == json_response(conn, 200)
2023 end
2024
2025 test "getting following, pagination", %{conn: conn} do
2026 user = insert(:user)
2027 following1 = insert(:user)
2028 following2 = insert(:user)
2029 following3 = insert(:user)
2030 {:ok, _} = User.follow(user, following1)
2031 {:ok, _} = User.follow(user, following2)
2032 {:ok, _} = User.follow(user, following3)
2033
2034 conn =
2035 conn
2036 |> assign(:user, user)
2037
2038 res_conn =
2039 conn
2040 |> get("/api/v1/accounts/#{user.id}/following?since_id=#{following1.id}")
2041
2042 assert [%{"id" => id3}, %{"id" => id2}] = json_response(res_conn, 200)
2043 assert id3 == following3.id
2044 assert id2 == following2.id
2045
2046 res_conn =
2047 conn
2048 |> get("/api/v1/accounts/#{user.id}/following?max_id=#{following3.id}")
2049
2050 assert [%{"id" => id2}, %{"id" => id1}] = json_response(res_conn, 200)
2051 assert id2 == following2.id
2052 assert id1 == following1.id
2053
2054 res_conn =
2055 conn
2056 |> get("/api/v1/accounts/#{user.id}/following?limit=1&max_id=#{following3.id}")
2057
2058 assert [%{"id" => id2}] = json_response(res_conn, 200)
2059 assert id2 == following2.id
2060
2061 assert [link_header] = get_resp_header(res_conn, "link")
2062 assert link_header =~ ~r/min_id=#{following2.id}/
2063 assert link_header =~ ~r/max_id=#{following2.id}/
2064 end
2065
2066 test "following / unfollowing a user", %{conn: conn} do
2067 user = insert(:user)
2068 other_user = insert(:user)
2069
2070 conn =
2071 conn
2072 |> assign(:user, user)
2073 |> post("/api/v1/accounts/#{other_user.id}/follow")
2074
2075 assert %{"id" => _id, "following" => true} = json_response(conn, 200)
2076
2077 user = User.get_cached_by_id(user.id)
2078
2079 conn =
2080 build_conn()
2081 |> assign(:user, user)
2082 |> post("/api/v1/accounts/#{other_user.id}/unfollow")
2083
2084 assert %{"id" => _id, "following" => false} = json_response(conn, 200)
2085
2086 user = User.get_cached_by_id(user.id)
2087
2088 conn =
2089 build_conn()
2090 |> assign(:user, user)
2091 |> post("/api/v1/follows", %{"uri" => other_user.nickname})
2092
2093 assert %{"id" => id} = json_response(conn, 200)
2094 assert id == to_string(other_user.id)
2095 end
2096
2097 test "following without reblogs" do
2098 follower = insert(:user)
2099 followed = insert(:user)
2100 other_user = insert(:user)
2101
2102 conn =
2103 build_conn()
2104 |> assign(:user, follower)
2105 |> post("/api/v1/accounts/#{followed.id}/follow?reblogs=false")
2106
2107 assert %{"showing_reblogs" => false} = json_response(conn, 200)
2108
2109 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "hey"})
2110 {:ok, reblog, _} = CommonAPI.repeat(activity.id, followed)
2111
2112 conn =
2113 build_conn()
2114 |> assign(:user, User.get_cached_by_id(follower.id))
2115 |> get("/api/v1/timelines/home")
2116
2117 assert [] == json_response(conn, 200)
2118
2119 conn =
2120 build_conn()
2121 |> assign(:user, follower)
2122 |> post("/api/v1/accounts/#{followed.id}/follow?reblogs=true")
2123
2124 assert %{"showing_reblogs" => true} = json_response(conn, 200)
2125
2126 conn =
2127 build_conn()
2128 |> assign(:user, User.get_cached_by_id(follower.id))
2129 |> get("/api/v1/timelines/home")
2130
2131 expected_activity_id = reblog.id
2132 assert [%{"id" => ^expected_activity_id}] = json_response(conn, 200)
2133 end
2134
2135 test "following / unfollowing errors" do
2136 user = insert(:user)
2137
2138 conn =
2139 build_conn()
2140 |> assign(:user, user)
2141
2142 # self follow
2143 conn_res = post(conn, "/api/v1/accounts/#{user.id}/follow")
2144 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
2145
2146 # self unfollow
2147 user = User.get_cached_by_id(user.id)
2148 conn_res = post(conn, "/api/v1/accounts/#{user.id}/unfollow")
2149 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
2150
2151 # self follow via uri
2152 user = User.get_cached_by_id(user.id)
2153 conn_res = post(conn, "/api/v1/follows", %{"uri" => user.nickname})
2154 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
2155
2156 # follow non existing user
2157 conn_res = post(conn, "/api/v1/accounts/doesntexist/follow")
2158 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
2159
2160 # follow non existing user via uri
2161 conn_res = post(conn, "/api/v1/follows", %{"uri" => "doesntexist"})
2162 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
2163
2164 # unfollow non existing user
2165 conn_res = post(conn, "/api/v1/accounts/doesntexist/unfollow")
2166 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
2167 end
2168
2169 describe "mute/unmute" do
2170 test "with notifications", %{conn: conn} do
2171 user = insert(:user)
2172 other_user = insert(:user)
2173
2174 conn =
2175 conn
2176 |> assign(:user, user)
2177 |> post("/api/v1/accounts/#{other_user.id}/mute")
2178
2179 response = json_response(conn, 200)
2180
2181 assert %{"id" => _id, "muting" => true, "muting_notifications" => true} = response
2182 user = User.get_cached_by_id(user.id)
2183
2184 conn =
2185 build_conn()
2186 |> assign(:user, user)
2187 |> post("/api/v1/accounts/#{other_user.id}/unmute")
2188
2189 response = json_response(conn, 200)
2190 assert %{"id" => _id, "muting" => false, "muting_notifications" => false} = response
2191 end
2192
2193 test "without notifications", %{conn: conn} do
2194 user = insert(:user)
2195 other_user = insert(:user)
2196
2197 conn =
2198 conn
2199 |> assign(:user, user)
2200 |> post("/api/v1/accounts/#{other_user.id}/mute", %{"notifications" => "false"})
2201
2202 response = json_response(conn, 200)
2203
2204 assert %{"id" => _id, "muting" => true, "muting_notifications" => false} = response
2205 user = User.get_cached_by_id(user.id)
2206
2207 conn =
2208 build_conn()
2209 |> assign(:user, user)
2210 |> post("/api/v1/accounts/#{other_user.id}/unmute")
2211
2212 response = json_response(conn, 200)
2213 assert %{"id" => _id, "muting" => false, "muting_notifications" => false} = response
2214 end
2215 end
2216
2217 test "subscribing / unsubscribing to a user", %{conn: conn} do
2218 user = insert(:user)
2219 subscription_target = insert(:user)
2220
2221 conn =
2222 conn
2223 |> assign(:user, user)
2224 |> post("/api/v1/pleroma/accounts/#{subscription_target.id}/subscribe")
2225
2226 assert %{"id" => _id, "subscribing" => true} = json_response(conn, 200)
2227
2228 conn =
2229 build_conn()
2230 |> assign(:user, user)
2231 |> post("/api/v1/pleroma/accounts/#{subscription_target.id}/unsubscribe")
2232
2233 assert %{"id" => _id, "subscribing" => false} = json_response(conn, 200)
2234 end
2235
2236 test "getting a list of mutes", %{conn: conn} do
2237 user = insert(:user)
2238 other_user = insert(:user)
2239
2240 {:ok, user} = User.mute(user, other_user)
2241
2242 conn =
2243 conn
2244 |> assign(:user, user)
2245 |> get("/api/v1/mutes")
2246
2247 other_user_id = to_string(other_user.id)
2248 assert [%{"id" => ^other_user_id}] = json_response(conn, 200)
2249 end
2250
2251 test "blocking / unblocking a user", %{conn: conn} do
2252 user = insert(:user)
2253 other_user = insert(:user)
2254
2255 conn =
2256 conn
2257 |> assign(:user, user)
2258 |> post("/api/v1/accounts/#{other_user.id}/block")
2259
2260 assert %{"id" => _id, "blocking" => true} = json_response(conn, 200)
2261
2262 user = User.get_cached_by_id(user.id)
2263
2264 conn =
2265 build_conn()
2266 |> assign(:user, user)
2267 |> post("/api/v1/accounts/#{other_user.id}/unblock")
2268
2269 assert %{"id" => _id, "blocking" => false} = json_response(conn, 200)
2270 end
2271
2272 test "getting a list of blocks", %{conn: conn} do
2273 user = insert(:user)
2274 other_user = insert(:user)
2275
2276 {:ok, user} = User.block(user, other_user)
2277
2278 conn =
2279 conn
2280 |> assign(:user, user)
2281 |> get("/api/v1/blocks")
2282
2283 other_user_id = to_string(other_user.id)
2284 assert [%{"id" => ^other_user_id}] = json_response(conn, 200)
2285 end
2286
2287 test "blocking / unblocking a domain", %{conn: conn} do
2288 user = insert(:user)
2289 other_user = insert(:user, %{ap_id: "https://dogwhistle.zone/@pundit"})
2290
2291 conn =
2292 conn
2293 |> assign(:user, user)
2294 |> post("/api/v1/domain_blocks", %{"domain" => "dogwhistle.zone"})
2295
2296 assert %{} = json_response(conn, 200)
2297 user = User.get_cached_by_ap_id(user.ap_id)
2298 assert User.blocks?(user, other_user)
2299
2300 conn =
2301 build_conn()
2302 |> assign(:user, user)
2303 |> delete("/api/v1/domain_blocks", %{"domain" => "dogwhistle.zone"})
2304
2305 assert %{} = json_response(conn, 200)
2306 user = User.get_cached_by_ap_id(user.ap_id)
2307 refute User.blocks?(user, other_user)
2308 end
2309
2310 test "getting a list of domain blocks", %{conn: conn} do
2311 user = insert(:user)
2312
2313 {:ok, user} = User.block_domain(user, "bad.site")
2314 {:ok, user} = User.block_domain(user, "even.worse.site")
2315
2316 conn =
2317 conn
2318 |> assign(:user, user)
2319 |> get("/api/v1/domain_blocks")
2320
2321 domain_blocks = json_response(conn, 200)
2322
2323 assert "bad.site" in domain_blocks
2324 assert "even.worse.site" in domain_blocks
2325 end
2326
2327 test "unimplemented follow_requests, blocks, domain blocks" do
2328 user = insert(:user)
2329
2330 ["blocks", "domain_blocks", "follow_requests"]
2331 |> Enum.each(fn endpoint ->
2332 conn =
2333 build_conn()
2334 |> assign(:user, user)
2335 |> get("/api/v1/#{endpoint}")
2336
2337 assert [] = json_response(conn, 200)
2338 end)
2339 end
2340
2341 test "returns the favorites of a user", %{conn: conn} do
2342 user = insert(:user)
2343 other_user = insert(:user)
2344
2345 {:ok, _} = CommonAPI.post(other_user, %{"status" => "bla"})
2346 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "traps are happy"})
2347
2348 {:ok, _, _} = CommonAPI.favorite(activity.id, user)
2349
2350 first_conn =
2351 conn
2352 |> assign(:user, user)
2353 |> get("/api/v1/favourites")
2354
2355 assert [status] = json_response(first_conn, 200)
2356 assert status["id"] == to_string(activity.id)
2357
2358 assert [{"link", _link_header}] =
2359 Enum.filter(first_conn.resp_headers, fn element -> match?({"link", _}, element) end)
2360
2361 # Honours query params
2362 {:ok, second_activity} =
2363 CommonAPI.post(other_user, %{
2364 "status" =>
2365 "Trees Are Never Sad Look At Them Every Once In Awhile They're Quite Beautiful."
2366 })
2367
2368 {:ok, _, _} = CommonAPI.favorite(second_activity.id, user)
2369
2370 last_like = status["id"]
2371
2372 second_conn =
2373 conn
2374 |> assign(:user, user)
2375 |> get("/api/v1/favourites?since_id=#{last_like}")
2376
2377 assert [second_status] = json_response(second_conn, 200)
2378 assert second_status["id"] == to_string(second_activity.id)
2379
2380 third_conn =
2381 conn
2382 |> assign(:user, user)
2383 |> get("/api/v1/favourites?limit=0")
2384
2385 assert [] = json_response(third_conn, 200)
2386 end
2387
2388 describe "getting favorites timeline of specified user" do
2389 setup do
2390 [current_user, user] = insert_pair(:user, %{info: %{hide_favorites: false}})
2391 [current_user: current_user, user: user]
2392 end
2393
2394 test "returns list of statuses favorited by specified user", %{
2395 conn: conn,
2396 current_user: current_user,
2397 user: user
2398 } do
2399 [activity | _] = insert_pair(:note_activity)
2400 CommonAPI.favorite(activity.id, user)
2401
2402 response =
2403 conn
2404 |> assign(:user, current_user)
2405 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2406 |> json_response(:ok)
2407
2408 [like] = response
2409
2410 assert length(response) == 1
2411 assert like["id"] == activity.id
2412 end
2413
2414 test "returns favorites for specified user_id when user is not logged in", %{
2415 conn: conn,
2416 user: user
2417 } do
2418 activity = insert(:note_activity)
2419 CommonAPI.favorite(activity.id, user)
2420
2421 response =
2422 conn
2423 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2424 |> json_response(:ok)
2425
2426 assert length(response) == 1
2427 end
2428
2429 test "returns favorited DM only when user is logged in and he is one of recipients", %{
2430 conn: conn,
2431 current_user: current_user,
2432 user: user
2433 } do
2434 {:ok, direct} =
2435 CommonAPI.post(current_user, %{
2436 "status" => "Hi @#{user.nickname}!",
2437 "visibility" => "direct"
2438 })
2439
2440 CommonAPI.favorite(direct.id, user)
2441
2442 response =
2443 conn
2444 |> assign(:user, current_user)
2445 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2446 |> json_response(:ok)
2447
2448 assert length(response) == 1
2449
2450 anonymous_response =
2451 conn
2452 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2453 |> json_response(:ok)
2454
2455 assert Enum.empty?(anonymous_response)
2456 end
2457
2458 test "does not return others' favorited DM when user is not one of recipients", %{
2459 conn: conn,
2460 current_user: current_user,
2461 user: user
2462 } do
2463 user_two = insert(:user)
2464
2465 {:ok, direct} =
2466 CommonAPI.post(user_two, %{
2467 "status" => "Hi @#{user.nickname}!",
2468 "visibility" => "direct"
2469 })
2470
2471 CommonAPI.favorite(direct.id, user)
2472
2473 response =
2474 conn
2475 |> assign(:user, current_user)
2476 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2477 |> json_response(:ok)
2478
2479 assert Enum.empty?(response)
2480 end
2481
2482 test "paginates favorites using since_id and max_id", %{
2483 conn: conn,
2484 current_user: current_user,
2485 user: user
2486 } do
2487 activities = insert_list(10, :note_activity)
2488
2489 Enum.each(activities, fn activity ->
2490 CommonAPI.favorite(activity.id, user)
2491 end)
2492
2493 third_activity = Enum.at(activities, 2)
2494 seventh_activity = Enum.at(activities, 6)
2495
2496 response =
2497 conn
2498 |> assign(:user, current_user)
2499 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites", %{
2500 since_id: third_activity.id,
2501 max_id: seventh_activity.id
2502 })
2503 |> json_response(:ok)
2504
2505 assert length(response) == 3
2506 refute third_activity in response
2507 refute seventh_activity in response
2508 end
2509
2510 test "limits favorites using limit parameter", %{
2511 conn: conn,
2512 current_user: current_user,
2513 user: user
2514 } do
2515 7
2516 |> insert_list(:note_activity)
2517 |> Enum.each(fn activity ->
2518 CommonAPI.favorite(activity.id, user)
2519 end)
2520
2521 response =
2522 conn
2523 |> assign(:user, current_user)
2524 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites", %{limit: "3"})
2525 |> json_response(:ok)
2526
2527 assert length(response) == 3
2528 end
2529
2530 test "returns empty response when user does not have any favorited statuses", %{
2531 conn: conn,
2532 current_user: current_user,
2533 user: user
2534 } do
2535 response =
2536 conn
2537 |> assign(:user, current_user)
2538 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2539 |> json_response(:ok)
2540
2541 assert Enum.empty?(response)
2542 end
2543
2544 test "returns 404 error when specified user is not exist", %{conn: conn} do
2545 conn = get(conn, "/api/v1/pleroma/accounts/test/favourites")
2546
2547 assert json_response(conn, 404) == %{"error" => "Record not found"}
2548 end
2549
2550 test "returns 403 error when user has hidden own favorites", %{
2551 conn: conn,
2552 current_user: current_user
2553 } do
2554 user = insert(:user, %{info: %{hide_favorites: true}})
2555 activity = insert(:note_activity)
2556 CommonAPI.favorite(activity.id, user)
2557
2558 conn =
2559 conn
2560 |> assign(:user, current_user)
2561 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2562
2563 assert json_response(conn, 403) == %{"error" => "Can't get favorites"}
2564 end
2565
2566 test "hides favorites for new users by default", %{conn: conn, current_user: current_user} do
2567 user = insert(:user)
2568 activity = insert(:note_activity)
2569 CommonAPI.favorite(activity.id, user)
2570
2571 conn =
2572 conn
2573 |> assign(:user, current_user)
2574 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2575
2576 assert user.info.hide_favorites
2577 assert json_response(conn, 403) == %{"error" => "Can't get favorites"}
2578 end
2579 end
2580
2581 test "get instance information", %{conn: conn} do
2582 conn = get(conn, "/api/v1/instance")
2583 assert result = json_response(conn, 200)
2584
2585 email = Config.get([:instance, :email])
2586 # Note: not checking for "max_toot_chars" since it's optional
2587 assert %{
2588 "uri" => _,
2589 "title" => _,
2590 "description" => _,
2591 "version" => _,
2592 "email" => from_config_email,
2593 "urls" => %{
2594 "streaming_api" => _
2595 },
2596 "stats" => _,
2597 "thumbnail" => _,
2598 "languages" => _,
2599 "registrations" => _,
2600 "poll_limits" => _
2601 } = result
2602
2603 assert email == from_config_email
2604 end
2605
2606 test "get instance stats", %{conn: conn} do
2607 user = insert(:user, %{local: true})
2608
2609 user2 = insert(:user, %{local: true})
2610 {:ok, _user2} = User.deactivate(user2, !user2.info.deactivated)
2611
2612 insert(:user, %{local: false, nickname: "u@peer1.com"})
2613 insert(:user, %{local: false, nickname: "u@peer2.com"})
2614
2615 {:ok, _} = CommonAPI.post(user, %{"status" => "cofe"})
2616
2617 # Stats should count users with missing or nil `info.deactivated` value
2618 user = User.get_cached_by_id(user.id)
2619 info_change = Changeset.change(user.info, %{deactivated: nil})
2620
2621 {:ok, _user} =
2622 user
2623 |> Changeset.change()
2624 |> Changeset.put_embed(:info, info_change)
2625 |> User.update_and_set_cache()
2626
2627 Pleroma.Stats.force_update()
2628
2629 conn = get(conn, "/api/v1/instance")
2630
2631 assert result = json_response(conn, 200)
2632
2633 stats = result["stats"]
2634
2635 assert stats
2636 assert stats["user_count"] == 1
2637 assert stats["status_count"] == 1
2638 assert stats["domain_count"] == 2
2639 end
2640
2641 test "get peers", %{conn: conn} do
2642 insert(:user, %{local: false, nickname: "u@peer1.com"})
2643 insert(:user, %{local: false, nickname: "u@peer2.com"})
2644
2645 Pleroma.Stats.force_update()
2646
2647 conn = get(conn, "/api/v1/instance/peers")
2648
2649 assert result = json_response(conn, 200)
2650
2651 assert ["peer1.com", "peer2.com"] == Enum.sort(result)
2652 end
2653
2654 test "put settings", %{conn: conn} do
2655 user = insert(:user)
2656
2657 conn =
2658 conn
2659 |> assign(:user, user)
2660 |> put("/api/web/settings", %{"data" => %{"programming" => "socks"}})
2661
2662 assert _result = json_response(conn, 200)
2663
2664 user = User.get_cached_by_ap_id(user.ap_id)
2665 assert user.info.settings == %{"programming" => "socks"}
2666 end
2667
2668 describe "pinned statuses" do
2669 setup do
2670 Config.put([:instance, :max_pinned_statuses], 1)
2671
2672 user = insert(:user)
2673 {:ok, activity} = CommonAPI.post(user, %{"status" => "HI!!!"})
2674
2675 [user: user, activity: activity]
2676 end
2677
2678 test "returns pinned statuses", %{conn: conn, user: user, activity: activity} do
2679 {:ok, _} = CommonAPI.pin(activity.id, user)
2680
2681 result =
2682 conn
2683 |> assign(:user, user)
2684 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
2685 |> json_response(200)
2686
2687 id_str = to_string(activity.id)
2688
2689 assert [%{"id" => ^id_str, "pinned" => true}] = result
2690 end
2691
2692 test "pin status", %{conn: conn, user: user, activity: activity} do
2693 id_str = to_string(activity.id)
2694
2695 assert %{"id" => ^id_str, "pinned" => true} =
2696 conn
2697 |> assign(:user, user)
2698 |> post("/api/v1/statuses/#{activity.id}/pin")
2699 |> json_response(200)
2700
2701 assert [%{"id" => ^id_str, "pinned" => true}] =
2702 conn
2703 |> assign(:user, user)
2704 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
2705 |> json_response(200)
2706 end
2707
2708 test "/pin: returns 400 error when activity is not public", %{conn: conn, user: user} do
2709 {:ok, dm} = CommonAPI.post(user, %{"status" => "test", "visibility" => "direct"})
2710
2711 conn =
2712 conn
2713 |> assign(:user, user)
2714 |> post("/api/v1/statuses/#{dm.id}/pin")
2715
2716 assert json_response(conn, 400) == %{"error" => "Could not pin"}
2717 end
2718
2719 test "unpin status", %{conn: conn, user: user, activity: activity} do
2720 {:ok, _} = CommonAPI.pin(activity.id, user)
2721
2722 id_str = to_string(activity.id)
2723 user = refresh_record(user)
2724
2725 assert %{"id" => ^id_str, "pinned" => false} =
2726 conn
2727 |> assign(:user, user)
2728 |> post("/api/v1/statuses/#{activity.id}/unpin")
2729 |> json_response(200)
2730
2731 assert [] =
2732 conn
2733 |> assign(:user, user)
2734 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
2735 |> json_response(200)
2736 end
2737
2738 test "/unpin: returns 400 error when activity is not exist", %{conn: conn, user: user} do
2739 conn =
2740 conn
2741 |> assign(:user, user)
2742 |> post("/api/v1/statuses/1/unpin")
2743
2744 assert json_response(conn, 400) == %{"error" => "Could not unpin"}
2745 end
2746
2747 test "max pinned statuses", %{conn: conn, user: user, activity: activity_one} do
2748 {:ok, activity_two} = CommonAPI.post(user, %{"status" => "HI!!!"})
2749
2750 id_str_one = to_string(activity_one.id)
2751
2752 assert %{"id" => ^id_str_one, "pinned" => true} =
2753 conn
2754 |> assign(:user, user)
2755 |> post("/api/v1/statuses/#{id_str_one}/pin")
2756 |> json_response(200)
2757
2758 user = refresh_record(user)
2759
2760 assert %{"error" => "You have already pinned the maximum number of statuses"} =
2761 conn
2762 |> assign(:user, user)
2763 |> post("/api/v1/statuses/#{activity_two.id}/pin")
2764 |> json_response(400)
2765 end
2766 end
2767
2768 describe "cards" do
2769 setup do
2770 Config.put([:rich_media, :enabled], true)
2771
2772 on_exit(fn ->
2773 Config.put([:rich_media, :enabled], false)
2774 end)
2775
2776 user = insert(:user)
2777 %{user: user}
2778 end
2779
2780 test "returns rich-media card", %{conn: conn, user: user} do
2781 {:ok, activity} = CommonAPI.post(user, %{"status" => "https://example.com/ogp"})
2782
2783 card_data = %{
2784 "image" => "http://ia.media-imdb.com/images/rock.jpg",
2785 "provider_name" => "example.com",
2786 "provider_url" => "https://example.com",
2787 "title" => "The Rock",
2788 "type" => "link",
2789 "url" => "https://example.com/ogp",
2790 "description" =>
2791 "Directed by Michael Bay. With Sean Connery, Nicolas Cage, Ed Harris, John Spencer.",
2792 "pleroma" => %{
2793 "opengraph" => %{
2794 "image" => "http://ia.media-imdb.com/images/rock.jpg",
2795 "title" => "The Rock",
2796 "type" => "video.movie",
2797 "url" => "https://example.com/ogp",
2798 "description" =>
2799 "Directed by Michael Bay. With Sean Connery, Nicolas Cage, Ed Harris, John Spencer."
2800 }
2801 }
2802 }
2803
2804 response =
2805 conn
2806 |> get("/api/v1/statuses/#{activity.id}/card")
2807 |> json_response(200)
2808
2809 assert response == card_data
2810
2811 # works with private posts
2812 {:ok, activity} =
2813 CommonAPI.post(user, %{"status" => "https://example.com/ogp", "visibility" => "direct"})
2814
2815 response_two =
2816 conn
2817 |> assign(:user, user)
2818 |> get("/api/v1/statuses/#{activity.id}/card")
2819 |> json_response(200)
2820
2821 assert response_two == card_data
2822 end
2823
2824 test "replaces missing description with an empty string", %{conn: conn, user: user} do
2825 {:ok, activity} =
2826 CommonAPI.post(user, %{"status" => "https://example.com/ogp-missing-data"})
2827
2828 response =
2829 conn
2830 |> get("/api/v1/statuses/#{activity.id}/card")
2831 |> json_response(:ok)
2832
2833 assert response == %{
2834 "type" => "link",
2835 "title" => "Pleroma",
2836 "description" => "",
2837 "image" => nil,
2838 "provider_name" => "example.com",
2839 "provider_url" => "https://example.com",
2840 "url" => "https://example.com/ogp-missing-data",
2841 "pleroma" => %{
2842 "opengraph" => %{
2843 "title" => "Pleroma",
2844 "type" => "website",
2845 "url" => "https://example.com/ogp-missing-data"
2846 }
2847 }
2848 }
2849 end
2850 end
2851
2852 test "bookmarks" do
2853 user = insert(:user)
2854 for_user = insert(:user)
2855
2856 {:ok, activity1} =
2857 CommonAPI.post(user, %{
2858 "status" => "heweoo?"
2859 })
2860
2861 {:ok, activity2} =
2862 CommonAPI.post(user, %{
2863 "status" => "heweoo!"
2864 })
2865
2866 response1 =
2867 build_conn()
2868 |> assign(:user, for_user)
2869 |> post("/api/v1/statuses/#{activity1.id}/bookmark")
2870
2871 assert json_response(response1, 200)["bookmarked"] == true
2872
2873 response2 =
2874 build_conn()
2875 |> assign(:user, for_user)
2876 |> post("/api/v1/statuses/#{activity2.id}/bookmark")
2877
2878 assert json_response(response2, 200)["bookmarked"] == true
2879
2880 bookmarks =
2881 build_conn()
2882 |> assign(:user, for_user)
2883 |> get("/api/v1/bookmarks")
2884
2885 assert [json_response(response2, 200), json_response(response1, 200)] ==
2886 json_response(bookmarks, 200)
2887
2888 response1 =
2889 build_conn()
2890 |> assign(:user, for_user)
2891 |> post("/api/v1/statuses/#{activity1.id}/unbookmark")
2892
2893 assert json_response(response1, 200)["bookmarked"] == false
2894
2895 bookmarks =
2896 build_conn()
2897 |> assign(:user, for_user)
2898 |> get("/api/v1/bookmarks")
2899
2900 assert [json_response(response2, 200)] == json_response(bookmarks, 200)
2901 end
2902
2903 describe "conversation muting" do
2904 setup do
2905 post_user = insert(:user)
2906 user = insert(:user)
2907
2908 {:ok, activity} = CommonAPI.post(post_user, %{"status" => "HIE"})
2909
2910 [user: user, activity: activity]
2911 end
2912
2913 test "mute conversation", %{conn: conn, user: user, activity: activity} do
2914 id_str = to_string(activity.id)
2915
2916 assert %{"id" => ^id_str, "muted" => true} =
2917 conn
2918 |> assign(:user, user)
2919 |> post("/api/v1/statuses/#{activity.id}/mute")
2920 |> json_response(200)
2921 end
2922
2923 test "cannot mute already muted conversation", %{conn: conn, user: user, activity: activity} do
2924 {:ok, _} = CommonAPI.add_mute(user, activity)
2925
2926 conn =
2927 conn
2928 |> assign(:user, user)
2929 |> post("/api/v1/statuses/#{activity.id}/mute")
2930
2931 assert json_response(conn, 400) == %{"error" => "conversation is already muted"}
2932 end
2933
2934 test "unmute conversation", %{conn: conn, user: user, activity: activity} do
2935 {:ok, _} = CommonAPI.add_mute(user, activity)
2936
2937 id_str = to_string(activity.id)
2938 user = refresh_record(user)
2939
2940 assert %{"id" => ^id_str, "muted" => false} =
2941 conn
2942 |> assign(:user, user)
2943 |> post("/api/v1/statuses/#{activity.id}/unmute")
2944 |> json_response(200)
2945 end
2946 end
2947
2948 describe "reports" do
2949 setup do
2950 reporter = insert(:user)
2951 target_user = insert(:user)
2952
2953 {:ok, activity} = CommonAPI.post(target_user, %{"status" => "foobar"})
2954
2955 [reporter: reporter, target_user: target_user, activity: activity]
2956 end
2957
2958 test "submit a basic report", %{conn: conn, reporter: reporter, target_user: target_user} do
2959 assert %{"action_taken" => false, "id" => _} =
2960 conn
2961 |> assign(:user, reporter)
2962 |> post("/api/v1/reports", %{"account_id" => target_user.id})
2963 |> json_response(200)
2964 end
2965
2966 test "submit a report with statuses and comment", %{
2967 conn: conn,
2968 reporter: reporter,
2969 target_user: target_user,
2970 activity: activity
2971 } do
2972 assert %{"action_taken" => false, "id" => _} =
2973 conn
2974 |> assign(:user, reporter)
2975 |> post("/api/v1/reports", %{
2976 "account_id" => target_user.id,
2977 "status_ids" => [activity.id],
2978 "comment" => "bad status!",
2979 "forward" => "false"
2980 })
2981 |> json_response(200)
2982 end
2983
2984 test "account_id is required", %{
2985 conn: conn,
2986 reporter: reporter,
2987 activity: activity
2988 } do
2989 assert %{"error" => "Valid `account_id` required"} =
2990 conn
2991 |> assign(:user, reporter)
2992 |> post("/api/v1/reports", %{"status_ids" => [activity.id]})
2993 |> json_response(400)
2994 end
2995
2996 test "comment must be up to the size specified in the config", %{
2997 conn: conn,
2998 reporter: reporter,
2999 target_user: target_user
3000 } do
3001 max_size = Config.get([:instance, :max_report_comment_size], 1000)
3002 comment = String.pad_trailing("a", max_size + 1, "a")
3003
3004 error = %{"error" => "Comment must be up to #{max_size} characters"}
3005
3006 assert ^error =
3007 conn
3008 |> assign(:user, reporter)
3009 |> post("/api/v1/reports", %{"account_id" => target_user.id, "comment" => comment})
3010 |> json_response(400)
3011 end
3012
3013 test "returns error when account is not exist", %{
3014 conn: conn,
3015 reporter: reporter,
3016 activity: activity
3017 } do
3018 conn =
3019 conn
3020 |> assign(:user, reporter)
3021 |> post("/api/v1/reports", %{"status_ids" => [activity.id], "account_id" => "foo"})
3022
3023 assert json_response(conn, 400) == %{"error" => "Account not found"}
3024 end
3025 end
3026
3027 describe "link headers" do
3028 test "preserves parameters in link headers", %{conn: conn} do
3029 user = insert(:user)
3030 other_user = insert(:user)
3031
3032 {:ok, activity1} =
3033 CommonAPI.post(other_user, %{
3034 "status" => "hi @#{user.nickname}",
3035 "visibility" => "public"
3036 })
3037
3038 {:ok, activity2} =
3039 CommonAPI.post(other_user, %{
3040 "status" => "hi @#{user.nickname}",
3041 "visibility" => "public"
3042 })
3043
3044 notification1 = Repo.get_by(Notification, activity_id: activity1.id)
3045 notification2 = Repo.get_by(Notification, activity_id: activity2.id)
3046
3047 conn =
3048 conn
3049 |> assign(:user, user)
3050 |> get("/api/v1/notifications", %{media_only: true})
3051
3052 assert [link_header] = get_resp_header(conn, "link")
3053 assert link_header =~ ~r/media_only=true/
3054 assert link_header =~ ~r/min_id=#{notification2.id}/
3055 assert link_header =~ ~r/max_id=#{notification1.id}/
3056 end
3057 end
3058
3059 test "accounts fetches correct account for nicknames beginning with numbers", %{conn: conn} do
3060 # Need to set an old-style integer ID to reproduce the problem
3061 # (these are no longer assigned to new accounts but were preserved
3062 # for existing accounts during the migration to flakeIDs)
3063 user_one = insert(:user, %{id: 1212})
3064 user_two = insert(:user, %{nickname: "#{user_one.id}garbage"})
3065
3066 resp_one =
3067 conn
3068 |> get("/api/v1/accounts/#{user_one.id}")
3069
3070 resp_two =
3071 conn
3072 |> get("/api/v1/accounts/#{user_two.nickname}")
3073
3074 resp_three =
3075 conn
3076 |> get("/api/v1/accounts/#{user_two.id}")
3077
3078 acc_one = json_response(resp_one, 200)
3079 acc_two = json_response(resp_two, 200)
3080 acc_three = json_response(resp_three, 200)
3081 refute acc_one == acc_two
3082 assert acc_two == acc_three
3083 end
3084
3085 describe "custom emoji" do
3086 test "with tags", %{conn: conn} do
3087 [emoji | _body] =
3088 conn
3089 |> get("/api/v1/custom_emojis")
3090 |> json_response(200)
3091
3092 assert Map.has_key?(emoji, "shortcode")
3093 assert Map.has_key?(emoji, "static_url")
3094 assert Map.has_key?(emoji, "tags")
3095 assert is_list(emoji["tags"])
3096 assert Map.has_key?(emoji, "category")
3097 assert Map.has_key?(emoji, "url")
3098 assert Map.has_key?(emoji, "visible_in_picker")
3099 end
3100 end
3101
3102 describe "index/2 redirections" do
3103 setup %{conn: conn} do
3104 session_opts = [
3105 store: :cookie,
3106 key: "_test",
3107 signing_salt: "cooldude"
3108 ]
3109
3110 conn =
3111 conn
3112 |> Plug.Session.call(Plug.Session.init(session_opts))
3113 |> fetch_session()
3114
3115 test_path = "/web/statuses/test"
3116 %{conn: conn, path: test_path}
3117 end
3118
3119 test "redirects not logged-in users to the login page", %{conn: conn, path: path} do
3120 conn = get(conn, path)
3121
3122 assert conn.status == 302
3123 assert redirected_to(conn) == "/web/login"
3124 end
3125
3126 test "redirects not logged-in users to the login page on private instances", %{
3127 conn: conn,
3128 path: path
3129 } do
3130 is_public = Config.get([:instance, :public])
3131 Config.put([:instance, :public], false)
3132
3133 conn = get(conn, path)
3134
3135 assert conn.status == 302
3136 assert redirected_to(conn) == "/web/login"
3137
3138 Config.put([:instance, :public], is_public)
3139 end
3140
3141 test "does not redirect logged in users to the login page", %{conn: conn, path: path} do
3142 token = insert(:oauth_token)
3143
3144 conn =
3145 conn
3146 |> assign(:user, token.user)
3147 |> put_session(:oauth_token, token.token)
3148 |> get(path)
3149
3150 assert conn.status == 200
3151 end
3152
3153 test "saves referer path to session", %{conn: conn, path: path} do
3154 conn = get(conn, path)
3155 return_to = Plug.Conn.get_session(conn, :return_to)
3156
3157 assert return_to == path
3158 end
3159
3160 test "redirects to the saved path after log in", %{conn: conn, path: path} do
3161 app = insert(:oauth_app, client_name: "Mastodon-Local", redirect_uris: ".")
3162 auth = insert(:oauth_authorization, app: app)
3163
3164 conn =
3165 conn
3166 |> put_session(:return_to, path)
3167 |> get("/web/login", %{code: auth.token})
3168
3169 assert conn.status == 302
3170 assert redirected_to(conn) == path
3171 end
3172
3173 test "redirects to the getting-started page when referer is not present", %{conn: conn} do
3174 app = insert(:oauth_app, client_name: "Mastodon-Local", redirect_uris: ".")
3175 auth = insert(:oauth_authorization, app: app)
3176
3177 conn = get(conn, "/web/login", %{code: auth.token})
3178
3179 assert conn.status == 302
3180 assert redirected_to(conn) == "/web/getting-started"
3181 end
3182 end
3183
3184 describe "scheduled activities" do
3185 test "creates a scheduled activity", %{conn: conn} do
3186 user = insert(:user)
3187 scheduled_at = NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond)
3188
3189 conn =
3190 conn
3191 |> assign(:user, user)
3192 |> post("/api/v1/statuses", %{
3193 "status" => "scheduled",
3194 "scheduled_at" => scheduled_at
3195 })
3196
3197 assert %{"scheduled_at" => expected_scheduled_at} = json_response(conn, 200)
3198 assert expected_scheduled_at == Pleroma.Web.CommonAPI.Utils.to_masto_date(scheduled_at)
3199 assert [] == Repo.all(Activity)
3200 end
3201
3202 test "creates a scheduled activity with a media attachment", %{conn: conn} do
3203 user = insert(:user)
3204 scheduled_at = NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond)
3205
3206 file = %Plug.Upload{
3207 content_type: "image/jpg",
3208 path: Path.absname("test/fixtures/image.jpg"),
3209 filename: "an_image.jpg"
3210 }
3211
3212 {:ok, upload} = ActivityPub.upload(file, actor: user.ap_id)
3213
3214 conn =
3215 conn
3216 |> assign(:user, user)
3217 |> post("/api/v1/statuses", %{
3218 "media_ids" => [to_string(upload.id)],
3219 "status" => "scheduled",
3220 "scheduled_at" => scheduled_at
3221 })
3222
3223 assert %{"media_attachments" => [media_attachment]} = json_response(conn, 200)
3224 assert %{"type" => "image"} = media_attachment
3225 end
3226
3227 test "skips the scheduling and creates the activity if scheduled_at is earlier than 5 minutes from now",
3228 %{conn: conn} do
3229 user = insert(:user)
3230
3231 scheduled_at =
3232 NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(5) - 1, :millisecond)
3233
3234 conn =
3235 conn
3236 |> assign(:user, user)
3237 |> post("/api/v1/statuses", %{
3238 "status" => "not scheduled",
3239 "scheduled_at" => scheduled_at
3240 })
3241
3242 assert %{"content" => "not scheduled"} = json_response(conn, 200)
3243 assert [] == Repo.all(ScheduledActivity)
3244 end
3245
3246 test "returns error when daily user limit is exceeded", %{conn: conn} do
3247 user = insert(:user)
3248
3249 today =
3250 NaiveDateTime.utc_now()
3251 |> NaiveDateTime.add(:timer.minutes(6), :millisecond)
3252 |> NaiveDateTime.to_iso8601()
3253
3254 attrs = %{params: %{}, scheduled_at: today}
3255 {:ok, _} = ScheduledActivity.create(user, attrs)
3256 {:ok, _} = ScheduledActivity.create(user, attrs)
3257
3258 conn =
3259 conn
3260 |> assign(:user, user)
3261 |> post("/api/v1/statuses", %{"status" => "scheduled", "scheduled_at" => today})
3262
3263 assert %{"error" => "daily limit exceeded"} == json_response(conn, 422)
3264 end
3265
3266 test "returns error when total user limit is exceeded", %{conn: conn} do
3267 user = insert(:user)
3268
3269 today =
3270 NaiveDateTime.utc_now()
3271 |> NaiveDateTime.add(:timer.minutes(6), :millisecond)
3272 |> NaiveDateTime.to_iso8601()
3273
3274 tomorrow =
3275 NaiveDateTime.utc_now()
3276 |> NaiveDateTime.add(:timer.hours(36), :millisecond)
3277 |> NaiveDateTime.to_iso8601()
3278
3279 attrs = %{params: %{}, scheduled_at: today}
3280 {:ok, _} = ScheduledActivity.create(user, attrs)
3281 {:ok, _} = ScheduledActivity.create(user, attrs)
3282 {:ok, _} = ScheduledActivity.create(user, %{params: %{}, scheduled_at: tomorrow})
3283
3284 conn =
3285 conn
3286 |> assign(:user, user)
3287 |> post("/api/v1/statuses", %{"status" => "scheduled", "scheduled_at" => tomorrow})
3288
3289 assert %{"error" => "total limit exceeded"} == json_response(conn, 422)
3290 end
3291
3292 test "shows scheduled activities", %{conn: conn} do
3293 user = insert(:user)
3294 scheduled_activity_id1 = insert(:scheduled_activity, user: user).id |> to_string()
3295 scheduled_activity_id2 = insert(:scheduled_activity, user: user).id |> to_string()
3296 scheduled_activity_id3 = insert(:scheduled_activity, user: user).id |> to_string()
3297 scheduled_activity_id4 = insert(:scheduled_activity, user: user).id |> to_string()
3298
3299 conn =
3300 conn
3301 |> assign(:user, user)
3302
3303 # min_id
3304 conn_res =
3305 conn
3306 |> get("/api/v1/scheduled_statuses?limit=2&min_id=#{scheduled_activity_id1}")
3307
3308 result = json_response(conn_res, 200)
3309 assert [%{"id" => ^scheduled_activity_id3}, %{"id" => ^scheduled_activity_id2}] = result
3310
3311 # since_id
3312 conn_res =
3313 conn
3314 |> get("/api/v1/scheduled_statuses?limit=2&since_id=#{scheduled_activity_id1}")
3315
3316 result = json_response(conn_res, 200)
3317 assert [%{"id" => ^scheduled_activity_id4}, %{"id" => ^scheduled_activity_id3}] = result
3318
3319 # max_id
3320 conn_res =
3321 conn
3322 |> get("/api/v1/scheduled_statuses?limit=2&max_id=#{scheduled_activity_id4}")
3323
3324 result = json_response(conn_res, 200)
3325 assert [%{"id" => ^scheduled_activity_id3}, %{"id" => ^scheduled_activity_id2}] = result
3326 end
3327
3328 test "shows a scheduled activity", %{conn: conn} do
3329 user = insert(:user)
3330 scheduled_activity = insert(:scheduled_activity, user: user)
3331
3332 res_conn =
3333 conn
3334 |> assign(:user, user)
3335 |> get("/api/v1/scheduled_statuses/#{scheduled_activity.id}")
3336
3337 assert %{"id" => scheduled_activity_id} = json_response(res_conn, 200)
3338 assert scheduled_activity_id == scheduled_activity.id |> to_string()
3339
3340 res_conn =
3341 conn
3342 |> assign(:user, user)
3343 |> get("/api/v1/scheduled_statuses/404")
3344
3345 assert %{"error" => "Record not found"} = json_response(res_conn, 404)
3346 end
3347
3348 test "updates a scheduled activity", %{conn: conn} do
3349 user = insert(:user)
3350 scheduled_activity = insert(:scheduled_activity, user: user)
3351
3352 new_scheduled_at =
3353 NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond)
3354
3355 res_conn =
3356 conn
3357 |> assign(:user, user)
3358 |> put("/api/v1/scheduled_statuses/#{scheduled_activity.id}", %{
3359 scheduled_at: new_scheduled_at
3360 })
3361
3362 assert %{"scheduled_at" => expected_scheduled_at} = json_response(res_conn, 200)
3363 assert expected_scheduled_at == Pleroma.Web.CommonAPI.Utils.to_masto_date(new_scheduled_at)
3364
3365 res_conn =
3366 conn
3367 |> assign(:user, user)
3368 |> put("/api/v1/scheduled_statuses/404", %{scheduled_at: new_scheduled_at})
3369
3370 assert %{"error" => "Record not found"} = json_response(res_conn, 404)
3371 end
3372
3373 test "deletes a scheduled activity", %{conn: conn} do
3374 user = insert(:user)
3375 scheduled_activity = insert(:scheduled_activity, user: user)
3376
3377 res_conn =
3378 conn
3379 |> assign(:user, user)
3380 |> delete("/api/v1/scheduled_statuses/#{scheduled_activity.id}")
3381
3382 assert %{} = json_response(res_conn, 200)
3383 assert nil == Repo.get(ScheduledActivity, scheduled_activity.id)
3384
3385 res_conn =
3386 conn
3387 |> assign(:user, user)
3388 |> delete("/api/v1/scheduled_statuses/#{scheduled_activity.id}")
3389
3390 assert %{"error" => "Record not found"} = json_response(res_conn, 404)
3391 end
3392 end
3393
3394 test "Repeated posts that are replies incorrectly have in_reply_to_id null", %{conn: conn} do
3395 user1 = insert(:user)
3396 user2 = insert(:user)
3397 user3 = insert(:user)
3398
3399 {:ok, replied_to} = CommonAPI.post(user1, %{"status" => "cofe"})
3400
3401 # Reply to status from another user
3402 conn1 =
3403 conn
3404 |> assign(:user, user2)
3405 |> post("/api/v1/statuses", %{"status" => "xD", "in_reply_to_id" => replied_to.id})
3406
3407 assert %{"content" => "xD", "id" => id} = json_response(conn1, 200)
3408
3409 activity = Activity.get_by_id_with_object(id)
3410
3411 assert Object.normalize(activity).data["inReplyTo"] == Object.normalize(replied_to).data["id"]
3412 assert Activity.get_in_reply_to_activity(activity).id == replied_to.id
3413
3414 # Reblog from the third user
3415 conn2 =
3416 conn
3417 |> assign(:user, user3)
3418 |> post("/api/v1/statuses/#{activity.id}/reblog")
3419
3420 assert %{"reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 1}} =
3421 json_response(conn2, 200)
3422
3423 assert to_string(activity.id) == id
3424
3425 # Getting third user status
3426 conn3 =
3427 conn
3428 |> assign(:user, user3)
3429 |> get("api/v1/timelines/home")
3430
3431 [reblogged_activity] = json_response(conn3, 200)
3432
3433 assert reblogged_activity["reblog"]["in_reply_to_id"] == replied_to.id
3434
3435 replied_to_user = User.get_by_ap_id(replied_to.data["actor"])
3436 assert reblogged_activity["reblog"]["in_reply_to_account_id"] == replied_to_user.id
3437 end
3438
3439 describe "create account by app" do
3440 test "Account registration via Application", %{conn: conn} do
3441 conn =
3442 conn
3443 |> post("/api/v1/apps", %{
3444 client_name: "client_name",
3445 redirect_uris: "urn:ietf:wg:oauth:2.0:oob",
3446 scopes: "read, write, follow"
3447 })
3448
3449 %{
3450 "client_id" => client_id,
3451 "client_secret" => client_secret,
3452 "id" => _,
3453 "name" => "client_name",
3454 "redirect_uri" => "urn:ietf:wg:oauth:2.0:oob",
3455 "vapid_key" => _,
3456 "website" => nil
3457 } = json_response(conn, 200)
3458
3459 conn =
3460 conn
3461 |> post("/oauth/token", %{
3462 grant_type: "client_credentials",
3463 client_id: client_id,
3464 client_secret: client_secret
3465 })
3466
3467 assert %{"access_token" => token, "refresh_token" => refresh, "scope" => scope} =
3468 json_response(conn, 200)
3469
3470 assert token
3471 token_from_db = Repo.get_by(Token, token: token)
3472 assert token_from_db
3473 assert refresh
3474 assert scope == "read write follow"
3475
3476 conn =
3477 build_conn()
3478 |> put_req_header("authorization", "Bearer " <> token)
3479 |> post("/api/v1/accounts", %{
3480 username: "lain",
3481 email: "lain@example.org",
3482 password: "PlzDontHackLain",
3483 agreement: true
3484 })
3485
3486 %{
3487 "access_token" => token,
3488 "created_at" => _created_at,
3489 "scope" => _scope,
3490 "token_type" => "Bearer"
3491 } = json_response(conn, 200)
3492
3493 token_from_db = Repo.get_by(Token, token: token)
3494 assert token_from_db
3495 token_from_db = Repo.preload(token_from_db, :user)
3496 assert token_from_db.user
3497
3498 assert token_from_db.user.info.confirmation_pending
3499 end
3500
3501 test "rate limit", %{conn: conn} do
3502 app_token = insert(:oauth_token, user: nil)
3503
3504 conn =
3505 put_req_header(conn, "authorization", "Bearer " <> app_token.token)
3506 |> Map.put(:remote_ip, {15, 15, 15, 15})
3507
3508 for i <- 1..5 do
3509 conn =
3510 conn
3511 |> post("/api/v1/accounts", %{
3512 username: "#{i}lain",
3513 email: "#{i}lain@example.org",
3514 password: "PlzDontHackLain",
3515 agreement: true
3516 })
3517
3518 %{
3519 "access_token" => token,
3520 "created_at" => _created_at,
3521 "scope" => _scope,
3522 "token_type" => "Bearer"
3523 } = json_response(conn, 200)
3524
3525 token_from_db = Repo.get_by(Token, token: token)
3526 assert token_from_db
3527 token_from_db = Repo.preload(token_from_db, :user)
3528 assert token_from_db.user
3529
3530 assert token_from_db.user.info.confirmation_pending
3531 end
3532
3533 conn =
3534 conn
3535 |> post("/api/v1/accounts", %{
3536 username: "6lain",
3537 email: "6lain@example.org",
3538 password: "PlzDontHackLain",
3539 agreement: true
3540 })
3541
3542 assert json_response(conn, :too_many_requests) == %{"error" => "Throttled"}
3543 end
3544 end
3545
3546 describe "GET /api/v1/polls/:id" do
3547 test "returns poll entity for object id", %{conn: conn} do
3548 user = insert(:user)
3549
3550 {:ok, activity} =
3551 CommonAPI.post(user, %{
3552 "status" => "Pleroma does",
3553 "poll" => %{"options" => ["what Mastodon't", "n't what Mastodoes"], "expires_in" => 20}
3554 })
3555
3556 object = Object.normalize(activity)
3557
3558 conn =
3559 conn
3560 |> assign(:user, user)
3561 |> get("/api/v1/polls/#{object.id}")
3562
3563 response = json_response(conn, 200)
3564 id = to_string(object.id)
3565 assert %{"id" => ^id, "expired" => false, "multiple" => false} = response
3566 end
3567
3568 test "does not expose polls for private statuses", %{conn: conn} do
3569 user = insert(:user)
3570 other_user = insert(:user)
3571
3572 {:ok, activity} =
3573 CommonAPI.post(user, %{
3574 "status" => "Pleroma does",
3575 "poll" => %{"options" => ["what Mastodon't", "n't what Mastodoes"], "expires_in" => 20},
3576 "visibility" => "private"
3577 })
3578
3579 object = Object.normalize(activity)
3580
3581 conn =
3582 conn
3583 |> assign(:user, other_user)
3584 |> get("/api/v1/polls/#{object.id}")
3585
3586 assert json_response(conn, 404)
3587 end
3588 end
3589
3590 describe "POST /api/v1/polls/:id/votes" do
3591 test "votes are added to the poll", %{conn: conn} do
3592 user = insert(:user)
3593 other_user = insert(:user)
3594
3595 {:ok, activity} =
3596 CommonAPI.post(user, %{
3597 "status" => "A very delicious sandwich",
3598 "poll" => %{
3599 "options" => ["Lettuce", "Grilled Bacon", "Tomato"],
3600 "expires_in" => 20,
3601 "multiple" => true
3602 }
3603 })
3604
3605 object = Object.normalize(activity)
3606
3607 conn =
3608 conn
3609 |> assign(:user, other_user)
3610 |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [0, 1, 2]})
3611
3612 assert json_response(conn, 200)
3613 object = Object.get_by_id(object.id)
3614
3615 assert Enum.all?(object.data["anyOf"], fn %{"replies" => %{"totalItems" => total_items}} ->
3616 total_items == 1
3617 end)
3618 end
3619
3620 test "author can't vote", %{conn: conn} do
3621 user = insert(:user)
3622
3623 {:ok, activity} =
3624 CommonAPI.post(user, %{
3625 "status" => "Am I cute?",
3626 "poll" => %{"options" => ["Yes", "No"], "expires_in" => 20}
3627 })
3628
3629 object = Object.normalize(activity)
3630
3631 assert conn
3632 |> assign(:user, user)
3633 |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [1]})
3634 |> json_response(422) == %{"error" => "Poll's author can't vote"}
3635
3636 object = Object.get_by_id(object.id)
3637
3638 refute Enum.at(object.data["oneOf"], 1)["replies"]["totalItems"] == 1
3639 end
3640
3641 test "does not allow multiple choices on a single-choice question", %{conn: conn} do
3642 user = insert(:user)
3643 other_user = insert(:user)
3644
3645 {:ok, activity} =
3646 CommonAPI.post(user, %{
3647 "status" => "The glass is",
3648 "poll" => %{"options" => ["half empty", "half full"], "expires_in" => 20}
3649 })
3650
3651 object = Object.normalize(activity)
3652
3653 assert conn
3654 |> assign(:user, other_user)
3655 |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [0, 1]})
3656 |> json_response(422) == %{"error" => "Too many choices"}
3657
3658 object = Object.get_by_id(object.id)
3659
3660 refute Enum.any?(object.data["oneOf"], fn %{"replies" => %{"totalItems" => total_items}} ->
3661 total_items == 1
3662 end)
3663 end
3664
3665 test "does not allow choice index to be greater than options count", %{conn: conn} do
3666 user = insert(:user)
3667 other_user = insert(:user)
3668
3669 {:ok, activity} =
3670 CommonAPI.post(user, %{
3671 "status" => "Am I cute?",
3672 "poll" => %{"options" => ["Yes", "No"], "expires_in" => 20}
3673 })
3674
3675 object = Object.normalize(activity)
3676
3677 conn =
3678 conn
3679 |> assign(:user, other_user)
3680 |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [2]})
3681
3682 assert json_response(conn, 422) == %{"error" => "Invalid indices"}
3683 end
3684
3685 test "returns 404 error when object is not exist", %{conn: conn} do
3686 user = insert(:user)
3687
3688 conn =
3689 conn
3690 |> assign(:user, user)
3691 |> post("/api/v1/polls/1/votes", %{"choices" => [0]})
3692
3693 assert json_response(conn, 404) == %{"error" => "Record not found"}
3694 end
3695
3696 test "returns 404 when poll is private and not available for user", %{conn: conn} do
3697 user = insert(:user)
3698 other_user = insert(:user)
3699
3700 {:ok, activity} =
3701 CommonAPI.post(user, %{
3702 "status" => "Am I cute?",
3703 "poll" => %{"options" => ["Yes", "No"], "expires_in" => 20},
3704 "visibility" => "private"
3705 })
3706
3707 object = Object.normalize(activity)
3708
3709 conn =
3710 conn
3711 |> assign(:user, other_user)
3712 |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [0]})
3713
3714 assert json_response(conn, 404) == %{"error" => "Record not found"}
3715 end
3716 end
3717
3718 describe "GET /api/v1/statuses/:id/favourited_by" do
3719 setup do
3720 user = insert(:user)
3721 {:ok, activity} = CommonAPI.post(user, %{"status" => "test"})
3722
3723 conn =
3724 build_conn()
3725 |> assign(:user, user)
3726
3727 [conn: conn, activity: activity]
3728 end
3729
3730 test "returns users who have favorited the status", %{conn: conn, activity: activity} do
3731 other_user = insert(:user)
3732 {:ok, _, _} = CommonAPI.favorite(activity.id, other_user)
3733
3734 response =
3735 conn
3736 |> get("/api/v1/statuses/#{activity.id}/favourited_by")
3737 |> json_response(:ok)
3738
3739 [%{"id" => id}] = response
3740
3741 assert id == other_user.id
3742 end
3743
3744 test "returns empty array when status has not been favorited yet", %{
3745 conn: conn,
3746 activity: activity
3747 } do
3748 response =
3749 conn
3750 |> get("/api/v1/statuses/#{activity.id}/favourited_by")
3751 |> json_response(:ok)
3752
3753 assert Enum.empty?(response)
3754 end
3755
3756 test "does not return users who have favorited the status but are blocked", %{
3757 conn: %{assigns: %{user: user}} = conn,
3758 activity: activity
3759 } do
3760 other_user = insert(:user)
3761 {:ok, user} = User.block(user, other_user)
3762
3763 {:ok, _, _} = CommonAPI.favorite(activity.id, other_user)
3764
3765 response =
3766 conn
3767 |> assign(:user, user)
3768 |> get("/api/v1/statuses/#{activity.id}/favourited_by")
3769 |> json_response(:ok)
3770
3771 assert Enum.empty?(response)
3772 end
3773
3774 test "does not fail on an unauthenticated request", %{conn: conn, activity: activity} do
3775 other_user = insert(:user)
3776 {:ok, _, _} = CommonAPI.favorite(activity.id, other_user)
3777
3778 response =
3779 conn
3780 |> assign(:user, nil)
3781 |> get("/api/v1/statuses/#{activity.id}/favourited_by")
3782 |> json_response(:ok)
3783
3784 [%{"id" => id}] = response
3785 assert id == other_user.id
3786 end
3787 end
3788
3789 describe "GET /api/v1/statuses/:id/reblogged_by" do
3790 setup do
3791 user = insert(:user)
3792 {:ok, activity} = CommonAPI.post(user, %{"status" => "test"})
3793
3794 conn =
3795 build_conn()
3796 |> assign(:user, user)
3797
3798 [conn: conn, activity: activity]
3799 end
3800
3801 test "returns users who have reblogged the status", %{conn: conn, activity: activity} do
3802 other_user = insert(:user)
3803 {:ok, _, _} = CommonAPI.repeat(activity.id, other_user)
3804
3805 response =
3806 conn
3807 |> get("/api/v1/statuses/#{activity.id}/reblogged_by")
3808 |> json_response(:ok)
3809
3810 [%{"id" => id}] = response
3811
3812 assert id == other_user.id
3813 end
3814
3815 test "returns empty array when status has not been reblogged yet", %{
3816 conn: conn,
3817 activity: activity
3818 } do
3819 response =
3820 conn
3821 |> get("/api/v1/statuses/#{activity.id}/reblogged_by")
3822 |> json_response(:ok)
3823
3824 assert Enum.empty?(response)
3825 end
3826
3827 test "does not return users who have reblogged the status but are blocked", %{
3828 conn: %{assigns: %{user: user}} = conn,
3829 activity: activity
3830 } do
3831 other_user = insert(:user)
3832 {:ok, user} = User.block(user, other_user)
3833
3834 {:ok, _, _} = CommonAPI.repeat(activity.id, other_user)
3835
3836 response =
3837 conn
3838 |> assign(:user, user)
3839 |> get("/api/v1/statuses/#{activity.id}/reblogged_by")
3840 |> json_response(:ok)
3841
3842 assert Enum.empty?(response)
3843 end
3844
3845 test "does not fail on an unauthenticated request", %{conn: conn, activity: activity} do
3846 other_user = insert(:user)
3847 {:ok, _, _} = CommonAPI.repeat(activity.id, other_user)
3848
3849 response =
3850 conn
3851 |> assign(:user, nil)
3852 |> get("/api/v1/statuses/#{activity.id}/reblogged_by")
3853 |> json_response(:ok)
3854
3855 [%{"id" => id}] = response
3856 assert id == other_user.id
3857 end
3858 end
3859
3860 describe "POST /auth/password, with valid parameters" do
3861 setup %{conn: conn} do
3862 user = insert(:user)
3863 conn = post(conn, "/auth/password?email=#{user.email}")
3864 %{conn: conn, user: user}
3865 end
3866
3867 test "it returns 204", %{conn: conn} do
3868 assert json_response(conn, :no_content)
3869 end
3870
3871 test "it creates a PasswordResetToken record for user", %{user: user} do
3872 token_record = Repo.get_by(Pleroma.PasswordResetToken, user_id: user.id)
3873 assert token_record
3874 end
3875
3876 test "it sends an email to user", %{user: user} do
3877 token_record = Repo.get_by(Pleroma.PasswordResetToken, user_id: user.id)
3878
3879 email = Pleroma.Emails.UserEmail.password_reset_email(user, token_record.token)
3880 notify_email = Config.get([:instance, :notify_email])
3881 instance_name = Config.get([:instance, :name])
3882
3883 assert_email_sent(
3884 from: {instance_name, notify_email},
3885 to: {user.name, user.email},
3886 html_body: email.html_body
3887 )
3888 end
3889 end
3890
3891 describe "POST /auth/password, with invalid parameters" do
3892 setup do
3893 user = insert(:user)
3894 {:ok, user: user}
3895 end
3896
3897 test "it returns 404 when user is not found", %{conn: conn, user: user} do
3898 conn = post(conn, "/auth/password?email=nonexisting_#{user.email}")
3899 assert conn.status == 404
3900 assert conn.resp_body == ""
3901 end
3902
3903 test "it returns 400 when user is not local", %{conn: conn, user: user} do
3904 {:ok, user} = Repo.update(Changeset.change(user, local: false))
3905 conn = post(conn, "/auth/password?email=#{user.email}")
3906 assert conn.status == 400
3907 assert conn.resp_body == ""
3908 end
3909 end
3910
3911 describe "POST /api/v1/pleroma/accounts/confirmation_resend" do
3912 setup do
3913 setting = Config.get([:instance, :account_activation_required])
3914
3915 unless setting do
3916 Config.put([:instance, :account_activation_required], true)
3917 on_exit(fn -> Config.put([:instance, :account_activation_required], setting) end)
3918 end
3919
3920 user = insert(:user)
3921 info_change = User.Info.confirmation_changeset(user.info, need_confirmation: true)
3922
3923 {:ok, user} =
3924 user
3925 |> Changeset.change()
3926 |> Changeset.put_embed(:info, info_change)
3927 |> Repo.update()
3928
3929 assert user.info.confirmation_pending
3930
3931 [user: user]
3932 end
3933
3934 test "resend account confirmation email", %{conn: conn, user: user} do
3935 conn
3936 |> assign(:user, user)
3937 |> post("/api/v1/pleroma/accounts/confirmation_resend?email=#{user.email}")
3938 |> json_response(:no_content)
3939
3940 email = Pleroma.Emails.UserEmail.account_confirmation_email(user)
3941 notify_email = Config.get([:instance, :notify_email])
3942 instance_name = Config.get([:instance, :name])
3943
3944 assert_email_sent(
3945 from: {instance_name, notify_email},
3946 to: {user.name, user.email},
3947 html_body: email.html_body
3948 )
3949 end
3950 end
3951
3952 describe "GET /api/v1/suggestions" do
3953 setup do
3954 user = insert(:user)
3955 other_user = insert(:user)
3956 config = Config.get(:suggestions)
3957 on_exit(fn -> Config.put(:suggestions, config) end)
3958
3959 host = Config.get([Pleroma.Web.Endpoint, :url, :host])
3960 url500 = "http://test500?#{host}&#{user.nickname}"
3961 url200 = "http://test200?#{host}&#{user.nickname}"
3962
3963 mock(fn
3964 %{method: :get, url: ^url500} ->
3965 %Tesla.Env{status: 500, body: "bad request"}
3966
3967 %{method: :get, url: ^url200} ->
3968 %Tesla.Env{
3969 status: 200,
3970 body:
3971 ~s([{"acct":"yj455","avatar":"https://social.heldscal.la/avatar/201.jpeg","avatar_static":"https://social.heldscal.la/avatar/s/201.jpeg"}, {"acct":"#{
3972 other_user.ap_id
3973 }","avatar":"https://social.heldscal.la/avatar/202.jpeg","avatar_static":"https://social.heldscal.la/avatar/s/202.jpeg"}])
3974 }
3975 end)
3976
3977 [user: user, other_user: other_user]
3978 end
3979
3980 test "returns empty result when suggestions disabled", %{conn: conn, user: user} do
3981 Config.put([:suggestions, :enabled], false)
3982
3983 res =
3984 conn
3985 |> assign(:user, user)
3986 |> get("/api/v1/suggestions")
3987 |> json_response(200)
3988
3989 assert res == []
3990 end
3991
3992 test "returns error", %{conn: conn, user: user} do
3993 Config.put([:suggestions, :enabled], true)
3994 Config.put([:suggestions, :third_party_engine], "http://test500?{{host}}&{{user}}")
3995
3996 res =
3997 conn
3998 |> assign(:user, user)
3999 |> get("/api/v1/suggestions")
4000 |> json_response(500)
4001
4002 assert res == "Something went wrong"
4003 end
4004
4005 test "returns suggestions", %{conn: conn, user: user, other_user: other_user} do
4006 Config.put([:suggestions, :enabled], true)
4007 Config.put([:suggestions, :third_party_engine], "http://test200?{{host}}&{{user}}")
4008
4009 res =
4010 conn
4011 |> assign(:user, user)
4012 |> get("/api/v1/suggestions")
4013 |> json_response(200)
4014
4015 assert res == [
4016 %{
4017 "acct" => "yj455",
4018 "avatar" => "https://social.heldscal.la/avatar/201.jpeg",
4019 "avatar_static" => "https://social.heldscal.la/avatar/s/201.jpeg",
4020 "id" => 0
4021 },
4022 %{
4023 "acct" => other_user.ap_id,
4024 "avatar" => "https://social.heldscal.la/avatar/202.jpeg",
4025 "avatar_static" => "https://social.heldscal.la/avatar/s/202.jpeg",
4026 "id" => other_user.id
4027 }
4028 ]
4029 end
4030 end
4031 end