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