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