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