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