Merge branch 'by-approval' into 'develop'
[akkoma] / test / user_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.UserTest do
6 alias Pleroma.Activity
7 alias Pleroma.Builders.UserBuilder
8 alias Pleroma.Object
9 alias Pleroma.Repo
10 alias Pleroma.Tests.ObanHelpers
11 alias Pleroma.User
12 alias Pleroma.Web.ActivityPub.ActivityPub
13 alias Pleroma.Web.CommonAPI
14
15 use Pleroma.DataCase
16 use Oban.Testing, repo: Pleroma.Repo
17
18 import Pleroma.Factory
19 import ExUnit.CaptureLog
20 import Swoosh.TestAssertions
21
22 setup_all do
23 Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
24 :ok
25 end
26
27 setup do: clear_config([:instance, :account_activation_required])
28
29 describe "service actors" do
30 test "returns updated invisible actor" do
31 uri = "#{Pleroma.Web.Endpoint.url()}/relay"
32 followers_uri = "#{uri}/followers"
33
34 insert(
35 :user,
36 %{
37 nickname: "relay",
38 invisible: false,
39 local: true,
40 ap_id: uri,
41 follower_address: followers_uri
42 }
43 )
44
45 actor = User.get_or_create_service_actor_by_ap_id(uri, "relay")
46 assert actor.invisible
47 end
48
49 test "returns relay user" do
50 uri = "#{Pleroma.Web.Endpoint.url()}/relay"
51 followers_uri = "#{uri}/followers"
52
53 assert %User{
54 nickname: "relay",
55 invisible: true,
56 local: true,
57 ap_id: ^uri,
58 follower_address: ^followers_uri
59 } = User.get_or_create_service_actor_by_ap_id(uri, "relay")
60
61 assert capture_log(fn ->
62 refute User.get_or_create_service_actor_by_ap_id("/relay", "relay")
63 end) =~ "Cannot create service actor:"
64 end
65
66 test "returns invisible actor" do
67 uri = "#{Pleroma.Web.Endpoint.url()}/internal/fetch-test"
68 followers_uri = "#{uri}/followers"
69 user = User.get_or_create_service_actor_by_ap_id(uri, "internal.fetch-test")
70
71 assert %User{
72 nickname: "internal.fetch-test",
73 invisible: true,
74 local: true,
75 ap_id: ^uri,
76 follower_address: ^followers_uri
77 } = user
78
79 user2 = User.get_or_create_service_actor_by_ap_id(uri, "internal.fetch-test")
80 assert user.id == user2.id
81 end
82 end
83
84 describe "AP ID user relationships" do
85 setup do
86 {:ok, user: insert(:user)}
87 end
88
89 test "outgoing_relationships_ap_ids/1", %{user: user} do
90 rel_types = [:block, :mute, :notification_mute, :reblog_mute, :inverse_subscription]
91
92 ap_ids_by_rel =
93 Enum.into(
94 rel_types,
95 %{},
96 fn rel_type ->
97 rel_records =
98 insert_list(2, :user_relationship, %{source: user, relationship_type: rel_type})
99
100 ap_ids = Enum.map(rel_records, fn rr -> Repo.preload(rr, :target).target.ap_id end)
101 {rel_type, Enum.sort(ap_ids)}
102 end
103 )
104
105 assert ap_ids_by_rel[:block] == Enum.sort(User.blocked_users_ap_ids(user))
106 assert ap_ids_by_rel[:block] == Enum.sort(Enum.map(User.blocked_users(user), & &1.ap_id))
107
108 assert ap_ids_by_rel[:mute] == Enum.sort(User.muted_users_ap_ids(user))
109 assert ap_ids_by_rel[:mute] == Enum.sort(Enum.map(User.muted_users(user), & &1.ap_id))
110
111 assert ap_ids_by_rel[:notification_mute] ==
112 Enum.sort(User.notification_muted_users_ap_ids(user))
113
114 assert ap_ids_by_rel[:notification_mute] ==
115 Enum.sort(Enum.map(User.notification_muted_users(user), & &1.ap_id))
116
117 assert ap_ids_by_rel[:reblog_mute] == Enum.sort(User.reblog_muted_users_ap_ids(user))
118
119 assert ap_ids_by_rel[:reblog_mute] ==
120 Enum.sort(Enum.map(User.reblog_muted_users(user), & &1.ap_id))
121
122 assert ap_ids_by_rel[:inverse_subscription] == Enum.sort(User.subscriber_users_ap_ids(user))
123
124 assert ap_ids_by_rel[:inverse_subscription] ==
125 Enum.sort(Enum.map(User.subscriber_users(user), & &1.ap_id))
126
127 outgoing_relationships_ap_ids = User.outgoing_relationships_ap_ids(user, rel_types)
128
129 assert ap_ids_by_rel ==
130 Enum.into(outgoing_relationships_ap_ids, %{}, fn {k, v} -> {k, Enum.sort(v)} end)
131 end
132 end
133
134 describe "when tags are nil" do
135 test "tagging a user" do
136 user = insert(:user, %{tags: nil})
137 user = User.tag(user, ["cool", "dude"])
138
139 assert "cool" in user.tags
140 assert "dude" in user.tags
141 end
142
143 test "untagging a user" do
144 user = insert(:user, %{tags: nil})
145 user = User.untag(user, ["cool", "dude"])
146
147 assert user.tags == []
148 end
149 end
150
151 test "ap_id returns the activity pub id for the user" do
152 user = UserBuilder.build()
153
154 expected_ap_id = "#{Pleroma.Web.base_url()}/users/#{user.nickname}"
155
156 assert expected_ap_id == User.ap_id(user)
157 end
158
159 test "ap_followers returns the followers collection for the user" do
160 user = UserBuilder.build()
161
162 expected_followers_collection = "#{User.ap_id(user)}/followers"
163
164 assert expected_followers_collection == User.ap_followers(user)
165 end
166
167 test "ap_following returns the following collection for the user" do
168 user = UserBuilder.build()
169
170 expected_followers_collection = "#{User.ap_id(user)}/following"
171
172 assert expected_followers_collection == User.ap_following(user)
173 end
174
175 test "returns all pending follow requests" do
176 unlocked = insert(:user)
177 locked = insert(:user, locked: true)
178 follower = insert(:user)
179
180 CommonAPI.follow(follower, unlocked)
181 CommonAPI.follow(follower, locked)
182
183 assert [] = User.get_follow_requests(unlocked)
184 assert [activity] = User.get_follow_requests(locked)
185
186 assert activity
187 end
188
189 test "doesn't return already accepted or duplicate follow requests" do
190 locked = insert(:user, locked: true)
191 pending_follower = insert(:user)
192 accepted_follower = insert(:user)
193
194 CommonAPI.follow(pending_follower, locked)
195 CommonAPI.follow(pending_follower, locked)
196 CommonAPI.follow(accepted_follower, locked)
197
198 Pleroma.FollowingRelationship.update(accepted_follower, locked, :follow_accept)
199
200 assert [^pending_follower] = User.get_follow_requests(locked)
201 end
202
203 test "doesn't return follow requests for deactivated accounts" do
204 locked = insert(:user, locked: true)
205 pending_follower = insert(:user, %{deactivated: true})
206
207 CommonAPI.follow(pending_follower, locked)
208
209 assert true == pending_follower.deactivated
210 assert [] = User.get_follow_requests(locked)
211 end
212
213 test "clears follow requests when requester is blocked" do
214 followed = insert(:user, locked: true)
215 follower = insert(:user)
216
217 CommonAPI.follow(follower, followed)
218 assert [_activity] = User.get_follow_requests(followed)
219
220 {:ok, _user_relationship} = User.block(followed, follower)
221 assert [] = User.get_follow_requests(followed)
222 end
223
224 test "follow_all follows mutliple users" do
225 user = insert(:user)
226 followed_zero = insert(:user)
227 followed_one = insert(:user)
228 followed_two = insert(:user)
229 blocked = insert(:user)
230 not_followed = insert(:user)
231 reverse_blocked = insert(:user)
232
233 {:ok, _user_relationship} = User.block(user, blocked)
234 {:ok, _user_relationship} = User.block(reverse_blocked, user)
235
236 {:ok, user} = User.follow(user, followed_zero)
237
238 {:ok, user} = User.follow_all(user, [followed_one, followed_two, blocked, reverse_blocked])
239
240 assert User.following?(user, followed_one)
241 assert User.following?(user, followed_two)
242 assert User.following?(user, followed_zero)
243 refute User.following?(user, not_followed)
244 refute User.following?(user, blocked)
245 refute User.following?(user, reverse_blocked)
246 end
247
248 test "follow_all follows mutliple users without duplicating" do
249 user = insert(:user)
250 followed_zero = insert(:user)
251 followed_one = insert(:user)
252 followed_two = insert(:user)
253
254 {:ok, user} = User.follow_all(user, [followed_zero, followed_one])
255 assert length(User.following(user)) == 3
256
257 {:ok, user} = User.follow_all(user, [followed_one, followed_two])
258 assert length(User.following(user)) == 4
259 end
260
261 test "follow takes a user and another user" do
262 user = insert(:user)
263 followed = insert(:user)
264
265 {:ok, user} = User.follow(user, followed)
266
267 user = User.get_cached_by_id(user.id)
268 followed = User.get_cached_by_ap_id(followed.ap_id)
269
270 assert followed.follower_count == 1
271 assert user.following_count == 1
272
273 assert User.ap_followers(followed) in User.following(user)
274 end
275
276 test "can't follow a deactivated users" do
277 user = insert(:user)
278 followed = insert(:user, %{deactivated: true})
279
280 {:error, _} = User.follow(user, followed)
281 end
282
283 test "can't follow a user who blocked us" do
284 blocker = insert(:user)
285 blockee = insert(:user)
286
287 {:ok, _user_relationship} = User.block(blocker, blockee)
288
289 {:error, _} = User.follow(blockee, blocker)
290 end
291
292 test "can't subscribe to a user who blocked us" do
293 blocker = insert(:user)
294 blocked = insert(:user)
295
296 {:ok, _user_relationship} = User.block(blocker, blocked)
297
298 {:error, _} = User.subscribe(blocked, blocker)
299 end
300
301 test "local users do not automatically follow local locked accounts" do
302 follower = insert(:user, locked: true)
303 followed = insert(:user, locked: true)
304
305 {:ok, follower} = User.maybe_direct_follow(follower, followed)
306
307 refute User.following?(follower, followed)
308 end
309
310 describe "unfollow/2" do
311 setup do: clear_config([:instance, :external_user_synchronization])
312
313 test "unfollow with syncronizes external user" do
314 Pleroma.Config.put([:instance, :external_user_synchronization], true)
315
316 followed =
317 insert(:user,
318 nickname: "fuser1",
319 follower_address: "http://localhost:4001/users/fuser1/followers",
320 following_address: "http://localhost:4001/users/fuser1/following",
321 ap_id: "http://localhost:4001/users/fuser1"
322 )
323
324 user =
325 insert(:user, %{
326 local: false,
327 nickname: "fuser2",
328 ap_id: "http://localhost:4001/users/fuser2",
329 follower_address: "http://localhost:4001/users/fuser2/followers",
330 following_address: "http://localhost:4001/users/fuser2/following"
331 })
332
333 {:ok, user} = User.follow(user, followed, :follow_accept)
334
335 {:ok, user, _activity} = User.unfollow(user, followed)
336
337 user = User.get_cached_by_id(user.id)
338
339 assert User.following(user) == []
340 end
341
342 test "unfollow takes a user and another user" do
343 followed = insert(:user)
344 user = insert(:user)
345
346 {:ok, user} = User.follow(user, followed, :follow_accept)
347
348 assert User.following(user) == [user.follower_address, followed.follower_address]
349
350 {:ok, user, _activity} = User.unfollow(user, followed)
351
352 assert User.following(user) == [user.follower_address]
353 end
354
355 test "unfollow doesn't unfollow yourself" do
356 user = insert(:user)
357
358 {:error, _} = User.unfollow(user, user)
359
360 assert User.following(user) == [user.follower_address]
361 end
362 end
363
364 test "test if a user is following another user" do
365 followed = insert(:user)
366 user = insert(:user)
367 User.follow(user, followed, :follow_accept)
368
369 assert User.following?(user, followed)
370 refute User.following?(followed, user)
371 end
372
373 test "fetches correct profile for nickname beginning with number" do
374 # Use old-style integer ID to try to reproduce the problem
375 user = insert(:user, %{id: 1080})
376 user_with_numbers = insert(:user, %{nickname: "#{user.id}garbage"})
377 assert user_with_numbers == User.get_cached_by_nickname_or_id(user_with_numbers.nickname)
378 end
379
380 describe "user registration" do
381 @full_user_data %{
382 bio: "A guy",
383 name: "my name",
384 nickname: "nick",
385 password: "test",
386 password_confirmation: "test",
387 email: "email@example.com"
388 }
389
390 setup do: clear_config([:instance, :autofollowed_nicknames])
391 setup do: clear_config([:welcome])
392 setup do: clear_config([:instance, :account_activation_required])
393
394 test "it autofollows accounts that are set for it" do
395 user = insert(:user)
396 remote_user = insert(:user, %{local: false})
397
398 Pleroma.Config.put([:instance, :autofollowed_nicknames], [
399 user.nickname,
400 remote_user.nickname
401 ])
402
403 cng = User.register_changeset(%User{}, @full_user_data)
404
405 {:ok, registered_user} = User.register(cng)
406
407 assert User.following?(registered_user, user)
408 refute User.following?(registered_user, remote_user)
409 end
410
411 test "it sends a welcome message if it is set" do
412 welcome_user = insert(:user)
413 Pleroma.Config.put([:welcome, :direct_message, :enabled], true)
414 Pleroma.Config.put([:welcome, :direct_message, :sender_nickname], welcome_user.nickname)
415 Pleroma.Config.put([:welcome, :direct_message, :message], "Hello, this is a cool site")
416
417 Pleroma.Config.put([:welcome, :email, :enabled], true)
418 Pleroma.Config.put([:welcome, :email, :sender], welcome_user.email)
419
420 Pleroma.Config.put(
421 [:welcome, :email, :subject],
422 "Hello, welcome to cool site: <%= instance_name %>"
423 )
424
425 instance_name = Pleroma.Config.get([:instance, :name])
426
427 cng = User.register_changeset(%User{}, @full_user_data)
428 {:ok, registered_user} = User.register(cng)
429 ObanHelpers.perform_all()
430
431 activity = Repo.one(Pleroma.Activity)
432 assert registered_user.ap_id in activity.recipients
433 assert Object.normalize(activity).data["content"] =~ "cool site"
434 assert activity.actor == welcome_user.ap_id
435
436 assert_email_sent(
437 from: {instance_name, welcome_user.email},
438 to: {registered_user.name, registered_user.email},
439 subject: "Hello, welcome to cool site: #{instance_name}",
440 html_body: "Welcome to #{instance_name}"
441 )
442 end
443
444 test "it sends a confirm email" do
445 Pleroma.Config.put([:instance, :account_activation_required], true)
446
447 cng = User.register_changeset(%User{}, @full_user_data)
448 {:ok, registered_user} = User.register(cng)
449 ObanHelpers.perform_all()
450 assert_email_sent(Pleroma.Emails.UserEmail.account_confirmation_email(registered_user))
451 end
452
453 test "it requires an email, name, nickname and password, bio is optional when account_activation_required is enabled" do
454 Pleroma.Config.put([:instance, :account_activation_required], true)
455
456 @full_user_data
457 |> Map.keys()
458 |> Enum.each(fn key ->
459 params = Map.delete(@full_user_data, key)
460 changeset = User.register_changeset(%User{}, params)
461
462 assert if key == :bio, do: changeset.valid?, else: not changeset.valid?
463 end)
464 end
465
466 test "it requires an name, nickname and password, bio and email are optional when account_activation_required is disabled" do
467 Pleroma.Config.put([:instance, :account_activation_required], false)
468
469 @full_user_data
470 |> Map.keys()
471 |> Enum.each(fn key ->
472 params = Map.delete(@full_user_data, key)
473 changeset = User.register_changeset(%User{}, params)
474
475 assert if key in [:bio, :email], do: changeset.valid?, else: not changeset.valid?
476 end)
477 end
478
479 test "it restricts certain nicknames" do
480 [restricted_name | _] = Pleroma.Config.get([User, :restricted_nicknames])
481
482 assert is_bitstring(restricted_name)
483
484 params =
485 @full_user_data
486 |> Map.put(:nickname, restricted_name)
487
488 changeset = User.register_changeset(%User{}, params)
489
490 refute changeset.valid?
491 end
492
493 test "it sets the password_hash and ap_id" do
494 changeset = User.register_changeset(%User{}, @full_user_data)
495
496 assert changeset.valid?
497
498 assert is_binary(changeset.changes[:password_hash])
499 assert changeset.changes[:ap_id] == User.ap_id(%User{nickname: @full_user_data.nickname})
500
501 assert changeset.changes.follower_address == "#{changeset.changes.ap_id}/followers"
502 end
503 end
504
505 describe "user registration, with :account_activation_required" do
506 @full_user_data %{
507 bio: "A guy",
508 name: "my name",
509 nickname: "nick",
510 password: "test",
511 password_confirmation: "test",
512 email: "email@example.com"
513 }
514 setup do: clear_config([:instance, :account_activation_required], true)
515
516 test "it sets the 'accepts_chat_messages' set to true" do
517 changeset = User.register_changeset(%User{}, @full_user_data)
518 assert changeset.valid?
519
520 {:ok, user} = Repo.insert(changeset)
521
522 assert user.accepts_chat_messages
523 end
524
525 test "it creates unconfirmed user" do
526 changeset = User.register_changeset(%User{}, @full_user_data)
527 assert changeset.valid?
528
529 {:ok, user} = Repo.insert(changeset)
530
531 assert user.confirmation_pending
532 assert user.confirmation_token
533 end
534
535 test "it creates confirmed user if :confirmed option is given" do
536 changeset = User.register_changeset(%User{}, @full_user_data, need_confirmation: false)
537 assert changeset.valid?
538
539 {:ok, user} = Repo.insert(changeset)
540
541 refute user.confirmation_pending
542 refute user.confirmation_token
543 end
544 end
545
546 describe "user registration, with :account_approval_required" do
547 @full_user_data %{
548 bio: "A guy",
549 name: "my name",
550 nickname: "nick",
551 password: "test",
552 password_confirmation: "test",
553 email: "email@example.com",
554 registration_reason: "I'm a cool guy :)"
555 }
556 setup do: clear_config([:instance, :account_approval_required], true)
557
558 test "it creates unapproved user" do
559 changeset = User.register_changeset(%User{}, @full_user_data)
560 assert changeset.valid?
561
562 {:ok, user} = Repo.insert(changeset)
563
564 assert user.approval_pending
565 assert user.registration_reason == "I'm a cool guy :)"
566 end
567
568 test "it restricts length of registration reason" do
569 reason_limit = Pleroma.Config.get([:instance, :registration_reason_length])
570
571 assert is_integer(reason_limit)
572
573 params =
574 @full_user_data
575 |> Map.put(
576 :registration_reason,
577 "Quia et nesciunt dolores numquam ipsam nisi sapiente soluta. Ullam repudiandae nisi quam porro officiis officiis ad. Consequatur animi velit ex quia. Odit voluptatem perferendis quia ut nisi. Dignissimos sit soluta atque aliquid dolorem ut dolorum ut. Labore voluptates iste iusto amet voluptatum earum. Ad fugit illum nam eos ut nemo. Pariatur ea fuga non aspernatur. Dignissimos debitis officia corporis est nisi ab et. Atque itaque alias eius voluptas minus. Accusamus numquam tempore occaecati in."
578 )
579
580 changeset = User.register_changeset(%User{}, params)
581
582 refute changeset.valid?
583 end
584 end
585
586 describe "get_or_fetch/1" do
587 test "gets an existing user by nickname" do
588 user = insert(:user)
589 {:ok, fetched_user} = User.get_or_fetch(user.nickname)
590
591 assert user == fetched_user
592 end
593
594 test "gets an existing user by ap_id" do
595 ap_id = "http://mastodon.example.org/users/admin"
596
597 user =
598 insert(
599 :user,
600 local: false,
601 nickname: "admin@mastodon.example.org",
602 ap_id: ap_id
603 )
604
605 {:ok, fetched_user} = User.get_or_fetch(ap_id)
606 freshed_user = refresh_record(user)
607 assert freshed_user == fetched_user
608 end
609 end
610
611 describe "fetching a user from nickname or trying to build one" do
612 test "gets an existing user" do
613 user = insert(:user)
614 {:ok, fetched_user} = User.get_or_fetch_by_nickname(user.nickname)
615
616 assert user == fetched_user
617 end
618
619 test "gets an existing user, case insensitive" do
620 user = insert(:user, nickname: "nick")
621 {:ok, fetched_user} = User.get_or_fetch_by_nickname("NICK")
622
623 assert user == fetched_user
624 end
625
626 test "gets an existing user by fully qualified nickname" do
627 user = insert(:user)
628
629 {:ok, fetched_user} =
630 User.get_or_fetch_by_nickname(user.nickname <> "@" <> Pleroma.Web.Endpoint.host())
631
632 assert user == fetched_user
633 end
634
635 test "gets an existing user by fully qualified nickname, case insensitive" do
636 user = insert(:user, nickname: "nick")
637 casing_altered_fqn = String.upcase(user.nickname <> "@" <> Pleroma.Web.Endpoint.host())
638
639 {:ok, fetched_user} = User.get_or_fetch_by_nickname(casing_altered_fqn)
640
641 assert user == fetched_user
642 end
643
644 @tag capture_log: true
645 test "returns nil if no user could be fetched" do
646 {:error, fetched_user} = User.get_or_fetch_by_nickname("nonexistant@social.heldscal.la")
647 assert fetched_user == "not found nonexistant@social.heldscal.la"
648 end
649
650 test "returns nil for nonexistant local user" do
651 {:error, fetched_user} = User.get_or_fetch_by_nickname("nonexistant")
652 assert fetched_user == "not found nonexistant"
653 end
654
655 test "updates an existing user, if stale" do
656 a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
657
658 orig_user =
659 insert(
660 :user,
661 local: false,
662 nickname: "admin@mastodon.example.org",
663 ap_id: "http://mastodon.example.org/users/admin",
664 last_refreshed_at: a_week_ago
665 )
666
667 assert orig_user.last_refreshed_at == a_week_ago
668
669 {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/admin")
670
671 assert user.inbox
672
673 refute user.last_refreshed_at == orig_user.last_refreshed_at
674 end
675
676 test "if nicknames clash, the old user gets a prefix with the old id to the nickname" do
677 a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
678
679 orig_user =
680 insert(
681 :user,
682 local: false,
683 nickname: "admin@mastodon.example.org",
684 ap_id: "http://mastodon.example.org/users/harinezumigari",
685 last_refreshed_at: a_week_ago
686 )
687
688 assert orig_user.last_refreshed_at == a_week_ago
689
690 {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/admin")
691
692 assert user.inbox
693
694 refute user.id == orig_user.id
695
696 orig_user = User.get_by_id(orig_user.id)
697
698 assert orig_user.nickname == "#{orig_user.id}.admin@mastodon.example.org"
699 end
700
701 @tag capture_log: true
702 test "it returns the old user if stale, but unfetchable" do
703 a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
704
705 orig_user =
706 insert(
707 :user,
708 local: false,
709 nickname: "admin@mastodon.example.org",
710 ap_id: "http://mastodon.example.org/users/raymoo",
711 last_refreshed_at: a_week_ago
712 )
713
714 assert orig_user.last_refreshed_at == a_week_ago
715
716 {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/raymoo")
717
718 assert user.last_refreshed_at == orig_user.last_refreshed_at
719 end
720 end
721
722 test "returns an ap_id for a user" do
723 user = insert(:user)
724
725 assert User.ap_id(user) ==
726 Pleroma.Web.Router.Helpers.user_feed_url(
727 Pleroma.Web.Endpoint,
728 :feed_redirect,
729 user.nickname
730 )
731 end
732
733 test "returns an ap_followers link for a user" do
734 user = insert(:user)
735
736 assert User.ap_followers(user) ==
737 Pleroma.Web.Router.Helpers.user_feed_url(
738 Pleroma.Web.Endpoint,
739 :feed_redirect,
740 user.nickname
741 ) <> "/followers"
742 end
743
744 describe "remote user changeset" do
745 @valid_remote %{
746 bio: "hello",
747 name: "Someone",
748 nickname: "a@b.de",
749 ap_id: "http...",
750 avatar: %{some: "avatar"}
751 }
752 setup do: clear_config([:instance, :user_bio_length])
753 setup do: clear_config([:instance, :user_name_length])
754
755 test "it confirms validity" do
756 cs = User.remote_user_changeset(@valid_remote)
757 assert cs.valid?
758 end
759
760 test "it sets the follower_adress" do
761 cs = User.remote_user_changeset(@valid_remote)
762 # remote users get a fake local follower address
763 assert cs.changes.follower_address ==
764 User.ap_followers(%User{nickname: @valid_remote[:nickname]})
765 end
766
767 test "it enforces the fqn format for nicknames" do
768 cs = User.remote_user_changeset(%{@valid_remote | nickname: "bla"})
769 assert Ecto.Changeset.get_field(cs, :local) == false
770 assert cs.changes.avatar
771 refute cs.valid?
772 end
773
774 test "it has required fields" do
775 [:ap_id]
776 |> Enum.each(fn field ->
777 cs = User.remote_user_changeset(Map.delete(@valid_remote, field))
778 refute cs.valid?
779 end)
780 end
781 end
782
783 describe "followers and friends" do
784 test "gets all followers for a given user" do
785 user = insert(:user)
786 follower_one = insert(:user)
787 follower_two = insert(:user)
788 not_follower = insert(:user)
789
790 {:ok, follower_one} = User.follow(follower_one, user)
791 {:ok, follower_two} = User.follow(follower_two, user)
792
793 res = User.get_followers(user)
794
795 assert Enum.member?(res, follower_one)
796 assert Enum.member?(res, follower_two)
797 refute Enum.member?(res, not_follower)
798 end
799
800 test "gets all friends (followed users) for a given user" do
801 user = insert(:user)
802 followed_one = insert(:user)
803 followed_two = insert(:user)
804 not_followed = insert(:user)
805
806 {:ok, user} = User.follow(user, followed_one)
807 {:ok, user} = User.follow(user, followed_two)
808
809 res = User.get_friends(user)
810
811 followed_one = User.get_cached_by_ap_id(followed_one.ap_id)
812 followed_two = User.get_cached_by_ap_id(followed_two.ap_id)
813 assert Enum.member?(res, followed_one)
814 assert Enum.member?(res, followed_two)
815 refute Enum.member?(res, not_followed)
816 end
817 end
818
819 describe "updating note and follower count" do
820 test "it sets the note_count property" do
821 note = insert(:note)
822
823 user = User.get_cached_by_ap_id(note.data["actor"])
824
825 assert user.note_count == 0
826
827 {:ok, user} = User.update_note_count(user)
828
829 assert user.note_count == 1
830 end
831
832 test "it increases the note_count property" do
833 note = insert(:note)
834 user = User.get_cached_by_ap_id(note.data["actor"])
835
836 assert user.note_count == 0
837
838 {:ok, user} = User.increase_note_count(user)
839
840 assert user.note_count == 1
841
842 {:ok, user} = User.increase_note_count(user)
843
844 assert user.note_count == 2
845 end
846
847 test "it decreases the note_count property" do
848 note = insert(:note)
849 user = User.get_cached_by_ap_id(note.data["actor"])
850
851 assert user.note_count == 0
852
853 {:ok, user} = User.increase_note_count(user)
854
855 assert user.note_count == 1
856
857 {:ok, user} = User.decrease_note_count(user)
858
859 assert user.note_count == 0
860
861 {:ok, user} = User.decrease_note_count(user)
862
863 assert user.note_count == 0
864 end
865
866 test "it sets the follower_count property" do
867 user = insert(:user)
868 follower = insert(:user)
869
870 User.follow(follower, user)
871
872 assert user.follower_count == 0
873
874 {:ok, user} = User.update_follower_count(user)
875
876 assert user.follower_count == 1
877 end
878 end
879
880 describe "follow_import" do
881 test "it imports user followings from list" do
882 [user1, user2, user3] = insert_list(3, :user)
883
884 identifiers = [
885 user2.ap_id,
886 user3.nickname
887 ]
888
889 {:ok, job} = User.follow_import(user1, identifiers)
890
891 assert {:ok, result} = ObanHelpers.perform(job)
892 assert is_list(result)
893 assert result == [user2, user3]
894 end
895 end
896
897 describe "mutes" do
898 test "it mutes people" do
899 user = insert(:user)
900 muted_user = insert(:user)
901
902 refute User.mutes?(user, muted_user)
903 refute User.muted_notifications?(user, muted_user)
904
905 {:ok, _user_relationships} = User.mute(user, muted_user)
906
907 assert User.mutes?(user, muted_user)
908 assert User.muted_notifications?(user, muted_user)
909 end
910
911 test "it unmutes users" do
912 user = insert(:user)
913 muted_user = insert(:user)
914
915 {:ok, _user_relationships} = User.mute(user, muted_user)
916 {:ok, _user_mute} = User.unmute(user, muted_user)
917
918 refute User.mutes?(user, muted_user)
919 refute User.muted_notifications?(user, muted_user)
920 end
921
922 test "it mutes user without notifications" do
923 user = insert(:user)
924 muted_user = insert(:user)
925
926 refute User.mutes?(user, muted_user)
927 refute User.muted_notifications?(user, muted_user)
928
929 {:ok, _user_relationships} = User.mute(user, muted_user, false)
930
931 assert User.mutes?(user, muted_user)
932 refute User.muted_notifications?(user, muted_user)
933 end
934 end
935
936 describe "blocks" do
937 test "it blocks people" do
938 user = insert(:user)
939 blocked_user = insert(:user)
940
941 refute User.blocks?(user, blocked_user)
942
943 {:ok, _user_relationship} = User.block(user, blocked_user)
944
945 assert User.blocks?(user, blocked_user)
946 end
947
948 test "it unblocks users" do
949 user = insert(:user)
950 blocked_user = insert(:user)
951
952 {:ok, _user_relationship} = User.block(user, blocked_user)
953 {:ok, _user_block} = User.unblock(user, blocked_user)
954
955 refute User.blocks?(user, blocked_user)
956 end
957
958 test "blocks tear down cyclical follow relationships" do
959 blocker = insert(:user)
960 blocked = insert(:user)
961
962 {:ok, blocker} = User.follow(blocker, blocked)
963 {:ok, blocked} = User.follow(blocked, blocker)
964
965 assert User.following?(blocker, blocked)
966 assert User.following?(blocked, blocker)
967
968 {:ok, _user_relationship} = User.block(blocker, blocked)
969 blocked = User.get_cached_by_id(blocked.id)
970
971 assert User.blocks?(blocker, blocked)
972
973 refute User.following?(blocker, blocked)
974 refute User.following?(blocked, blocker)
975 end
976
977 test "blocks tear down blocker->blocked follow relationships" do
978 blocker = insert(:user)
979 blocked = insert(:user)
980
981 {:ok, blocker} = User.follow(blocker, blocked)
982
983 assert User.following?(blocker, blocked)
984 refute User.following?(blocked, blocker)
985
986 {:ok, _user_relationship} = User.block(blocker, blocked)
987 blocked = User.get_cached_by_id(blocked.id)
988
989 assert User.blocks?(blocker, blocked)
990
991 refute User.following?(blocker, blocked)
992 refute User.following?(blocked, blocker)
993 end
994
995 test "blocks tear down blocked->blocker follow relationships" do
996 blocker = insert(:user)
997 blocked = insert(:user)
998
999 {:ok, blocked} = User.follow(blocked, blocker)
1000
1001 refute User.following?(blocker, blocked)
1002 assert User.following?(blocked, blocker)
1003
1004 {:ok, _user_relationship} = User.block(blocker, blocked)
1005 blocked = User.get_cached_by_id(blocked.id)
1006
1007 assert User.blocks?(blocker, blocked)
1008
1009 refute User.following?(blocker, blocked)
1010 refute User.following?(blocked, blocker)
1011 end
1012
1013 test "blocks tear down blocked->blocker subscription relationships" do
1014 blocker = insert(:user)
1015 blocked = insert(:user)
1016
1017 {:ok, _subscription} = User.subscribe(blocked, blocker)
1018
1019 assert User.subscribed_to?(blocked, blocker)
1020 refute User.subscribed_to?(blocker, blocked)
1021
1022 {:ok, _user_relationship} = User.block(blocker, blocked)
1023
1024 assert User.blocks?(blocker, blocked)
1025 refute User.subscribed_to?(blocker, blocked)
1026 refute User.subscribed_to?(blocked, blocker)
1027 end
1028 end
1029
1030 describe "domain blocking" do
1031 test "blocks domains" do
1032 user = insert(:user)
1033 collateral_user = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1034
1035 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1036
1037 assert User.blocks?(user, collateral_user)
1038 end
1039
1040 test "does not block domain with same end" do
1041 user = insert(:user)
1042
1043 collateral_user =
1044 insert(:user, %{ap_id: "https://another-awful-and-rude-instance.com/user/bully"})
1045
1046 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1047
1048 refute User.blocks?(user, collateral_user)
1049 end
1050
1051 test "does not block domain with same end if wildcard added" do
1052 user = insert(:user)
1053
1054 collateral_user =
1055 insert(:user, %{ap_id: "https://another-awful-and-rude-instance.com/user/bully"})
1056
1057 {:ok, user} = User.block_domain(user, "*.awful-and-rude-instance.com")
1058
1059 refute User.blocks?(user, collateral_user)
1060 end
1061
1062 test "blocks domain with wildcard for subdomain" do
1063 user = insert(:user)
1064
1065 user_from_subdomain =
1066 insert(:user, %{ap_id: "https://subdomain.awful-and-rude-instance.com/user/bully"})
1067
1068 user_with_two_subdomains =
1069 insert(:user, %{
1070 ap_id: "https://subdomain.second_subdomain.awful-and-rude-instance.com/user/bully"
1071 })
1072
1073 user_domain = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1074
1075 {:ok, user} = User.block_domain(user, "*.awful-and-rude-instance.com")
1076
1077 assert User.blocks?(user, user_from_subdomain)
1078 assert User.blocks?(user, user_with_two_subdomains)
1079 assert User.blocks?(user, user_domain)
1080 end
1081
1082 test "unblocks domains" do
1083 user = insert(:user)
1084 collateral_user = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1085
1086 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1087 {:ok, user} = User.unblock_domain(user, "awful-and-rude-instance.com")
1088
1089 refute User.blocks?(user, collateral_user)
1090 end
1091
1092 test "follows take precedence over domain blocks" do
1093 user = insert(:user)
1094 good_eggo = insert(:user, %{ap_id: "https://meanies.social/user/cuteposter"})
1095
1096 {:ok, user} = User.block_domain(user, "meanies.social")
1097 {:ok, user} = User.follow(user, good_eggo)
1098
1099 refute User.blocks?(user, good_eggo)
1100 end
1101 end
1102
1103 describe "blocks_import" do
1104 test "it imports user blocks from list" do
1105 [user1, user2, user3] = insert_list(3, :user)
1106
1107 identifiers = [
1108 user2.ap_id,
1109 user3.nickname
1110 ]
1111
1112 {:ok, job} = User.blocks_import(user1, identifiers)
1113
1114 assert {:ok, result} = ObanHelpers.perform(job)
1115 assert is_list(result)
1116 assert result == [user2, user3]
1117 end
1118 end
1119
1120 describe "get_recipients_from_activity" do
1121 test "works for announces" do
1122 actor = insert(:user)
1123 user = insert(:user, local: true)
1124
1125 {:ok, activity} = CommonAPI.post(actor, %{status: "hello"})
1126 {:ok, announce} = CommonAPI.repeat(activity.id, user)
1127
1128 recipients = User.get_recipients_from_activity(announce)
1129
1130 assert user in recipients
1131 end
1132
1133 test "get recipients" do
1134 actor = insert(:user)
1135 user = insert(:user, local: true)
1136 user_two = insert(:user, local: false)
1137 addressed = insert(:user, local: true)
1138 addressed_remote = insert(:user, local: false)
1139
1140 {:ok, activity} =
1141 CommonAPI.post(actor, %{
1142 status: "hey @#{addressed.nickname} @#{addressed_remote.nickname}"
1143 })
1144
1145 assert Enum.map([actor, addressed], & &1.ap_id) --
1146 Enum.map(User.get_recipients_from_activity(activity), & &1.ap_id) == []
1147
1148 {:ok, user} = User.follow(user, actor)
1149 {:ok, _user_two} = User.follow(user_two, actor)
1150 recipients = User.get_recipients_from_activity(activity)
1151 assert length(recipients) == 3
1152 assert user in recipients
1153 assert addressed in recipients
1154 end
1155
1156 test "has following" do
1157 actor = insert(:user)
1158 user = insert(:user)
1159 user_two = insert(:user)
1160 addressed = insert(:user, local: true)
1161
1162 {:ok, activity} =
1163 CommonAPI.post(actor, %{
1164 status: "hey @#{addressed.nickname}"
1165 })
1166
1167 assert Enum.map([actor, addressed], & &1.ap_id) --
1168 Enum.map(User.get_recipients_from_activity(activity), & &1.ap_id) == []
1169
1170 {:ok, _actor} = User.follow(actor, user)
1171 {:ok, _actor} = User.follow(actor, user_two)
1172 recipients = User.get_recipients_from_activity(activity)
1173 assert length(recipients) == 2
1174 assert addressed in recipients
1175 end
1176 end
1177
1178 describe ".deactivate" do
1179 test "can de-activate then re-activate a user" do
1180 user = insert(:user)
1181 assert false == user.deactivated
1182 {:ok, user} = User.deactivate(user)
1183 assert true == user.deactivated
1184 {:ok, user} = User.deactivate(user, false)
1185 assert false == user.deactivated
1186 end
1187
1188 test "hide a user from followers" do
1189 user = insert(:user)
1190 user2 = insert(:user)
1191
1192 {:ok, user} = User.follow(user, user2)
1193 {:ok, _user} = User.deactivate(user)
1194
1195 user2 = User.get_cached_by_id(user2.id)
1196
1197 assert user2.follower_count == 0
1198 assert [] = User.get_followers(user2)
1199 end
1200
1201 test "hide a user from friends" do
1202 user = insert(:user)
1203 user2 = insert(:user)
1204
1205 {:ok, user2} = User.follow(user2, user)
1206 assert user2.following_count == 1
1207 assert User.following_count(user2) == 1
1208
1209 {:ok, _user} = User.deactivate(user)
1210
1211 user2 = User.get_cached_by_id(user2.id)
1212
1213 assert refresh_record(user2).following_count == 0
1214 assert user2.following_count == 0
1215 assert User.following_count(user2) == 0
1216 assert [] = User.get_friends(user2)
1217 end
1218
1219 test "hide a user's statuses from timelines and notifications" do
1220 user = insert(:user)
1221 user2 = insert(:user)
1222
1223 {:ok, user2} = User.follow(user2, user)
1224
1225 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{user2.nickname}"})
1226
1227 activity = Repo.preload(activity, :bookmark)
1228
1229 [notification] = Pleroma.Notification.for_user(user2)
1230 assert notification.activity.id == activity.id
1231
1232 assert [activity] == ActivityPub.fetch_public_activities(%{}) |> Repo.preload(:bookmark)
1233
1234 assert [%{activity | thread_muted?: CommonAPI.thread_muted?(user2, activity)}] ==
1235 ActivityPub.fetch_activities([user2.ap_id | User.following(user2)], %{
1236 user: user2
1237 })
1238
1239 {:ok, _user} = User.deactivate(user)
1240
1241 assert [] == ActivityPub.fetch_public_activities(%{})
1242 assert [] == Pleroma.Notification.for_user(user2)
1243
1244 assert [] ==
1245 ActivityPub.fetch_activities([user2.ap_id | User.following(user2)], %{
1246 user: user2
1247 })
1248 end
1249 end
1250
1251 describe "approve" do
1252 test "approves a user" do
1253 user = insert(:user, approval_pending: true)
1254 assert true == user.approval_pending
1255 {:ok, user} = User.approve(user)
1256 assert false == user.approval_pending
1257 end
1258
1259 test "approves a list of users" do
1260 unapproved_users = [
1261 insert(:user, approval_pending: true),
1262 insert(:user, approval_pending: true),
1263 insert(:user, approval_pending: true)
1264 ]
1265
1266 {:ok, users} = User.approve(unapproved_users)
1267
1268 assert Enum.count(users) == 3
1269
1270 Enum.each(users, fn user ->
1271 assert false == user.approval_pending
1272 end)
1273 end
1274 end
1275
1276 describe "delete" do
1277 setup do
1278 {:ok, user} = insert(:user) |> User.set_cache()
1279
1280 [user: user]
1281 end
1282
1283 setup do: clear_config([:instance, :federating])
1284
1285 test ".delete_user_activities deletes all create activities", %{user: user} do
1286 {:ok, activity} = CommonAPI.post(user, %{status: "2hu"})
1287
1288 User.delete_user_activities(user)
1289
1290 # TODO: Test removal favorites, repeats, delete activities.
1291 refute Activity.get_by_id(activity.id)
1292 end
1293
1294 test "it deactivates a user, all follow relationships and all activities", %{user: user} do
1295 follower = insert(:user)
1296 {:ok, follower} = User.follow(follower, user)
1297
1298 locked_user = insert(:user, name: "locked", locked: true)
1299 {:ok, _} = User.follow(user, locked_user, :follow_pending)
1300
1301 object = insert(:note, user: user)
1302 activity = insert(:note_activity, user: user, note: object)
1303
1304 object_two = insert(:note, user: follower)
1305 activity_two = insert(:note_activity, user: follower, note: object_two)
1306
1307 {:ok, like} = CommonAPI.favorite(user, activity_two.id)
1308 {:ok, like_two} = CommonAPI.favorite(follower, activity.id)
1309 {:ok, repeat} = CommonAPI.repeat(activity_two.id, user)
1310
1311 {:ok, job} = User.delete(user)
1312 {:ok, _user} = ObanHelpers.perform(job)
1313
1314 follower = User.get_cached_by_id(follower.id)
1315
1316 refute User.following?(follower, user)
1317 assert %{deactivated: true} = User.get_by_id(user.id)
1318
1319 assert [] == User.get_follow_requests(locked_user)
1320
1321 user_activities =
1322 user.ap_id
1323 |> Activity.Queries.by_actor()
1324 |> Repo.all()
1325 |> Enum.map(fn act -> act.data["type"] end)
1326
1327 assert Enum.all?(user_activities, fn act -> act in ~w(Delete Undo) end)
1328
1329 refute Activity.get_by_id(activity.id)
1330 refute Activity.get_by_id(like.id)
1331 refute Activity.get_by_id(like_two.id)
1332 refute Activity.get_by_id(repeat.id)
1333 end
1334 end
1335
1336 describe "delete/1 when confirmation is pending" do
1337 setup do
1338 user = insert(:user, confirmation_pending: true)
1339 {:ok, user: user}
1340 end
1341
1342 test "deletes user from database when activation required", %{user: user} do
1343 clear_config([:instance, :account_activation_required], true)
1344
1345 {:ok, job} = User.delete(user)
1346 {:ok, _} = ObanHelpers.perform(job)
1347
1348 refute User.get_cached_by_id(user.id)
1349 refute User.get_by_id(user.id)
1350 end
1351
1352 test "deactivates user when activation is not required", %{user: user} do
1353 clear_config([:instance, :account_activation_required], false)
1354
1355 {:ok, job} = User.delete(user)
1356 {:ok, _} = ObanHelpers.perform(job)
1357
1358 assert %{deactivated: true} = User.get_cached_by_id(user.id)
1359 assert %{deactivated: true} = User.get_by_id(user.id)
1360 end
1361 end
1362
1363 test "delete/1 when approval is pending deletes the user" do
1364 user = insert(:user, approval_pending: true)
1365 {:ok, user: user}
1366
1367 {:ok, job} = User.delete(user)
1368 {:ok, _} = ObanHelpers.perform(job)
1369
1370 refute User.get_cached_by_id(user.id)
1371 refute User.get_by_id(user.id)
1372 end
1373
1374 test "get_public_key_for_ap_id fetches a user that's not in the db" do
1375 assert {:ok, _key} = User.get_public_key_for_ap_id("http://mastodon.example.org/users/admin")
1376 end
1377
1378 describe "per-user rich-text filtering" do
1379 test "html_filter_policy returns default policies, when rich-text is enabled" do
1380 user = insert(:user)
1381
1382 assert Pleroma.Config.get([:markup, :scrub_policy]) == User.html_filter_policy(user)
1383 end
1384
1385 test "html_filter_policy returns TwitterText scrubber when rich-text is disabled" do
1386 user = insert(:user, no_rich_text: true)
1387
1388 assert Pleroma.HTML.Scrubber.TwitterText == User.html_filter_policy(user)
1389 end
1390 end
1391
1392 describe "caching" do
1393 test "invalidate_cache works" do
1394 user = insert(:user)
1395
1396 User.set_cache(user)
1397 User.invalidate_cache(user)
1398
1399 {:ok, nil} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1400 {:ok, nil} = Cachex.get(:user_cache, "nickname:#{user.nickname}")
1401 end
1402
1403 test "User.delete() plugs any possible zombie objects" do
1404 user = insert(:user)
1405
1406 {:ok, job} = User.delete(user)
1407 {:ok, _} = ObanHelpers.perform(job)
1408
1409 {:ok, cached_user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1410
1411 assert cached_user != user
1412
1413 {:ok, cached_user} = Cachex.get(:user_cache, "nickname:#{user.ap_id}")
1414
1415 assert cached_user != user
1416 end
1417 end
1418
1419 describe "account_status/1" do
1420 setup do: clear_config([:instance, :account_activation_required])
1421
1422 test "return confirmation_pending for unconfirm user" do
1423 Pleroma.Config.put([:instance, :account_activation_required], true)
1424 user = insert(:user, confirmation_pending: true)
1425 assert User.account_status(user) == :confirmation_pending
1426 end
1427
1428 test "return active for confirmed user" do
1429 Pleroma.Config.put([:instance, :account_activation_required], true)
1430 user = insert(:user, confirmation_pending: false)
1431 assert User.account_status(user) == :active
1432 end
1433
1434 test "return active for remote user" do
1435 user = insert(:user, local: false)
1436 assert User.account_status(user) == :active
1437 end
1438
1439 test "returns :password_reset_pending for user with reset password" do
1440 user = insert(:user, password_reset_pending: true)
1441 assert User.account_status(user) == :password_reset_pending
1442 end
1443
1444 test "returns :deactivated for deactivated user" do
1445 user = insert(:user, local: true, confirmation_pending: false, deactivated: true)
1446 assert User.account_status(user) == :deactivated
1447 end
1448
1449 test "returns :approval_pending for unapproved user" do
1450 user = insert(:user, local: true, approval_pending: true)
1451 assert User.account_status(user) == :approval_pending
1452
1453 user = insert(:user, local: true, confirmation_pending: true, approval_pending: true)
1454 assert User.account_status(user) == :approval_pending
1455 end
1456 end
1457
1458 describe "superuser?/1" do
1459 test "returns false for unprivileged users" do
1460 user = insert(:user, local: true)
1461
1462 refute User.superuser?(user)
1463 end
1464
1465 test "returns false for remote users" do
1466 user = insert(:user, local: false)
1467 remote_admin_user = insert(:user, local: false, is_admin: true)
1468
1469 refute User.superuser?(user)
1470 refute User.superuser?(remote_admin_user)
1471 end
1472
1473 test "returns true for local moderators" do
1474 user = insert(:user, local: true, is_moderator: true)
1475
1476 assert User.superuser?(user)
1477 end
1478
1479 test "returns true for local admins" do
1480 user = insert(:user, local: true, is_admin: true)
1481
1482 assert User.superuser?(user)
1483 end
1484 end
1485
1486 describe "invisible?/1" do
1487 test "returns true for an invisible user" do
1488 user = insert(:user, local: true, invisible: true)
1489
1490 assert User.invisible?(user)
1491 end
1492
1493 test "returns false for a non-invisible user" do
1494 user = insert(:user, local: true)
1495
1496 refute User.invisible?(user)
1497 end
1498 end
1499
1500 describe "visible_for/2" do
1501 test "returns true when the account is itself" do
1502 user = insert(:user, local: true)
1503
1504 assert User.visible_for(user, user) == :visible
1505 end
1506
1507 test "returns false when the account is unauthenticated and auth is required" do
1508 Pleroma.Config.put([:instance, :account_activation_required], true)
1509
1510 user = insert(:user, local: true, confirmation_pending: true)
1511 other_user = insert(:user, local: true)
1512
1513 refute User.visible_for(user, other_user) == :visible
1514 end
1515
1516 test "returns true when the account is unauthenticated and auth is not required" do
1517 user = insert(:user, local: true, confirmation_pending: true)
1518 other_user = insert(:user, local: true)
1519
1520 assert User.visible_for(user, other_user) == :visible
1521 end
1522
1523 test "returns true when the account is unauthenticated and being viewed by a privileged account (auth required)" do
1524 Pleroma.Config.put([:instance, :account_activation_required], true)
1525
1526 user = insert(:user, local: true, confirmation_pending: true)
1527 other_user = insert(:user, local: true, is_admin: true)
1528
1529 assert User.visible_for(user, other_user) == :visible
1530 end
1531 end
1532
1533 describe "parse_bio/2" do
1534 test "preserves hosts in user links text" do
1535 remote_user = insert(:user, local: false, nickname: "nick@domain.com")
1536 user = insert(:user)
1537 bio = "A.k.a. @nick@domain.com"
1538
1539 expected_text =
1540 ~s(A.k.a. <span class="h-card"><a class="u-url mention" data-user="#{remote_user.id}" href="#{
1541 remote_user.ap_id
1542 }" rel="ugc">@<span>nick@domain.com</span></a></span>)
1543
1544 assert expected_text == User.parse_bio(bio, user)
1545 end
1546
1547 test "Adds rel=me on linkbacked urls" do
1548 user = insert(:user, ap_id: "https://social.example.org/users/lain")
1549
1550 bio = "http://example.com/rel_me/null"
1551 expected_text = "<a href=\"#{bio}\">#{bio}</a>"
1552 assert expected_text == User.parse_bio(bio, user)
1553
1554 bio = "http://example.com/rel_me/link"
1555 expected_text = "<a href=\"#{bio}\" rel=\"me\">#{bio}</a>"
1556 assert expected_text == User.parse_bio(bio, user)
1557
1558 bio = "http://example.com/rel_me/anchor"
1559 expected_text = "<a href=\"#{bio}\" rel=\"me\">#{bio}</a>"
1560 assert expected_text == User.parse_bio(bio, user)
1561 end
1562 end
1563
1564 test "follower count is updated when a follower is blocked" do
1565 user = insert(:user)
1566 follower = insert(:user)
1567 follower2 = insert(:user)
1568 follower3 = insert(:user)
1569
1570 {:ok, follower} = User.follow(follower, user)
1571 {:ok, _follower2} = User.follow(follower2, user)
1572 {:ok, _follower3} = User.follow(follower3, user)
1573
1574 {:ok, _user_relationship} = User.block(user, follower)
1575 user = refresh_record(user)
1576
1577 assert user.follower_count == 2
1578 end
1579
1580 describe "list_inactive_users_query/1" do
1581 defp days_ago(days) do
1582 NaiveDateTime.add(
1583 NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second),
1584 -days * 60 * 60 * 24,
1585 :second
1586 )
1587 end
1588
1589 test "Users are inactive by default" do
1590 total = 10
1591
1592 users =
1593 Enum.map(1..total, fn _ ->
1594 insert(:user, last_digest_emailed_at: days_ago(20), deactivated: false)
1595 end)
1596
1597 inactive_users_ids =
1598 Pleroma.User.list_inactive_users_query()
1599 |> Pleroma.Repo.all()
1600 |> Enum.map(& &1.id)
1601
1602 Enum.each(users, fn user ->
1603 assert user.id in inactive_users_ids
1604 end)
1605 end
1606
1607 test "Only includes users who has no recent activity" do
1608 total = 10
1609
1610 users =
1611 Enum.map(1..total, fn _ ->
1612 insert(:user, last_digest_emailed_at: days_ago(20), deactivated: false)
1613 end)
1614
1615 {inactive, active} = Enum.split(users, trunc(total / 2))
1616
1617 Enum.map(active, fn user ->
1618 to = Enum.random(users -- [user])
1619
1620 {:ok, _} =
1621 CommonAPI.post(user, %{
1622 status: "hey @#{to.nickname}"
1623 })
1624 end)
1625
1626 inactive_users_ids =
1627 Pleroma.User.list_inactive_users_query()
1628 |> Pleroma.Repo.all()
1629 |> Enum.map(& &1.id)
1630
1631 Enum.each(active, fn user ->
1632 refute user.id in inactive_users_ids
1633 end)
1634
1635 Enum.each(inactive, fn user ->
1636 assert user.id in inactive_users_ids
1637 end)
1638 end
1639
1640 test "Only includes users with no read notifications" do
1641 total = 10
1642
1643 users =
1644 Enum.map(1..total, fn _ ->
1645 insert(:user, last_digest_emailed_at: days_ago(20), deactivated: false)
1646 end)
1647
1648 [sender | recipients] = users
1649 {inactive, active} = Enum.split(recipients, trunc(total / 2))
1650
1651 Enum.each(recipients, fn to ->
1652 {:ok, _} =
1653 CommonAPI.post(sender, %{
1654 status: "hey @#{to.nickname}"
1655 })
1656
1657 {:ok, _} =
1658 CommonAPI.post(sender, %{
1659 status: "hey again @#{to.nickname}"
1660 })
1661 end)
1662
1663 Enum.each(active, fn user ->
1664 [n1, _n2] = Pleroma.Notification.for_user(user)
1665 {:ok, _} = Pleroma.Notification.read_one(user, n1.id)
1666 end)
1667
1668 inactive_users_ids =
1669 Pleroma.User.list_inactive_users_query()
1670 |> Pleroma.Repo.all()
1671 |> Enum.map(& &1.id)
1672
1673 Enum.each(active, fn user ->
1674 refute user.id in inactive_users_ids
1675 end)
1676
1677 Enum.each(inactive, fn user ->
1678 assert user.id in inactive_users_ids
1679 end)
1680 end
1681 end
1682
1683 describe "toggle_confirmation/1" do
1684 test "if user is confirmed" do
1685 user = insert(:user, confirmation_pending: false)
1686 {:ok, user} = User.toggle_confirmation(user)
1687
1688 assert user.confirmation_pending
1689 assert user.confirmation_token
1690 end
1691
1692 test "if user is unconfirmed" do
1693 user = insert(:user, confirmation_pending: true, confirmation_token: "some token")
1694 {:ok, user} = User.toggle_confirmation(user)
1695
1696 refute user.confirmation_pending
1697 refute user.confirmation_token
1698 end
1699 end
1700
1701 describe "ensure_keys_present" do
1702 test "it creates keys for a user and stores them in info" do
1703 user = insert(:user)
1704 refute is_binary(user.keys)
1705 {:ok, user} = User.ensure_keys_present(user)
1706 assert is_binary(user.keys)
1707 end
1708
1709 test "it doesn't create keys if there already are some" do
1710 user = insert(:user, keys: "xxx")
1711 {:ok, user} = User.ensure_keys_present(user)
1712 assert user.keys == "xxx"
1713 end
1714 end
1715
1716 describe "get_ap_ids_by_nicknames" do
1717 test "it returns a list of AP ids for a given set of nicknames" do
1718 user = insert(:user)
1719 user_two = insert(:user)
1720
1721 ap_ids = User.get_ap_ids_by_nicknames([user.nickname, user_two.nickname, "nonexistent"])
1722 assert length(ap_ids) == 2
1723 assert user.ap_id in ap_ids
1724 assert user_two.ap_id in ap_ids
1725 end
1726 end
1727
1728 describe "sync followers count" do
1729 setup do
1730 user1 = insert(:user, local: false, ap_id: "http://localhost:4001/users/masto_closed")
1731 user2 = insert(:user, local: false, ap_id: "http://localhost:4001/users/fuser2")
1732 insert(:user, local: true)
1733 insert(:user, local: false, deactivated: true)
1734 {:ok, user1: user1, user2: user2}
1735 end
1736
1737 test "external_users/1 external active users with limit", %{user1: user1, user2: user2} do
1738 [fdb_user1] = User.external_users(limit: 1)
1739
1740 assert fdb_user1.ap_id
1741 assert fdb_user1.ap_id == user1.ap_id
1742 assert fdb_user1.id == user1.id
1743
1744 [fdb_user2] = User.external_users(max_id: fdb_user1.id, limit: 1)
1745
1746 assert fdb_user2.ap_id
1747 assert fdb_user2.ap_id == user2.ap_id
1748 assert fdb_user2.id == user2.id
1749
1750 assert User.external_users(max_id: fdb_user2.id, limit: 1) == []
1751 end
1752 end
1753
1754 describe "is_internal_user?/1" do
1755 test "non-internal user returns false" do
1756 user = insert(:user)
1757 refute User.is_internal_user?(user)
1758 end
1759
1760 test "user with no nickname returns true" do
1761 user = insert(:user, %{nickname: nil})
1762 assert User.is_internal_user?(user)
1763 end
1764
1765 test "user with internal-prefixed nickname returns true" do
1766 user = insert(:user, %{nickname: "internal.test"})
1767 assert User.is_internal_user?(user)
1768 end
1769 end
1770
1771 describe "update_and_set_cache/1" do
1772 test "returns error when user is stale instead Ecto.StaleEntryError" do
1773 user = insert(:user)
1774
1775 changeset = Ecto.Changeset.change(user, bio: "test")
1776
1777 Repo.delete(user)
1778
1779 assert {:error, %Ecto.Changeset{errors: [id: {"is stale", [stale: true]}], valid?: false}} =
1780 User.update_and_set_cache(changeset)
1781 end
1782
1783 test "performs update cache if user updated" do
1784 user = insert(:user)
1785 assert {:ok, nil} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1786
1787 changeset = Ecto.Changeset.change(user, bio: "test-bio")
1788
1789 assert {:ok, %User{bio: "test-bio"} = user} = User.update_and_set_cache(changeset)
1790 assert {:ok, user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1791 assert %User{bio: "test-bio"} = User.get_cached_by_ap_id(user.ap_id)
1792 end
1793 end
1794
1795 describe "following/followers synchronization" do
1796 setup do: clear_config([:instance, :external_user_synchronization])
1797
1798 test "updates the counters normally on following/getting a follow when disabled" do
1799 Pleroma.Config.put([:instance, :external_user_synchronization], false)
1800 user = insert(:user)
1801
1802 other_user =
1803 insert(:user,
1804 local: false,
1805 follower_address: "http://localhost:4001/users/masto_closed/followers",
1806 following_address: "http://localhost:4001/users/masto_closed/following",
1807 ap_enabled: true
1808 )
1809
1810 assert other_user.following_count == 0
1811 assert other_user.follower_count == 0
1812
1813 {:ok, user} = Pleroma.User.follow(user, other_user)
1814 other_user = Pleroma.User.get_by_id(other_user.id)
1815
1816 assert user.following_count == 1
1817 assert other_user.follower_count == 1
1818 end
1819
1820 test "syncronizes the counters with the remote instance for the followed when enabled" do
1821 Pleroma.Config.put([:instance, :external_user_synchronization], false)
1822
1823 user = insert(:user)
1824
1825 other_user =
1826 insert(:user,
1827 local: false,
1828 follower_address: "http://localhost:4001/users/masto_closed/followers",
1829 following_address: "http://localhost:4001/users/masto_closed/following",
1830 ap_enabled: true
1831 )
1832
1833 assert other_user.following_count == 0
1834 assert other_user.follower_count == 0
1835
1836 Pleroma.Config.put([:instance, :external_user_synchronization], true)
1837 {:ok, _user} = User.follow(user, other_user)
1838 other_user = User.get_by_id(other_user.id)
1839
1840 assert other_user.follower_count == 437
1841 end
1842
1843 test "syncronizes the counters with the remote instance for the follower when enabled" do
1844 Pleroma.Config.put([:instance, :external_user_synchronization], false)
1845
1846 user = insert(:user)
1847
1848 other_user =
1849 insert(:user,
1850 local: false,
1851 follower_address: "http://localhost:4001/users/masto_closed/followers",
1852 following_address: "http://localhost:4001/users/masto_closed/following",
1853 ap_enabled: true
1854 )
1855
1856 assert other_user.following_count == 0
1857 assert other_user.follower_count == 0
1858
1859 Pleroma.Config.put([:instance, :external_user_synchronization], true)
1860 {:ok, other_user} = User.follow(other_user, user)
1861
1862 assert other_user.following_count == 152
1863 end
1864 end
1865
1866 describe "change_email/2" do
1867 setup do
1868 [user: insert(:user)]
1869 end
1870
1871 test "blank email returns error", %{user: user} do
1872 assert {:error, %{errors: [email: {"can't be blank", _}]}} = User.change_email(user, "")
1873 assert {:error, %{errors: [email: {"can't be blank", _}]}} = User.change_email(user, nil)
1874 end
1875
1876 test "non unique email returns error", %{user: user} do
1877 %{email: email} = insert(:user)
1878
1879 assert {:error, %{errors: [email: {"has already been taken", _}]}} =
1880 User.change_email(user, email)
1881 end
1882
1883 test "invalid email returns error", %{user: user} do
1884 assert {:error, %{errors: [email: {"has invalid format", _}]}} =
1885 User.change_email(user, "cofe")
1886 end
1887
1888 test "changes email", %{user: user} do
1889 assert {:ok, %User{email: "cofe@cofe.party"}} = User.change_email(user, "cofe@cofe.party")
1890 end
1891 end
1892
1893 describe "get_cached_by_nickname_or_id" do
1894 setup do
1895 local_user = insert(:user)
1896 remote_user = insert(:user, nickname: "nickname@example.com", local: false)
1897
1898 [local_user: local_user, remote_user: remote_user]
1899 end
1900
1901 setup do: clear_config([:instance, :limit_to_local_content])
1902
1903 test "allows getting remote users by id no matter what :limit_to_local_content is set to", %{
1904 remote_user: remote_user
1905 } do
1906 Pleroma.Config.put([:instance, :limit_to_local_content], false)
1907 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
1908
1909 Pleroma.Config.put([:instance, :limit_to_local_content], true)
1910 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
1911
1912 Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
1913 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
1914 end
1915
1916 test "disallows getting remote users by nickname without authentication when :limit_to_local_content is set to :unauthenticated",
1917 %{remote_user: remote_user} do
1918 Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
1919 assert nil == User.get_cached_by_nickname_or_id(remote_user.nickname)
1920 end
1921
1922 test "allows getting remote users by nickname with authentication when :limit_to_local_content is set to :unauthenticated",
1923 %{remote_user: remote_user, local_user: local_user} do
1924 Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
1925 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.nickname, for: local_user)
1926 end
1927
1928 test "disallows getting remote users by nickname when :limit_to_local_content is set to true",
1929 %{remote_user: remote_user} do
1930 Pleroma.Config.put([:instance, :limit_to_local_content], true)
1931 assert nil == User.get_cached_by_nickname_or_id(remote_user.nickname)
1932 end
1933
1934 test "allows getting local users by nickname no matter what :limit_to_local_content is set to",
1935 %{local_user: local_user} do
1936 Pleroma.Config.put([:instance, :limit_to_local_content], false)
1937 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
1938
1939 Pleroma.Config.put([:instance, :limit_to_local_content], true)
1940 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
1941
1942 Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
1943 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
1944 end
1945 end
1946
1947 describe "update_email_notifications/2" do
1948 setup do
1949 user = insert(:user, email_notifications: %{"digest" => true})
1950
1951 {:ok, user: user}
1952 end
1953
1954 test "Notifications are updated", %{user: user} do
1955 true = user.email_notifications["digest"]
1956 assert {:ok, result} = User.update_email_notifications(user, %{"digest" => false})
1957 assert result.email_notifications["digest"] == false
1958 end
1959 end
1960
1961 test "avatar fallback" do
1962 user = insert(:user)
1963 assert User.avatar_url(user) =~ "/images/avi.png"
1964
1965 clear_config([:assets, :default_user_avatar], "avatar.png")
1966
1967 user = User.get_cached_by_nickname_or_id(user.nickname)
1968 assert User.avatar_url(user) =~ "avatar.png"
1969
1970 assert User.avatar_url(user, no_default: true) == nil
1971 end
1972 end