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