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