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