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