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