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