merge develop
[akkoma] / test / user_test.exs
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
5 defmodule Pleroma.UserTest do
6 alias Pleroma.Activity
7 alias Pleroma.Builders.UserBuilder
8 alias Pleroma.Object
9 alias Pleroma.Repo
10 alias Pleroma.User
11 alias Pleroma.Web.ActivityPub.ActivityPub
12 alias Pleroma.Web.CommonAPI
13
14 use Pleroma.DataCase
15
16 import Pleroma.Factory
17 import Mock
18
19 setup_all do
20 Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
21 :ok
22 end
23
24 describe "when tags are nil" do
25 test "tagging a user" do
26 user = insert(:user, %{tags: nil})
27 user = User.tag(user, ["cool", "dude"])
28
29 assert "cool" in user.tags
30 assert "dude" in user.tags
31 end
32
33 test "untagging a user" do
34 user = insert(:user, %{tags: nil})
35 user = User.untag(user, ["cool", "dude"])
36
37 assert user.tags == []
38 end
39 end
40
41 test "ap_id returns the activity pub id for the user" do
42 user = UserBuilder.build()
43
44 expected_ap_id = "#{Pleroma.Web.base_url()}/users/#{user.nickname}"
45
46 assert expected_ap_id == User.ap_id(user)
47 end
48
49 test "ap_followers returns the followers collection for the user" do
50 user = UserBuilder.build()
51
52 expected_followers_collection = "#{User.ap_id(user)}/followers"
53
54 assert expected_followers_collection == User.ap_followers(user)
55 end
56
57 test "ap_following returns the following collection for the user" do
58 user = UserBuilder.build()
59
60 expected_followers_collection = "#{User.ap_id(user)}/following"
61
62 assert expected_followers_collection == User.ap_following(user)
63 end
64
65 test "returns all pending follow requests" do
66 unlocked = insert(:user)
67 locked = insert(:user, %{info: %{locked: true}})
68 follower = insert(:user)
69
70 Pleroma.Web.TwitterAPI.TwitterAPI.follow(follower, %{"user_id" => unlocked.id})
71 Pleroma.Web.TwitterAPI.TwitterAPI.follow(follower, %{"user_id" => locked.id})
72
73 assert {:ok, []} = User.get_follow_requests(unlocked)
74 assert {:ok, [activity]} = User.get_follow_requests(locked)
75
76 assert activity
77 end
78
79 test "doesn't return already accepted or duplicate follow requests" do
80 locked = insert(:user, %{info: %{locked: true}})
81 pending_follower = insert(:user)
82 accepted_follower = insert(:user)
83
84 Pleroma.Web.TwitterAPI.TwitterAPI.follow(pending_follower, %{"user_id" => locked.id})
85 Pleroma.Web.TwitterAPI.TwitterAPI.follow(pending_follower, %{"user_id" => locked.id})
86 Pleroma.Web.TwitterAPI.TwitterAPI.follow(accepted_follower, %{"user_id" => locked.id})
87 User.follow(accepted_follower, locked)
88
89 assert {:ok, [activity]} = User.get_follow_requests(locked)
90 assert activity
91 end
92
93 test "follow_all follows mutliple users" do
94 user = insert(:user)
95 followed_zero = insert(:user)
96 followed_one = insert(:user)
97 followed_two = insert(:user)
98 blocked = insert(:user)
99 not_followed = insert(:user)
100 reverse_blocked = insert(:user)
101
102 {:ok, user} = User.block(user, blocked)
103 {:ok, reverse_blocked} = User.block(reverse_blocked, user)
104
105 {:ok, user} = User.follow(user, followed_zero)
106
107 {:ok, user} = User.follow_all(user, [followed_one, followed_two, blocked, reverse_blocked])
108
109 assert User.following?(user, followed_one)
110 assert User.following?(user, followed_two)
111 assert User.following?(user, followed_zero)
112 refute User.following?(user, not_followed)
113 refute User.following?(user, blocked)
114 refute User.following?(user, reverse_blocked)
115 end
116
117 test "follow_all follows mutliple users without duplicating" do
118 user = insert(:user)
119 followed_zero = insert(:user)
120 followed_one = insert(:user)
121 followed_two = insert(:user)
122
123 {:ok, user} = User.follow_all(user, [followed_zero, followed_one])
124 assert length(user.following) == 3
125
126 {:ok, user} = User.follow_all(user, [followed_one, followed_two])
127 assert length(user.following) == 4
128 end
129
130 test "follow takes a user and another user" do
131 user = insert(:user)
132 followed = insert(:user)
133
134 {:ok, user} = User.follow(user, followed)
135
136 user = User.get_cached_by_id(user.id)
137
138 followed = User.get_cached_by_ap_id(followed.ap_id)
139 assert followed.info.follower_count == 1
140
141 assert User.ap_followers(followed) in user.following
142 end
143
144 test "can't follow a deactivated users" do
145 user = insert(:user)
146 followed = insert(:user, info: %{deactivated: true})
147
148 {:error, _} = User.follow(user, followed)
149 end
150
151 test "can't follow a user who blocked us" do
152 blocker = insert(:user)
153 blockee = insert(:user)
154
155 {:ok, blocker} = User.block(blocker, blockee)
156
157 {:error, _} = User.follow(blockee, blocker)
158 end
159
160 test "can't subscribe to a user who blocked us" do
161 blocker = insert(:user)
162 blocked = insert(:user)
163
164 {:ok, blocker} = User.block(blocker, blocked)
165
166 {:error, _} = User.subscribe(blocked, blocker)
167 end
168
169 test "local users do not automatically follow local locked accounts" do
170 follower = insert(:user, info: %{locked: true})
171 followed = insert(:user, info: %{locked: true})
172
173 {:ok, follower} = User.maybe_direct_follow(follower, followed)
174
175 refute User.following?(follower, followed)
176 end
177
178 # This is a somewhat useless test.
179 # test "following a remote user will ensure a websub subscription is present" do
180 # user = insert(:user)
181 # {:ok, followed} = OStatus.make_user("shp@social.heldscal.la")
182
183 # assert followed.local == false
184
185 # {:ok, user} = User.follow(user, followed)
186 # assert User.ap_followers(followed) in user.following
187
188 # query = from w in WebsubClientSubscription,
189 # where: w.topic == ^followed.info["topic"]
190 # websub = Repo.one(query)
191
192 # assert websub
193 # end
194
195 test "unfollow takes a user and another user" do
196 followed = insert(:user)
197 user = insert(:user, %{following: [User.ap_followers(followed)]})
198
199 {:ok, user, _activity} = User.unfollow(user, followed)
200
201 user = User.get_cached_by_id(user.id)
202
203 assert user.following == []
204 end
205
206 test "unfollow doesn't unfollow yourself" do
207 user = insert(:user)
208
209 {:error, _} = User.unfollow(user, user)
210
211 user = User.get_cached_by_id(user.id)
212 assert user.following == [user.ap_id]
213 end
214
215 test "test if a user is following another user" do
216 followed = insert(:user)
217 user = insert(:user, %{following: [User.ap_followers(followed)]})
218
219 assert User.following?(user, followed)
220 refute User.following?(followed, user)
221 end
222
223 test "fetches correct profile for nickname beginning with number" do
224 # Use old-style integer ID to try to reproduce the problem
225 user = insert(:user, %{id: 1080})
226 user_with_numbers = insert(:user, %{nickname: "#{user.id}garbage"})
227 assert user_with_numbers == User.get_cached_by_nickname_or_id(user_with_numbers.nickname)
228 end
229
230 describe "user registration" do
231 @full_user_data %{
232 bio: "A guy",
233 name: "my name",
234 nickname: "nick",
235 password: "test",
236 password_confirmation: "test",
237 email: "email@example.com"
238 }
239
240 test "it autofollows accounts that are set for it" do
241 user = insert(:user)
242 remote_user = insert(:user, %{local: false})
243
244 Pleroma.Config.put([:instance, :autofollowed_nicknames], [
245 user.nickname,
246 remote_user.nickname
247 ])
248
249 cng = User.register_changeset(%User{}, @full_user_data)
250
251 {:ok, registered_user} = User.register(cng)
252
253 assert User.following?(registered_user, user)
254 refute User.following?(registered_user, remote_user)
255
256 Pleroma.Config.put([:instance, :autofollowed_nicknames], [])
257 end
258
259 test "it sends a welcome message if it is set" do
260 welcome_user = insert(:user)
261
262 Pleroma.Config.put([:instance, :welcome_user_nickname], welcome_user.nickname)
263 Pleroma.Config.put([:instance, :welcome_message], "Hello, this is a cool site")
264
265 cng = User.register_changeset(%User{}, @full_user_data)
266 {:ok, registered_user} = User.register(cng)
267
268 activity = Repo.one(Pleroma.Activity)
269 assert registered_user.ap_id in activity.recipients
270 assert Object.normalize(activity).data["content"] =~ "cool site"
271 assert activity.actor == welcome_user.ap_id
272
273 Pleroma.Config.put([:instance, :welcome_user_nickname], nil)
274 Pleroma.Config.put([:instance, :welcome_message], nil)
275 end
276
277 test "it requires an email, name, nickname and password, bio is optional" do
278 @full_user_data
279 |> Map.keys()
280 |> Enum.each(fn key ->
281 params = Map.delete(@full_user_data, key)
282 changeset = User.register_changeset(%User{}, params)
283
284 assert if key == :bio, do: changeset.valid?, else: not changeset.valid?
285 end)
286 end
287
288 test "it restricts certain nicknames" do
289 [restricted_name | _] = Pleroma.Config.get([User, :restricted_nicknames])
290
291 assert is_bitstring(restricted_name)
292
293 params =
294 @full_user_data
295 |> Map.put(:nickname, restricted_name)
296
297 changeset = User.register_changeset(%User{}, params)
298
299 refute changeset.valid?
300 end
301
302 test "it sets the password_hash, ap_id and following fields" do
303 changeset = User.register_changeset(%User{}, @full_user_data)
304
305 assert changeset.valid?
306
307 assert is_binary(changeset.changes[:password_hash])
308 assert changeset.changes[:ap_id] == User.ap_id(%User{nickname: @full_user_data.nickname})
309
310 assert changeset.changes[:following] == [
311 User.ap_followers(%User{nickname: @full_user_data.nickname})
312 ]
313
314 assert changeset.changes.follower_address == "#{changeset.changes.ap_id}/followers"
315 end
316
317 test "it ensures info is not nil" do
318 changeset = User.register_changeset(%User{}, @full_user_data)
319
320 assert changeset.valid?
321
322 {:ok, user} =
323 changeset
324 |> Repo.insert()
325
326 refute is_nil(user.info)
327 end
328 end
329
330 describe "user registration, with :account_activation_required" do
331 @full_user_data %{
332 bio: "A guy",
333 name: "my name",
334 nickname: "nick",
335 password: "test",
336 password_confirmation: "test",
337 email: "email@example.com"
338 }
339
340 setup do
341 setting = Pleroma.Config.get([:instance, :account_activation_required])
342
343 unless setting do
344 Pleroma.Config.put([:instance, :account_activation_required], true)
345 on_exit(fn -> Pleroma.Config.put([:instance, :account_activation_required], setting) end)
346 end
347
348 :ok
349 end
350
351 test "it creates unconfirmed user" do
352 changeset = User.register_changeset(%User{}, @full_user_data)
353 assert changeset.valid?
354
355 {:ok, user} = Repo.insert(changeset)
356
357 assert user.info.confirmation_pending
358 assert user.info.confirmation_token
359 end
360
361 test "it creates confirmed user if :confirmed option is given" do
362 changeset = User.register_changeset(%User{}, @full_user_data, need_confirmation: false)
363 assert changeset.valid?
364
365 {:ok, user} = Repo.insert(changeset)
366
367 refute user.info.confirmation_pending
368 refute user.info.confirmation_token
369 end
370 end
371
372 describe "get_or_fetch/1" do
373 test "gets an existing user by nickname" do
374 user = insert(:user)
375 {:ok, fetched_user} = User.get_or_fetch(user.nickname)
376
377 assert user == fetched_user
378 end
379
380 test "gets an existing user by ap_id" do
381 ap_id = "http://mastodon.example.org/users/admin"
382
383 user =
384 insert(
385 :user,
386 local: false,
387 nickname: "admin@mastodon.example.org",
388 ap_id: ap_id,
389 info: %{}
390 )
391
392 {:ok, fetched_user} = User.get_or_fetch(ap_id)
393 freshed_user = refresh_record(user)
394 assert freshed_user == fetched_user
395 end
396 end
397
398 describe "fetching a user from nickname or trying to build one" do
399 test "gets an existing user" do
400 user = insert(:user)
401 {:ok, fetched_user} = User.get_or_fetch_by_nickname(user.nickname)
402
403 assert user == fetched_user
404 end
405
406 test "gets an existing user, case insensitive" do
407 user = insert(:user, nickname: "nick")
408 {:ok, fetched_user} = User.get_or_fetch_by_nickname("NICK")
409
410 assert user == fetched_user
411 end
412
413 test "gets an existing user by fully qualified nickname" do
414 user = insert(:user)
415
416 {:ok, fetched_user} =
417 User.get_or_fetch_by_nickname(user.nickname <> "@" <> Pleroma.Web.Endpoint.host())
418
419 assert user == fetched_user
420 end
421
422 test "gets an existing user by fully qualified nickname, case insensitive" do
423 user = insert(:user, nickname: "nick")
424 casing_altered_fqn = String.upcase(user.nickname <> "@" <> Pleroma.Web.Endpoint.host())
425
426 {:ok, fetched_user} = User.get_or_fetch_by_nickname(casing_altered_fqn)
427
428 assert user == fetched_user
429 end
430
431 test "fetches an external user via ostatus if no user exists" do
432 {:ok, fetched_user} = User.get_or_fetch_by_nickname("shp@social.heldscal.la")
433 assert fetched_user.nickname == "shp@social.heldscal.la"
434 end
435
436 test "returns nil if no user could be fetched" do
437 {:error, fetched_user} = User.get_or_fetch_by_nickname("nonexistant@social.heldscal.la")
438 assert fetched_user == "not found nonexistant@social.heldscal.la"
439 end
440
441 test "returns nil for nonexistant local user" do
442 {:error, fetched_user} = User.get_or_fetch_by_nickname("nonexistant")
443 assert fetched_user == "not found nonexistant"
444 end
445
446 test "updates an existing user, if stale" do
447 a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
448
449 orig_user =
450 insert(
451 :user,
452 local: false,
453 nickname: "admin@mastodon.example.org",
454 ap_id: "http://mastodon.example.org/users/admin",
455 last_refreshed_at: a_week_ago,
456 info: %{}
457 )
458
459 assert orig_user.last_refreshed_at == a_week_ago
460
461 {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/admin")
462 assert user.info.source_data["endpoints"]
463
464 refute user.last_refreshed_at == orig_user.last_refreshed_at
465 end
466 end
467
468 test "returns an ap_id for a user" do
469 user = insert(:user)
470
471 assert User.ap_id(user) ==
472 Pleroma.Web.Router.Helpers.o_status_url(
473 Pleroma.Web.Endpoint,
474 :feed_redirect,
475 user.nickname
476 )
477 end
478
479 test "returns an ap_followers link for a user" do
480 user = insert(:user)
481
482 assert User.ap_followers(user) ==
483 Pleroma.Web.Router.Helpers.o_status_url(
484 Pleroma.Web.Endpoint,
485 :feed_redirect,
486 user.nickname
487 ) <> "/followers"
488 end
489
490 describe "remote user creation changeset" do
491 @valid_remote %{
492 bio: "hello",
493 name: "Someone",
494 nickname: "a@b.de",
495 ap_id: "http...",
496 info: %{some: "info"},
497 avatar: %{some: "avatar"}
498 }
499
500 test "it confirms validity" do
501 cs = User.remote_user_creation(@valid_remote)
502 assert cs.valid?
503 end
504
505 test "it sets the follower_adress" do
506 cs = User.remote_user_creation(@valid_remote)
507 # remote users get a fake local follower address
508 assert cs.changes.follower_address ==
509 User.ap_followers(%User{nickname: @valid_remote[:nickname]})
510 end
511
512 test "it enforces the fqn format for nicknames" do
513 cs = User.remote_user_creation(%{@valid_remote | nickname: "bla"})
514 assert cs.changes.local == false
515 assert cs.changes.avatar
516 refute cs.valid?
517 end
518
519 test "it has required fields" do
520 [:name, :ap_id]
521 |> Enum.each(fn field ->
522 cs = User.remote_user_creation(Map.delete(@valid_remote, field))
523 refute cs.valid?
524 end)
525 end
526
527 test "it restricts some sizes" do
528 [bio: 5000, name: 100]
529 |> Enum.each(fn {field, size} ->
530 string = String.pad_leading(".", size)
531 cs = User.remote_user_creation(Map.put(@valid_remote, field, string))
532 assert cs.valid?
533
534 string = String.pad_leading(".", size + 1)
535 cs = User.remote_user_creation(Map.put(@valid_remote, field, string))
536 refute cs.valid?
537 end)
538 end
539 end
540
541 describe "followers and friends" do
542 test "gets all followers for a given user" do
543 user = insert(:user)
544 follower_one = insert(:user)
545 follower_two = insert(:user)
546 not_follower = insert(:user)
547
548 {:ok, follower_one} = User.follow(follower_one, user)
549 {:ok, follower_two} = User.follow(follower_two, user)
550
551 {:ok, res} = User.get_followers(user)
552
553 assert Enum.member?(res, follower_one)
554 assert Enum.member?(res, follower_two)
555 refute Enum.member?(res, not_follower)
556 end
557
558 test "gets all friends (followed users) for a given user" do
559 user = insert(:user)
560 followed_one = insert(:user)
561 followed_two = insert(:user)
562 not_followed = insert(:user)
563
564 {:ok, user} = User.follow(user, followed_one)
565 {:ok, user} = User.follow(user, followed_two)
566
567 {:ok, res} = User.get_friends(user)
568
569 followed_one = User.get_cached_by_ap_id(followed_one.ap_id)
570 followed_two = User.get_cached_by_ap_id(followed_two.ap_id)
571 assert Enum.member?(res, followed_one)
572 assert Enum.member?(res, followed_two)
573 refute Enum.member?(res, not_followed)
574 end
575 end
576
577 describe "updating note and follower count" do
578 test "it sets the info->note_count property" do
579 note = insert(:note)
580
581 user = User.get_cached_by_ap_id(note.data["actor"])
582
583 assert user.info.note_count == 0
584
585 {:ok, user} = User.update_note_count(user)
586
587 assert user.info.note_count == 1
588 end
589
590 test "it increases the info->note_count property" do
591 note = insert(:note)
592 user = User.get_cached_by_ap_id(note.data["actor"])
593
594 assert user.info.note_count == 0
595
596 {:ok, user} = User.increase_note_count(user)
597
598 assert user.info.note_count == 1
599
600 {:ok, user} = User.increase_note_count(user)
601
602 assert user.info.note_count == 2
603 end
604
605 test "it decreases the info->note_count property" do
606 note = insert(:note)
607 user = User.get_cached_by_ap_id(note.data["actor"])
608
609 assert user.info.note_count == 0
610
611 {:ok, user} = User.increase_note_count(user)
612
613 assert user.info.note_count == 1
614
615 {:ok, user} = User.decrease_note_count(user)
616
617 assert user.info.note_count == 0
618
619 {:ok, user} = User.decrease_note_count(user)
620
621 assert user.info.note_count == 0
622 end
623
624 test "it sets the info->follower_count property" do
625 user = insert(:user)
626 follower = insert(:user)
627
628 User.follow(follower, user)
629
630 assert user.info.follower_count == 0
631
632 {:ok, user} = User.update_follower_count(user)
633
634 assert user.info.follower_count == 1
635 end
636 end
637
638 describe "remove duplicates from following list" do
639 test "it removes duplicates" do
640 user = insert(:user)
641 follower = insert(:user)
642
643 {:ok, %User{following: following} = follower} = User.follow(follower, user)
644 assert length(following) == 2
645
646 {:ok, follower} =
647 follower
648 |> User.update_changeset(%{following: following ++ following})
649 |> Repo.update()
650
651 assert length(follower.following) == 4
652
653 {:ok, follower} = User.remove_duplicated_following(follower)
654 assert length(follower.following) == 2
655 end
656
657 test "it does nothing when following is uniq" do
658 user = insert(:user)
659 follower = insert(:user)
660
661 {:ok, follower} = User.follow(follower, user)
662 assert length(follower.following) == 2
663
664 {:ok, follower} = User.remove_duplicated_following(follower)
665 assert length(follower.following) == 2
666 end
667 end
668
669 describe "follow_import" do
670 test "it imports user followings from list" do
671 [user1, user2, user3] = insert_list(3, :user)
672
673 identifiers = [
674 user2.ap_id,
675 user3.nickname
676 ]
677
678 result = User.follow_import(user1, identifiers)
679 assert is_list(result)
680 assert result == [user2, user3]
681 end
682 end
683
684 describe "mutes" do
685 test "it mutes people" do
686 user = insert(:user)
687 muted_user = insert(:user)
688
689 refute User.mutes?(user, muted_user)
690
691 {:ok, user} = User.mute(user, muted_user)
692
693 assert User.mutes?(user, muted_user)
694 end
695
696 test "it unmutes users" do
697 user = insert(:user)
698 muted_user = insert(:user)
699
700 {:ok, user} = User.mute(user, muted_user)
701 {:ok, user} = User.unmute(user, muted_user)
702
703 refute User.mutes?(user, muted_user)
704 end
705 end
706
707 describe "blocks" do
708 test "it blocks people" do
709 user = insert(:user)
710 blocked_user = insert(:user)
711
712 refute User.blocks?(user, blocked_user)
713
714 {:ok, user} = User.block(user, blocked_user)
715
716 assert User.blocks?(user, blocked_user)
717 end
718
719 test "it unblocks users" do
720 user = insert(:user)
721 blocked_user = insert(:user)
722
723 {:ok, user} = User.block(user, blocked_user)
724 {:ok, user} = User.unblock(user, blocked_user)
725
726 refute User.blocks?(user, blocked_user)
727 end
728
729 test "blocks tear down cyclical follow relationships" do
730 blocker = insert(:user)
731 blocked = insert(:user)
732
733 {:ok, blocker} = User.follow(blocker, blocked)
734 {:ok, blocked} = User.follow(blocked, blocker)
735
736 assert User.following?(blocker, blocked)
737 assert User.following?(blocked, blocker)
738
739 {:ok, blocker} = User.block(blocker, blocked)
740 blocked = User.get_cached_by_id(blocked.id)
741
742 assert User.blocks?(blocker, blocked)
743
744 refute User.following?(blocker, blocked)
745 refute User.following?(blocked, blocker)
746 end
747
748 test "blocks tear down blocker->blocked follow relationships" do
749 blocker = insert(:user)
750 blocked = insert(:user)
751
752 {:ok, blocker} = User.follow(blocker, blocked)
753
754 assert User.following?(blocker, blocked)
755 refute User.following?(blocked, blocker)
756
757 {:ok, blocker} = User.block(blocker, blocked)
758 blocked = User.get_cached_by_id(blocked.id)
759
760 assert User.blocks?(blocker, blocked)
761
762 refute User.following?(blocker, blocked)
763 refute User.following?(blocked, blocker)
764 end
765
766 test "blocks tear down blocked->blocker follow relationships" do
767 blocker = insert(:user)
768 blocked = insert(:user)
769
770 {:ok, blocked} = User.follow(blocked, blocker)
771
772 refute User.following?(blocker, blocked)
773 assert User.following?(blocked, blocker)
774
775 {:ok, blocker} = User.block(blocker, blocked)
776 blocked = User.get_cached_by_id(blocked.id)
777
778 assert User.blocks?(blocker, blocked)
779
780 refute User.following?(blocker, blocked)
781 refute User.following?(blocked, blocker)
782 end
783
784 test "blocks tear down blocked->blocker subscription relationships" do
785 blocker = insert(:user)
786 blocked = insert(:user)
787
788 {:ok, blocker} = User.subscribe(blocked, blocker)
789
790 assert User.subscribed_to?(blocked, blocker)
791 refute User.subscribed_to?(blocker, blocked)
792
793 {:ok, blocker} = User.block(blocker, blocked)
794
795 assert User.blocks?(blocker, blocked)
796 refute User.subscribed_to?(blocker, blocked)
797 refute User.subscribed_to?(blocked, blocker)
798 end
799 end
800
801 describe "domain blocking" do
802 test "blocks domains" do
803 user = insert(:user)
804 collateral_user = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
805
806 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
807
808 assert User.blocks?(user, collateral_user)
809 end
810
811 test "unblocks domains" do
812 user = insert(:user)
813 collateral_user = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
814
815 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
816 {:ok, user} = User.unblock_domain(user, "awful-and-rude-instance.com")
817
818 refute User.blocks?(user, collateral_user)
819 end
820 end
821
822 describe "blocks_import" do
823 test "it imports user blocks from list" do
824 [user1, user2, user3] = insert_list(3, :user)
825
826 identifiers = [
827 user2.ap_id,
828 user3.nickname
829 ]
830
831 result = User.blocks_import(user1, identifiers)
832 assert is_list(result)
833 assert result == [user2, user3]
834 end
835 end
836
837 test "get recipients from activity" do
838 actor = insert(:user)
839 user = insert(:user, local: true)
840 user_two = insert(:user, local: false)
841 addressed = insert(:user, local: true)
842 addressed_remote = insert(:user, local: false)
843
844 {:ok, activity} =
845 CommonAPI.post(actor, %{
846 "status" => "hey @#{addressed.nickname} @#{addressed_remote.nickname}"
847 })
848
849 assert Enum.map([actor, addressed], & &1.ap_id) --
850 Enum.map(User.get_recipients_from_activity(activity), & &1.ap_id) == []
851
852 {:ok, user} = User.follow(user, actor)
853 {:ok, _user_two} = User.follow(user_two, actor)
854 recipients = User.get_recipients_from_activity(activity)
855 assert length(recipients) == 3
856 assert user in recipients
857 assert addressed in recipients
858 end
859
860 describe ".deactivate" do
861 test "can de-activate then re-activate a user" do
862 user = insert(:user)
863 assert false == user.info.deactivated
864 {:ok, user} = User.deactivate(user)
865 assert true == user.info.deactivated
866 {:ok, user} = User.deactivate(user, false)
867 assert false == user.info.deactivated
868 end
869
870 test "hide a user from followers " do
871 user = insert(:user)
872 user2 = insert(:user)
873
874 {:ok, user} = User.follow(user, user2)
875 {:ok, _user} = User.deactivate(user)
876
877 info = User.get_cached_user_info(user2)
878
879 assert info.follower_count == 0
880 assert {:ok, []} = User.get_followers(user2)
881 end
882
883 test "hide a user from friends" do
884 user = insert(:user)
885 user2 = insert(:user)
886
887 {:ok, user2} = User.follow(user2, user)
888 assert User.following_count(user2) == 1
889
890 {:ok, _user} = User.deactivate(user)
891
892 info = User.get_cached_user_info(user2)
893
894 assert info.following_count == 0
895 assert User.following_count(user2) == 0
896 assert {:ok, []} = User.get_friends(user2)
897 end
898
899 test "hide a user's statuses from timelines and notifications" do
900 user = insert(:user)
901 user2 = insert(:user)
902
903 {:ok, user2} = User.follow(user2, user)
904
905 {:ok, activity} = CommonAPI.post(user, %{"status" => "hey @#{user2.nickname}"})
906
907 activity = Repo.preload(activity, :bookmark)
908
909 [notification] = Pleroma.Notification.for_user(user2)
910 assert notification.activity.id == activity.id
911
912 assert [activity] == ActivityPub.fetch_public_activities(%{}) |> Repo.preload(:bookmark)
913
914 assert [%{activity | thread_muted?: CommonAPI.thread_muted?(user2, activity)}] ==
915 ActivityPub.fetch_activities([user2.ap_id | user2.following], %{"user" => user2})
916
917 {:ok, _user} = User.deactivate(user)
918
919 assert [] == ActivityPub.fetch_public_activities(%{})
920 assert [] == Pleroma.Notification.for_user(user2)
921
922 assert [] ==
923 ActivityPub.fetch_activities([user2.ap_id | user2.following], %{"user" => user2})
924 end
925 end
926
927 describe "delete" do
928 setup do
929 {:ok, user} = insert(:user) |> User.set_cache()
930
931 [user: user]
932 end
933
934 test ".delete_user_activities deletes all create activities", %{user: user} do
935 {:ok, activity} = CommonAPI.post(user, %{"status" => "2hu"})
936
937 {:ok, _} = User.delete_user_activities(user)
938
939 # TODO: Remove favorites, repeats, delete activities.
940 refute Activity.get_by_id(activity.id)
941 end
942
943 test "it deletes a user, all follow relationships and all activities", %{user: user} do
944 follower = insert(:user)
945 {:ok, follower} = User.follow(follower, user)
946
947 object = insert(:note, user: user)
948 activity = insert(:note_activity, user: user, note: object)
949
950 object_two = insert(:note, user: follower)
951 activity_two = insert(:note_activity, user: follower, note: object_two)
952
953 {:ok, like, _} = CommonAPI.favorite(activity_two.id, user)
954 {:ok, like_two, _} = CommonAPI.favorite(activity.id, follower)
955 {:ok, repeat, _} = CommonAPI.repeat(activity_two.id, user)
956
957 {:ok, _} = User.delete(user)
958
959 follower = User.get_cached_by_id(follower.id)
960
961 refute User.following?(follower, user)
962 refute User.get_by_id(user.id)
963 assert {:ok, nil} == Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
964
965 user_activities =
966 user.ap_id
967 |> Activity.query_by_actor()
968 |> Repo.all()
969 |> Enum.map(fn act -> act.data["type"] end)
970
971 assert Enum.all?(user_activities, fn act -> act in ~w(Delete Undo) end)
972
973 refute Activity.get_by_id(activity.id)
974 refute Activity.get_by_id(like.id)
975 refute Activity.get_by_id(like_two.id)
976 refute Activity.get_by_id(repeat.id)
977 end
978
979 test_with_mock "it sends out User Delete activity",
980 %{user: user},
981 Pleroma.Web.ActivityPub.Publisher,
982 [:passthrough],
983 [] do
984 config_path = [:instance, :federating]
985 initial_setting = Pleroma.Config.get(config_path)
986 Pleroma.Config.put(config_path, true)
987
988 {:ok, follower} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/admin")
989 {:ok, _} = User.follow(follower, user)
990
991 {:ok, _user} = User.delete(user)
992
993 assert called(
994 Pleroma.Web.ActivityPub.Publisher.publish_one(%{
995 inbox: "http://mastodon.example.org/inbox"
996 })
997 )
998
999 Pleroma.Config.put(config_path, initial_setting)
1000 end
1001 end
1002
1003 test "get_public_key_for_ap_id fetches a user that's not in the db" do
1004 assert {:ok, _key} = User.get_public_key_for_ap_id("http://mastodon.example.org/users/admin")
1005 end
1006
1007 test "insert or update a user from given data" do
1008 user = insert(:user, %{nickname: "nick@name.de"})
1009 data = %{ap_id: user.ap_id <> "xxx", name: user.name, nickname: user.nickname}
1010
1011 assert {:ok, %User{}} = User.insert_or_update_user(data)
1012 end
1013
1014 describe "per-user rich-text filtering" do
1015 test "html_filter_policy returns default policies, when rich-text is enabled" do
1016 user = insert(:user)
1017
1018 assert Pleroma.Config.get([:markup, :scrub_policy]) == User.html_filter_policy(user)
1019 end
1020
1021 test "html_filter_policy returns TwitterText scrubber when rich-text is disabled" do
1022 user = insert(:user, %{info: %{no_rich_text: true}})
1023
1024 assert Pleroma.HTML.Scrubber.TwitterText == User.html_filter_policy(user)
1025 end
1026 end
1027
1028 describe "caching" do
1029 test "invalidate_cache works" do
1030 user = insert(:user)
1031 _user_info = User.get_cached_user_info(user)
1032
1033 User.invalidate_cache(user)
1034
1035 {:ok, nil} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1036 {:ok, nil} = Cachex.get(:user_cache, "nickname:#{user.nickname}")
1037 {:ok, nil} = Cachex.get(:user_cache, "user_info:#{user.id}")
1038 end
1039
1040 test "User.delete() plugs any possible zombie objects" do
1041 user = insert(:user)
1042
1043 {:ok, _} = User.delete(user)
1044
1045 {:ok, cached_user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1046
1047 assert cached_user != user
1048
1049 {:ok, cached_user} = Cachex.get(:user_cache, "nickname:#{user.ap_id}")
1050
1051 assert cached_user != user
1052 end
1053 end
1054
1055 test "auth_active?/1 works correctly" do
1056 Pleroma.Config.put([:instance, :account_activation_required], true)
1057
1058 local_user = insert(:user, local: true, info: %{confirmation_pending: true})
1059 confirmed_user = insert(:user, local: true, info: %{confirmation_pending: false})
1060 remote_user = insert(:user, local: false)
1061
1062 refute User.auth_active?(local_user)
1063 assert User.auth_active?(confirmed_user)
1064 assert User.auth_active?(remote_user)
1065
1066 Pleroma.Config.put([:instance, :account_activation_required], false)
1067 end
1068
1069 describe "superuser?/1" do
1070 test "returns false for unprivileged users" do
1071 user = insert(:user, local: true)
1072
1073 refute User.superuser?(user)
1074 end
1075
1076 test "returns false for remote users" do
1077 user = insert(:user, local: false)
1078 remote_admin_user = insert(:user, local: false, info: %{is_admin: true})
1079
1080 refute User.superuser?(user)
1081 refute User.superuser?(remote_admin_user)
1082 end
1083
1084 test "returns true for local moderators" do
1085 user = insert(:user, local: true, info: %{is_moderator: true})
1086
1087 assert User.superuser?(user)
1088 end
1089
1090 test "returns true for local admins" do
1091 user = insert(:user, local: true, info: %{is_admin: true})
1092
1093 assert User.superuser?(user)
1094 end
1095 end
1096
1097 describe "visible_for?/2" do
1098 test "returns true when the account is itself" do
1099 user = insert(:user, local: true)
1100
1101 assert User.visible_for?(user, user)
1102 end
1103
1104 test "returns false when the account is unauthenticated and auth is required" do
1105 Pleroma.Config.put([:instance, :account_activation_required], true)
1106
1107 user = insert(:user, local: true, info: %{confirmation_pending: true})
1108 other_user = insert(:user, local: true)
1109
1110 refute User.visible_for?(user, other_user)
1111
1112 Pleroma.Config.put([:instance, :account_activation_required], false)
1113 end
1114
1115 test "returns true when the account is unauthenticated and auth is not required" do
1116 user = insert(:user, local: true, info: %{confirmation_pending: true})
1117 other_user = insert(:user, local: true)
1118
1119 assert User.visible_for?(user, other_user)
1120 end
1121
1122 test "returns true when the account is unauthenticated and being viewed by a privileged account (auth required)" do
1123 Pleroma.Config.put([:instance, :account_activation_required], true)
1124
1125 user = insert(:user, local: true, info: %{confirmation_pending: true})
1126 other_user = insert(:user, local: true, info: %{is_admin: true})
1127
1128 assert User.visible_for?(user, other_user)
1129
1130 Pleroma.Config.put([:instance, :account_activation_required], false)
1131 end
1132 end
1133
1134 describe "parse_bio/2" do
1135 test "preserves hosts in user links text" do
1136 remote_user = insert(:user, local: false, nickname: "nick@domain.com")
1137 user = insert(:user)
1138 bio = "A.k.a. @nick@domain.com"
1139
1140 expected_text =
1141 "A.k.a. <span class='h-card'><a data-user='#{remote_user.id}' class='u-url mention' href='#{
1142 remote_user.ap_id
1143 }'>@<span>nick@domain.com</span></a></span>"
1144
1145 assert expected_text == User.parse_bio(bio, user)
1146 end
1147
1148 test "Adds rel=me on linkbacked urls" do
1149 user = insert(:user, ap_id: "http://social.example.org/users/lain")
1150
1151 bio = "http://example.org/rel_me/null"
1152 expected_text = "<a href=\"#{bio}\">#{bio}</a>"
1153 assert expected_text == User.parse_bio(bio, user)
1154
1155 bio = "http://example.org/rel_me/link"
1156 expected_text = "<a href=\"#{bio}\">#{bio}</a>"
1157 assert expected_text == User.parse_bio(bio, user)
1158
1159 bio = "http://example.org/rel_me/anchor"
1160 expected_text = "<a href=\"#{bio}\">#{bio}</a>"
1161 assert expected_text == User.parse_bio(bio, user)
1162 end
1163 end
1164
1165 test "follower count is updated when a follower is blocked" do
1166 user = insert(:user)
1167 follower = insert(:user)
1168 follower2 = insert(:user)
1169 follower3 = insert(:user)
1170
1171 {:ok, follower} = User.follow(follower, user)
1172 {:ok, _follower2} = User.follow(follower2, user)
1173 {:ok, _follower3} = User.follow(follower3, user)
1174
1175 {:ok, _} = User.block(user, follower)
1176
1177 user_show = Pleroma.Web.TwitterAPI.UserView.render("show.json", %{user: user})
1178
1179 assert Map.get(user_show, "followers_count") == 2
1180 end
1181
1182 describe "list_inactive_users_query/1" do
1183 defp days_ago(days) do
1184 NaiveDateTime.add(
1185 NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second),
1186 -days * 60 * 60 * 24,
1187 :second
1188 )
1189 end
1190
1191 test "Users are inactive by default" do
1192 total = 10
1193
1194 users =
1195 Enum.map(1..total, fn _ ->
1196 insert(:user, last_digest_emailed_at: days_ago(20), info: %{deactivated: false})
1197 end)
1198
1199 inactive_users_ids =
1200 Pleroma.User.list_inactive_users_query()
1201 |> Pleroma.Repo.all()
1202 |> Enum.map(& &1.id)
1203
1204 Enum.each(users, fn user ->
1205 assert user.id in inactive_users_ids
1206 end)
1207 end
1208
1209 test "Only includes users who has no recent activity" do
1210 total = 10
1211
1212 users =
1213 Enum.map(1..total, fn _ ->
1214 insert(:user, last_digest_emailed_at: days_ago(20), info: %{deactivated: false})
1215 end)
1216
1217 {inactive, active} = Enum.split(users, trunc(total / 2))
1218
1219 Enum.map(active, fn user ->
1220 to = Enum.random(users -- [user])
1221
1222 {:ok, _} =
1223 Pleroma.Web.TwitterAPI.TwitterAPI.create_status(user, %{
1224 "status" => "hey @#{to.nickname}"
1225 })
1226 end)
1227
1228 inactive_users_ids =
1229 Pleroma.User.list_inactive_users_query()
1230 |> Pleroma.Repo.all()
1231 |> Enum.map(& &1.id)
1232
1233 Enum.each(active, fn user ->
1234 refute user.id in inactive_users_ids
1235 end)
1236
1237 Enum.each(inactive, fn user ->
1238 assert user.id in inactive_users_ids
1239 end)
1240 end
1241
1242 test "Only includes users with no read notifications" do
1243 total = 10
1244
1245 users =
1246 Enum.map(1..total, fn _ ->
1247 insert(:user, last_digest_emailed_at: days_ago(20), info: %{deactivated: false})
1248 end)
1249
1250 [sender | recipients] = users
1251 {inactive, active} = Enum.split(recipients, trunc(total / 2))
1252
1253 Enum.each(recipients, fn to ->
1254 {:ok, _} =
1255 Pleroma.Web.TwitterAPI.TwitterAPI.create_status(sender, %{
1256 "status" => "hey @#{to.nickname}"
1257 })
1258
1259 {:ok, _} =
1260 Pleroma.Web.TwitterAPI.TwitterAPI.create_status(sender, %{
1261 "status" => "hey again @#{to.nickname}"
1262 })
1263 end)
1264
1265 Enum.each(active, fn user ->
1266 [n1, _n2] = Pleroma.Notification.for_user(user)
1267 {:ok, _} = Pleroma.Notification.read_one(user, n1.id)
1268 end)
1269
1270 inactive_users_ids =
1271 Pleroma.User.list_inactive_users_query()
1272 |> Pleroma.Repo.all()
1273 |> Enum.map(& &1.id)
1274
1275 Enum.each(active, fn user ->
1276 refute user.id in inactive_users_ids
1277 end)
1278
1279 Enum.each(inactive, fn user ->
1280 assert user.id in inactive_users_ids
1281 end)
1282 end
1283 end
1284
1285 describe "toggle_confirmation/1" do
1286 test "if user is confirmed" do
1287 user = insert(:user, info: %{confirmation_pending: false})
1288 {:ok, user} = User.toggle_confirmation(user)
1289
1290 assert user.info.confirmation_pending
1291 assert user.info.confirmation_token
1292 end
1293
1294 test "if user is unconfirmed" do
1295 user = insert(:user, info: %{confirmation_pending: true, confirmation_token: "some token"})
1296 {:ok, user} = User.toggle_confirmation(user)
1297
1298 refute user.info.confirmation_pending
1299 refute user.info.confirmation_token
1300 end
1301 end
1302
1303 describe "ensure_keys_present" do
1304 test "it creates keys for a user and stores them in info" do
1305 user = insert(:user)
1306 refute is_binary(user.info.keys)
1307 {:ok, user} = User.ensure_keys_present(user)
1308 assert is_binary(user.info.keys)
1309 end
1310
1311 test "it doesn't create keys if there already are some" do
1312 user = insert(:user, %{info: %{keys: "xxx"}})
1313 {:ok, user} = User.ensure_keys_present(user)
1314 assert user.info.keys == "xxx"
1315 end
1316 end
1317
1318 describe "get_ap_ids_by_nicknames" do
1319 test "it returns a list of AP ids for a given set of nicknames" do
1320 user = insert(:user)
1321 user_two = insert(:user)
1322
1323 ap_ids = User.get_ap_ids_by_nicknames([user.nickname, user_two.nickname, "nonexistent"])
1324 assert length(ap_ids) == 2
1325 assert user.ap_id in ap_ids
1326 assert user_two.ap_id in ap_ids
1327 end
1328 end
1329
1330 describe "sync followers count" do
1331 setup do
1332 user1 = insert(:user, local: false, ap_id: "http://localhost:4001/users/masto_closed")
1333 user2 = insert(:user, local: false, ap_id: "http://localhost:4001/users/fuser2")
1334 insert(:user, local: true)
1335 insert(:user, local: false, info: %{deactivated: true})
1336 {:ok, user1: user1, user2: user2}
1337 end
1338
1339 test "external_users/1 external active users with limit", %{user1: user1, user2: user2} do
1340 [fdb_user1] = User.external_users(limit: 1)
1341
1342 assert fdb_user1.ap_id
1343 assert fdb_user1.ap_id == user1.ap_id
1344 assert fdb_user1.id == user1.id
1345
1346 [fdb_user2] = User.external_users(max_id: fdb_user1.id, limit: 1)
1347
1348 assert fdb_user2.ap_id
1349 assert fdb_user2.ap_id == user2.ap_id
1350 assert fdb_user2.id == user2.id
1351
1352 assert User.external_users(max_id: fdb_user2.id, limit: 1) == []
1353 end
1354 end
1355
1356 describe "set_info_cache/2" do
1357 setup do
1358 user = insert(:user)
1359 {:ok, user: user}
1360 end
1361
1362 test "update from args", %{user: user} do
1363 User.set_info_cache(user, %{following_count: 15, follower_count: 18})
1364
1365 %{follower_count: followers, following_count: following} = User.get_cached_user_info(user)
1366 assert followers == 18
1367 assert following == 15
1368 end
1369
1370 test "without args", %{user: user} do
1371 User.set_info_cache(user, %{})
1372
1373 %{follower_count: followers, following_count: following} = User.get_cached_user_info(user)
1374 assert followers == 0
1375 assert following == 0
1376 end
1377 end
1378
1379 describe "user_info/2" do
1380 setup do
1381 user = insert(:user)
1382 {:ok, user: user}
1383 end
1384
1385 test "update from args", %{user: user} do
1386 %{follower_count: followers, following_count: following} =
1387 User.user_info(user, %{following_count: 15, follower_count: 18})
1388
1389 assert followers == 18
1390 assert following == 15
1391 end
1392
1393 test "without args", %{user: user} do
1394 %{follower_count: followers, following_count: following} = User.user_info(user)
1395
1396 assert followers == 0
1397 assert following == 0
1398 end
1399 end
1400 end