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