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