0f8860ec524d1747f9b8a946902f1e13fd9eb96d
[akkoma] / test / web / common_api / common_api_test.exs
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
5 defmodule Pleroma.Web.CommonAPITest do
6 use Pleroma.DataCase
7 alias Pleroma.Activity
8 alias Pleroma.Chat
9 alias Pleroma.Conversation.Participation
10 alias Pleroma.Object
11 alias Pleroma.User
12 alias Pleroma.Web.ActivityPub.ActivityPub
13 alias Pleroma.Web.ActivityPub.Visibility
14 alias Pleroma.Web.AdminAPI.AccountView
15 alias Pleroma.Web.CommonAPI
16
17 import Pleroma.Factory
18
19 require Pleroma.Constants
20
21 setup do: clear_config([:instance, :safe_dm_mentions])
22 setup do: clear_config([:instance, :limit])
23 setup do: clear_config([:instance, :max_pinned_statuses])
24
25 describe "posting chat messages" do
26 setup do: clear_config([:instance, :chat_limit])
27
28 test "it posts a chat message" do
29 author = insert(:user)
30 recipient = insert(:user)
31
32 {:ok, activity} =
33 CommonAPI.post_chat_message(
34 author,
35 recipient,
36 "a test message <script>alert('uuu')</script> :firefox:"
37 )
38
39 assert activity.data["type"] == "Create"
40 assert activity.local
41 object = Object.normalize(activity)
42
43 assert object.data["type"] == "ChatMessage"
44 assert object.data["to"] == [recipient.ap_id]
45
46 assert object.data["content"] ==
47 "a test message &lt;script&gt;alert(&#39;uuu&#39;)&lt;/script&gt; :firefox:"
48
49 assert object.data["emoji"] == %{
50 "firefox" => "http://localhost:4001/emoji/Firefox.gif"
51 }
52
53 assert Chat.get(author.id, recipient.ap_id)
54 assert Chat.get(recipient.id, author.ap_id)
55 end
56
57 test "it reject messages over the local limit" do
58 Pleroma.Config.put([:instance, :chat_limit], 2)
59
60 author = insert(:user)
61 recipient = insert(:user)
62
63 {:error, message} =
64 CommonAPI.post_chat_message(
65 author,
66 recipient,
67 "123"
68 )
69
70 assert message == :content_too_long
71 end
72 end
73
74 test "favoriting race condition" do
75 user = insert(:user)
76 users_serial = insert_list(10, :user)
77 users = insert_list(10, :user)
78
79 {:ok, activity} = CommonAPI.post(user, %{"status" => "."})
80
81 users_serial
82 |> Enum.map(fn user ->
83 CommonAPI.favorite(user, activity.id)
84 end)
85
86 object = Object.get_by_ap_id(activity.data["object"])
87 assert object.data["like_count"] == 10
88
89 users
90 |> Enum.map(fn user ->
91 Task.async(fn ->
92 CommonAPI.favorite(user, activity.id)
93 end)
94 end)
95 |> Enum.map(&Task.await/1)
96
97 object = Object.get_by_ap_id(activity.data["object"])
98 assert object.data["like_count"] == 20
99 end
100
101 test "when replying to a conversation / participation, it will set the correct context id even if no explicit reply_to is given" do
102 user = insert(:user)
103 {:ok, activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "direct"})
104
105 [participation] = Participation.for_user(user)
106
107 {:ok, convo_reply} =
108 CommonAPI.post(user, %{"status" => ".", "in_reply_to_conversation_id" => participation.id})
109
110 assert Visibility.is_direct?(convo_reply)
111
112 assert activity.data["context"] == convo_reply.data["context"]
113 end
114
115 test "when replying to a conversation / participation, it only mentions the recipients explicitly declared in the participation" do
116 har = insert(:user)
117 jafnhar = insert(:user)
118 tridi = insert(:user)
119
120 {:ok, activity} =
121 CommonAPI.post(har, %{
122 "status" => "@#{jafnhar.nickname} hey",
123 "visibility" => "direct"
124 })
125
126 assert har.ap_id in activity.recipients
127 assert jafnhar.ap_id in activity.recipients
128
129 [participation] = Participation.for_user(har)
130
131 {:ok, activity} =
132 CommonAPI.post(har, %{
133 "status" => "I don't really like @#{tridi.nickname}",
134 "visibility" => "direct",
135 "in_reply_to_status_id" => activity.id,
136 "in_reply_to_conversation_id" => participation.id
137 })
138
139 assert har.ap_id in activity.recipients
140 assert jafnhar.ap_id in activity.recipients
141 refute tridi.ap_id in activity.recipients
142 end
143
144 test "with the safe_dm_mention option set, it does not mention people beyond the initial tags" do
145 har = insert(:user)
146 jafnhar = insert(:user)
147 tridi = insert(:user)
148
149 Pleroma.Config.put([:instance, :safe_dm_mentions], true)
150
151 {:ok, activity} =
152 CommonAPI.post(har, %{
153 "status" => "@#{jafnhar.nickname} hey, i never want to see @#{tridi.nickname} again",
154 "visibility" => "direct"
155 })
156
157 refute tridi.ap_id in activity.recipients
158 assert jafnhar.ap_id in activity.recipients
159 end
160
161 test "it de-duplicates tags" do
162 user = insert(:user)
163 {:ok, activity} = CommonAPI.post(user, %{"status" => "#2hu #2HU"})
164
165 object = Object.normalize(activity)
166
167 assert object.data["tag"] == ["2hu"]
168 end
169
170 test "it adds emoji in the object" do
171 user = insert(:user)
172 {:ok, activity} = CommonAPI.post(user, %{"status" => ":firefox:"})
173
174 assert Object.normalize(activity).data["emoji"]["firefox"]
175 end
176
177 describe "posting" do
178 test "it supports explicit addressing" do
179 user = insert(:user)
180 user_two = insert(:user)
181 user_three = insert(:user)
182 user_four = insert(:user)
183
184 {:ok, activity} =
185 CommonAPI.post(user, %{
186 "status" =>
187 "Hey, I think @#{user_three.nickname} is ugly. @#{user_four.nickname} is alright though.",
188 "to" => [user_two.nickname, user_four.nickname, "nonexistent"]
189 })
190
191 assert user.ap_id in activity.recipients
192 assert user_two.ap_id in activity.recipients
193 assert user_four.ap_id in activity.recipients
194 refute user_three.ap_id in activity.recipients
195 end
196
197 test "it filters out obviously bad tags when accepting a post as HTML" do
198 user = insert(:user)
199
200 post = "<p><b>2hu</b></p><script>alert('xss')</script>"
201
202 {:ok, activity} =
203 CommonAPI.post(user, %{
204 "status" => post,
205 "content_type" => "text/html"
206 })
207
208 object = Object.normalize(activity)
209
210 assert object.data["content"] == "<p><b>2hu</b></p>alert(&#39;xss&#39;)"
211 end
212
213 test "it filters out obviously bad tags when accepting a post as Markdown" do
214 user = insert(:user)
215
216 post = "<p><b>2hu</b></p><script>alert('xss')</script>"
217
218 {:ok, activity} =
219 CommonAPI.post(user, %{
220 "status" => post,
221 "content_type" => "text/markdown"
222 })
223
224 object = Object.normalize(activity)
225
226 assert object.data["content"] == "<p><b>2hu</b></p>alert(&#39;xss&#39;)"
227 end
228
229 test "it does not allow replies to direct messages that are not direct messages themselves" do
230 user = insert(:user)
231
232 {:ok, activity} = CommonAPI.post(user, %{"status" => "suya..", "visibility" => "direct"})
233
234 assert {:ok, _} =
235 CommonAPI.post(user, %{
236 "status" => "suya..",
237 "visibility" => "direct",
238 "in_reply_to_status_id" => activity.id
239 })
240
241 Enum.each(["public", "private", "unlisted"], fn visibility ->
242 assert {:error, "The message visibility must be direct"} =
243 CommonAPI.post(user, %{
244 "status" => "suya..",
245 "visibility" => visibility,
246 "in_reply_to_status_id" => activity.id
247 })
248 end)
249 end
250
251 test "it allows to address a list" do
252 user = insert(:user)
253 {:ok, list} = Pleroma.List.create("foo", user)
254
255 {:ok, activity} =
256 CommonAPI.post(user, %{"status" => "foobar", "visibility" => "list:#{list.id}"})
257
258 assert activity.data["bcc"] == [list.ap_id]
259 assert activity.recipients == [list.ap_id, user.ap_id]
260 assert activity.data["listMessage"] == list.ap_id
261 end
262
263 test "it returns error when status is empty and no attachments" do
264 user = insert(:user)
265
266 assert {:error, "Cannot post an empty status without attachments"} =
267 CommonAPI.post(user, %{"status" => ""})
268 end
269
270 test "it validates character limits are correctly enforced" do
271 Pleroma.Config.put([:instance, :limit], 5)
272
273 user = insert(:user)
274
275 assert {:error, "The status is over the character limit"} =
276 CommonAPI.post(user, %{"status" => "foobar"})
277
278 assert {:ok, activity} = CommonAPI.post(user, %{"status" => "12345"})
279 end
280
281 test "it can handle activities that expire" do
282 user = insert(:user)
283
284 expires_at =
285 NaiveDateTime.utc_now()
286 |> NaiveDateTime.truncate(:second)
287 |> NaiveDateTime.add(1_000_000, :second)
288
289 assert {:ok, activity} =
290 CommonAPI.post(user, %{"status" => "chai", "expires_in" => 1_000_000})
291
292 assert expiration = Pleroma.ActivityExpiration.get_by_activity_id(activity.id)
293 assert expiration.scheduled_at == expires_at
294 end
295 end
296
297 describe "reactions" do
298 test "reacting to a status with an emoji" do
299 user = insert(:user)
300 other_user = insert(:user)
301
302 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "cofe"})
303
304 {:ok, reaction, _} = CommonAPI.react_with_emoji(activity.id, user, "👍")
305
306 assert reaction.data["actor"] == user.ap_id
307 assert reaction.data["content"] == "👍"
308
309 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "cofe"})
310
311 {:error, _} = CommonAPI.react_with_emoji(activity.id, user, ".")
312 end
313
314 test "unreacting to a status with an emoji" do
315 user = insert(:user)
316 other_user = insert(:user)
317
318 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "cofe"})
319 {:ok, reaction, _} = CommonAPI.react_with_emoji(activity.id, user, "👍")
320
321 {:ok, unreaction, _} = CommonAPI.unreact_with_emoji(activity.id, user, "👍")
322
323 assert unreaction.data["type"] == "Undo"
324 assert unreaction.data["object"] == reaction.data["id"]
325 end
326
327 test "repeating a status" do
328 user = insert(:user)
329 other_user = insert(:user)
330
331 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "cofe"})
332
333 {:ok, %Activity{}, _} = CommonAPI.repeat(activity.id, user)
334 end
335
336 test "can't repeat a repeat" do
337 user = insert(:user)
338 other_user = insert(:user)
339 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "cofe"})
340
341 {:ok, %Activity{} = announce, _} = CommonAPI.repeat(activity.id, other_user)
342
343 refute match?({:ok, %Activity{}, _}, CommonAPI.repeat(announce.id, user))
344 end
345
346 test "repeating a status privately" do
347 user = insert(:user)
348 other_user = insert(:user)
349
350 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "cofe"})
351
352 {:ok, %Activity{} = announce_activity, _} =
353 CommonAPI.repeat(activity.id, user, %{"visibility" => "private"})
354
355 assert Visibility.is_private?(announce_activity)
356 end
357
358 test "favoriting a status" do
359 user = insert(:user)
360 other_user = insert(:user)
361
362 {:ok, post_activity} = CommonAPI.post(other_user, %{"status" => "cofe"})
363
364 {:ok, %Activity{data: data}} = CommonAPI.favorite(user, post_activity.id)
365 assert data["type"] == "Like"
366 assert data["actor"] == user.ap_id
367 assert data["object"] == post_activity.data["object"]
368 end
369
370 test "retweeting a status twice returns the status" do
371 user = insert(:user)
372 other_user = insert(:user)
373
374 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "cofe"})
375 {:ok, %Activity{} = announce, object} = CommonAPI.repeat(activity.id, user)
376 {:ok, ^announce, ^object} = CommonAPI.repeat(activity.id, user)
377 end
378
379 test "favoriting a status twice returns ok, but without the like activity" do
380 user = insert(:user)
381 other_user = insert(:user)
382
383 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "cofe"})
384 {:ok, %Activity{}} = CommonAPI.favorite(user, activity.id)
385 assert {:ok, :already_liked} = CommonAPI.favorite(user, activity.id)
386 end
387 end
388
389 describe "pinned statuses" do
390 setup do
391 Pleroma.Config.put([:instance, :max_pinned_statuses], 1)
392
393 user = insert(:user)
394 {:ok, activity} = CommonAPI.post(user, %{"status" => "HI!!!"})
395
396 [user: user, activity: activity]
397 end
398
399 test "pin status", %{user: user, activity: activity} do
400 assert {:ok, ^activity} = CommonAPI.pin(activity.id, user)
401
402 id = activity.id
403 user = refresh_record(user)
404
405 assert %User{pinned_activities: [^id]} = user
406 end
407
408 test "pin poll", %{user: user} do
409 {:ok, activity} =
410 CommonAPI.post(user, %{
411 "status" => "How is fediverse today?",
412 "poll" => %{"options" => ["Absolutely outstanding", "Not good"], "expires_in" => 20}
413 })
414
415 assert {:ok, ^activity} = CommonAPI.pin(activity.id, user)
416
417 id = activity.id
418 user = refresh_record(user)
419
420 assert %User{pinned_activities: [^id]} = user
421 end
422
423 test "unlisted statuses can be pinned", %{user: user} do
424 {:ok, activity} = CommonAPI.post(user, %{"status" => "HI!!!", "visibility" => "unlisted"})
425 assert {:ok, ^activity} = CommonAPI.pin(activity.id, user)
426 end
427
428 test "only self-authored can be pinned", %{activity: activity} do
429 user = insert(:user)
430
431 assert {:error, "Could not pin"} = CommonAPI.pin(activity.id, user)
432 end
433
434 test "max pinned statuses", %{user: user, activity: activity_one} do
435 {:ok, activity_two} = CommonAPI.post(user, %{"status" => "HI!!!"})
436
437 assert {:ok, ^activity_one} = CommonAPI.pin(activity_one.id, user)
438
439 user = refresh_record(user)
440
441 assert {:error, "You have already pinned the maximum number of statuses"} =
442 CommonAPI.pin(activity_two.id, user)
443 end
444
445 test "unpin status", %{user: user, activity: activity} do
446 {:ok, activity} = CommonAPI.pin(activity.id, user)
447
448 user = refresh_record(user)
449
450 id = activity.id
451
452 assert match?({:ok, %{id: ^id}}, CommonAPI.unpin(activity.id, user))
453
454 user = refresh_record(user)
455
456 assert %User{pinned_activities: []} = user
457 end
458
459 test "should unpin when deleting a status", %{user: user, activity: activity} do
460 {:ok, activity} = CommonAPI.pin(activity.id, user)
461
462 user = refresh_record(user)
463
464 assert {:ok, _} = CommonAPI.delete(activity.id, user)
465
466 user = refresh_record(user)
467
468 assert %User{pinned_activities: []} = user
469 end
470 end
471
472 describe "mute tests" do
473 setup do
474 user = insert(:user)
475
476 activity = insert(:note_activity)
477
478 [user: user, activity: activity]
479 end
480
481 test "add mute", %{user: user, activity: activity} do
482 {:ok, _} = CommonAPI.add_mute(user, activity)
483 assert CommonAPI.thread_muted?(user, activity)
484 end
485
486 test "remove mute", %{user: user, activity: activity} do
487 CommonAPI.add_mute(user, activity)
488 {:ok, _} = CommonAPI.remove_mute(user, activity)
489 refute CommonAPI.thread_muted?(user, activity)
490 end
491
492 test "check that mutes can't be duplicate", %{user: user, activity: activity} do
493 CommonAPI.add_mute(user, activity)
494 {:error, _} = CommonAPI.add_mute(user, activity)
495 end
496 end
497
498 describe "reports" do
499 test "creates a report" do
500 reporter = insert(:user)
501 target_user = insert(:user)
502
503 {:ok, activity} = CommonAPI.post(target_user, %{"status" => "foobar"})
504
505 reporter_ap_id = reporter.ap_id
506 target_ap_id = target_user.ap_id
507 activity_ap_id = activity.data["id"]
508 comment = "foobar"
509
510 report_data = %{
511 "account_id" => target_user.id,
512 "comment" => comment,
513 "status_ids" => [activity.id]
514 }
515
516 note_obj = %{
517 "type" => "Note",
518 "id" => activity_ap_id,
519 "content" => "foobar",
520 "published" => activity.object.data["published"],
521 "actor" => AccountView.render("show.json", %{user: target_user})
522 }
523
524 assert {:ok, flag_activity} = CommonAPI.report(reporter, report_data)
525
526 assert %Activity{
527 actor: ^reporter_ap_id,
528 data: %{
529 "type" => "Flag",
530 "content" => ^comment,
531 "object" => [^target_ap_id, ^note_obj],
532 "state" => "open"
533 }
534 } = flag_activity
535 end
536
537 test "updates report state" do
538 [reporter, target_user] = insert_pair(:user)
539 activity = insert(:note_activity, user: target_user)
540
541 {:ok, %Activity{id: report_id}} =
542 CommonAPI.report(reporter, %{
543 "account_id" => target_user.id,
544 "comment" => "I feel offended",
545 "status_ids" => [activity.id]
546 })
547
548 {:ok, report} = CommonAPI.update_report_state(report_id, "resolved")
549
550 assert report.data["state"] == "resolved"
551
552 [reported_user, activity_id] = report.data["object"]
553
554 assert reported_user == target_user.ap_id
555 assert activity_id == activity.data["id"]
556 end
557
558 test "does not update report state when state is unsupported" do
559 [reporter, target_user] = insert_pair(:user)
560 activity = insert(:note_activity, user: target_user)
561
562 {:ok, %Activity{id: report_id}} =
563 CommonAPI.report(reporter, %{
564 "account_id" => target_user.id,
565 "comment" => "I feel offended",
566 "status_ids" => [activity.id]
567 })
568
569 assert CommonAPI.update_report_state(report_id, "test") == {:error, "Unsupported state"}
570 end
571
572 test "updates state of multiple reports" do
573 [reporter, target_user] = insert_pair(:user)
574 activity = insert(:note_activity, user: target_user)
575
576 {:ok, %Activity{id: first_report_id}} =
577 CommonAPI.report(reporter, %{
578 "account_id" => target_user.id,
579 "comment" => "I feel offended",
580 "status_ids" => [activity.id]
581 })
582
583 {:ok, %Activity{id: second_report_id}} =
584 CommonAPI.report(reporter, %{
585 "account_id" => target_user.id,
586 "comment" => "I feel very offended!",
587 "status_ids" => [activity.id]
588 })
589
590 {:ok, report_ids} =
591 CommonAPI.update_report_state([first_report_id, second_report_id], "resolved")
592
593 first_report = Activity.get_by_id(first_report_id)
594 second_report = Activity.get_by_id(second_report_id)
595
596 assert report_ids -- [first_report_id, second_report_id] == []
597 assert first_report.data["state"] == "resolved"
598 assert second_report.data["state"] == "resolved"
599 end
600 end
601
602 describe "reblog muting" do
603 setup do
604 muter = insert(:user)
605
606 muted = insert(:user)
607
608 [muter: muter, muted: muted]
609 end
610
611 test "add a reblog mute", %{muter: muter, muted: muted} do
612 {:ok, _reblog_mute} = CommonAPI.hide_reblogs(muter, muted)
613
614 assert User.showing_reblogs?(muter, muted) == false
615 end
616
617 test "remove a reblog mute", %{muter: muter, muted: muted} do
618 {:ok, _reblog_mute} = CommonAPI.hide_reblogs(muter, muted)
619 {:ok, _reblog_mute} = CommonAPI.show_reblogs(muter, muted)
620
621 assert User.showing_reblogs?(muter, muted) == true
622 end
623 end
624
625 describe "unfollow/2" do
626 test "also unsubscribes a user" do
627 [follower, followed] = insert_pair(:user)
628 {:ok, follower, followed, _} = CommonAPI.follow(follower, followed)
629 {:ok, _subscription} = User.subscribe(follower, followed)
630
631 assert User.subscribed_to?(follower, followed)
632
633 {:ok, follower} = CommonAPI.unfollow(follower, followed)
634
635 refute User.subscribed_to?(follower, followed)
636 end
637
638 test "cancels a pending follow for a local user" do
639 follower = insert(:user)
640 followed = insert(:user, locked: true)
641
642 assert {:ok, follower, followed, %{id: activity_id, data: %{"state" => "pending"}}} =
643 CommonAPI.follow(follower, followed)
644
645 assert User.get_follow_state(follower, followed) == :follow_pending
646 assert {:ok, follower} = CommonAPI.unfollow(follower, followed)
647 assert User.get_follow_state(follower, followed) == nil
648
649 assert %{id: ^activity_id, data: %{"state" => "cancelled"}} =
650 Pleroma.Web.ActivityPub.Utils.fetch_latest_follow(follower, followed)
651
652 assert %{
653 data: %{
654 "type" => "Undo",
655 "object" => %{"type" => "Follow", "state" => "cancelled"}
656 }
657 } = Pleroma.Web.ActivityPub.Utils.fetch_latest_undo(follower)
658 end
659
660 test "cancels a pending follow for a remote user" do
661 follower = insert(:user)
662 followed = insert(:user, locked: true, local: false, ap_enabled: true)
663
664 assert {:ok, follower, followed, %{id: activity_id, data: %{"state" => "pending"}}} =
665 CommonAPI.follow(follower, followed)
666
667 assert User.get_follow_state(follower, followed) == :follow_pending
668 assert {:ok, follower} = CommonAPI.unfollow(follower, followed)
669 assert User.get_follow_state(follower, followed) == nil
670
671 assert %{id: ^activity_id, data: %{"state" => "cancelled"}} =
672 Pleroma.Web.ActivityPub.Utils.fetch_latest_follow(follower, followed)
673
674 assert %{
675 data: %{
676 "type" => "Undo",
677 "object" => %{"type" => "Follow", "state" => "cancelled"}
678 }
679 } = Pleroma.Web.ActivityPub.Utils.fetch_latest_undo(follower)
680 end
681 end
682
683 describe "accept_follow_request/2" do
684 test "after acceptance, it sets all existing pending follow request states to 'accept'" do
685 user = insert(:user, locked: true)
686 follower = insert(:user)
687 follower_two = insert(:user)
688
689 {:ok, follow_activity} = ActivityPub.follow(follower, user)
690 {:ok, follow_activity_two} = ActivityPub.follow(follower, user)
691 {:ok, follow_activity_three} = ActivityPub.follow(follower_two, user)
692
693 assert follow_activity.data["state"] == "pending"
694 assert follow_activity_two.data["state"] == "pending"
695 assert follow_activity_three.data["state"] == "pending"
696
697 {:ok, _follower} = CommonAPI.accept_follow_request(follower, user)
698
699 assert Repo.get(Activity, follow_activity.id).data["state"] == "accept"
700 assert Repo.get(Activity, follow_activity_two.id).data["state"] == "accept"
701 assert Repo.get(Activity, follow_activity_three.id).data["state"] == "pending"
702 end
703
704 test "after rejection, it sets all existing pending follow request states to 'reject'" do
705 user = insert(:user, locked: true)
706 follower = insert(:user)
707 follower_two = insert(:user)
708
709 {:ok, follow_activity} = ActivityPub.follow(follower, user)
710 {:ok, follow_activity_two} = ActivityPub.follow(follower, user)
711 {:ok, follow_activity_three} = ActivityPub.follow(follower_two, user)
712
713 assert follow_activity.data["state"] == "pending"
714 assert follow_activity_two.data["state"] == "pending"
715 assert follow_activity_three.data["state"] == "pending"
716
717 {:ok, _follower} = CommonAPI.reject_follow_request(follower, user)
718
719 assert Repo.get(Activity, follow_activity.id).data["state"] == "reject"
720 assert Repo.get(Activity, follow_activity_two.id).data["state"] == "reject"
721 assert Repo.get(Activity, follow_activity_three.id).data["state"] == "pending"
722 end
723 end
724
725 describe "vote/3" do
726 test "does not allow to vote twice" do
727 user = insert(:user)
728 other_user = insert(:user)
729
730 {:ok, activity} =
731 CommonAPI.post(user, %{
732 "status" => "Am I cute?",
733 "poll" => %{"options" => ["Yes", "No"], "expires_in" => 20}
734 })
735
736 object = Object.normalize(activity)
737
738 {:ok, _, object} = CommonAPI.vote(other_user, object, [0])
739
740 assert {:error, "Already voted"} == CommonAPI.vote(other_user, object, [1])
741 end
742 end
743
744 describe "listen/2" do
745 test "returns a valid activity" do
746 user = insert(:user)
747
748 {:ok, activity} =
749 CommonAPI.listen(user, %{
750 "title" => "lain radio episode 1",
751 "album" => "lain radio",
752 "artist" => "lain",
753 "length" => 180_000
754 })
755
756 object = Object.normalize(activity)
757
758 assert object.data["title"] == "lain radio episode 1"
759
760 assert Visibility.get_visibility(activity) == "public"
761 end
762
763 test "respects visibility=private" do
764 user = insert(:user)
765
766 {:ok, activity} =
767 CommonAPI.listen(user, %{
768 "title" => "lain radio episode 1",
769 "album" => "lain radio",
770 "artist" => "lain",
771 "length" => 180_000,
772 "visibility" => "private"
773 })
774
775 object = Object.normalize(activity)
776
777 assert object.data["title"] == "lain radio episode 1"
778
779 assert Visibility.get_visibility(activity) == "private"
780 end
781 end
782 end