purge chat and shout endpoints
[akkoma] / test / pleroma / user_test.exs
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2021 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.Notification
9 alias Pleroma.Object
10 alias Pleroma.Repo
11 alias Pleroma.Tests.ObanHelpers
12 alias Pleroma.User
13 alias Pleroma.Web.ActivityPub.ActivityPub
14 alias Pleroma.Web.CommonAPI
15
16 use Pleroma.DataCase
17 use Oban.Testing, repo: Pleroma.Repo
18
19 import Pleroma.Factory
20 import ExUnit.CaptureLog
21 import Swoosh.TestAssertions
22
23 setup_all do
24 Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
25 :ok
26 end
27
28 setup do: clear_config([:instance, :account_activation_required])
29
30 describe "service actors" do
31 test "returns updated invisible actor" do
32 uri = "#{Pleroma.Web.Endpoint.url()}/relay"
33 followers_uri = "#{uri}/followers"
34
35 insert(
36 :user,
37 %{
38 nickname: "relay",
39 invisible: false,
40 local: true,
41 ap_id: uri,
42 follower_address: followers_uri
43 }
44 )
45
46 actor = User.get_or_create_service_actor_by_ap_id(uri, "relay")
47 assert actor.invisible
48 end
49
50 test "returns relay user" do
51 uri = "#{Pleroma.Web.Endpoint.url()}/relay"
52 followers_uri = "#{uri}/followers"
53
54 assert %User{
55 nickname: "relay",
56 invisible: true,
57 local: true,
58 ap_id: ^uri,
59 follower_address: ^followers_uri
60 } = User.get_or_create_service_actor_by_ap_id(uri, "relay")
61
62 assert capture_log(fn ->
63 refute User.get_or_create_service_actor_by_ap_id("/relay", "relay")
64 end) =~ "Cannot create service actor:"
65 end
66
67 test "returns invisible actor" do
68 uri = "#{Pleroma.Web.Endpoint.url()}/internal/fetch-test"
69 followers_uri = "#{uri}/followers"
70 user = User.get_or_create_service_actor_by_ap_id(uri, "internal.fetch-test")
71
72 assert %User{
73 nickname: "internal.fetch-test",
74 invisible: true,
75 local: true,
76 ap_id: ^uri,
77 follower_address: ^followers_uri
78 } = user
79
80 user2 = User.get_or_create_service_actor_by_ap_id(uri, "internal.fetch-test")
81 assert user.id == user2.id
82 end
83 end
84
85 describe "AP ID user relationships" do
86 setup do
87 {:ok, user: insert(:user)}
88 end
89
90 test "outgoing_relationships_ap_ids/1", %{user: user} do
91 rel_types = [:block, :mute, :notification_mute, :reblog_mute, :inverse_subscription]
92
93 ap_ids_by_rel =
94 Enum.into(
95 rel_types,
96 %{},
97 fn rel_type ->
98 rel_records =
99 insert_list(2, :user_relationship, %{source: user, relationship_type: rel_type})
100
101 ap_ids = Enum.map(rel_records, fn rr -> Repo.preload(rr, :target).target.ap_id end)
102 {rel_type, Enum.sort(ap_ids)}
103 end
104 )
105
106 assert ap_ids_by_rel[:block] == Enum.sort(User.blocked_users_ap_ids(user))
107 assert ap_ids_by_rel[:block] == Enum.sort(Enum.map(User.blocked_users(user), & &1.ap_id))
108
109 assert ap_ids_by_rel[:mute] == Enum.sort(User.muted_users_ap_ids(user))
110 assert ap_ids_by_rel[:mute] == Enum.sort(Enum.map(User.muted_users(user), & &1.ap_id))
111
112 assert ap_ids_by_rel[:notification_mute] ==
113 Enum.sort(User.notification_muted_users_ap_ids(user))
114
115 assert ap_ids_by_rel[:notification_mute] ==
116 Enum.sort(Enum.map(User.notification_muted_users(user), & &1.ap_id))
117
118 assert ap_ids_by_rel[:reblog_mute] == Enum.sort(User.reblog_muted_users_ap_ids(user))
119
120 assert ap_ids_by_rel[:reblog_mute] ==
121 Enum.sort(Enum.map(User.reblog_muted_users(user), & &1.ap_id))
122
123 assert ap_ids_by_rel[:inverse_subscription] == Enum.sort(User.subscriber_users_ap_ids(user))
124
125 assert ap_ids_by_rel[:inverse_subscription] ==
126 Enum.sort(Enum.map(User.subscriber_users(user), & &1.ap_id))
127
128 outgoing_relationships_ap_ids = User.outgoing_relationships_ap_ids(user, rel_types)
129
130 assert ap_ids_by_rel ==
131 Enum.into(outgoing_relationships_ap_ids, %{}, fn {k, v} -> {k, Enum.sort(v)} end)
132 end
133 end
134
135 describe "when tags are nil" do
136 test "tagging a user" do
137 user = insert(:user, %{tags: nil})
138 user = User.tag(user, ["cool", "dude"])
139
140 assert "cool" in user.tags
141 assert "dude" in user.tags
142 end
143
144 test "untagging a user" do
145 user = insert(:user, %{tags: nil})
146 user = User.untag(user, ["cool", "dude"])
147
148 assert user.tags == []
149 end
150 end
151
152 test "ap_id returns the activity pub id for the user" do
153 user = UserBuilder.build()
154
155 expected_ap_id = "#{Pleroma.Web.Endpoint.url()}/users/#{user.nickname}"
156
157 assert expected_ap_id == User.ap_id(user)
158 end
159
160 test "ap_followers returns the followers collection for the user" do
161 user = UserBuilder.build()
162
163 expected_followers_collection = "#{User.ap_id(user)}/followers"
164
165 assert expected_followers_collection == User.ap_followers(user)
166 end
167
168 test "ap_following returns the following collection for the user" do
169 user = UserBuilder.build()
170
171 expected_followers_collection = "#{User.ap_id(user)}/following"
172
173 assert expected_followers_collection == User.ap_following(user)
174 end
175
176 test "returns all pending follow requests" do
177 unlocked = insert(:user)
178 locked = insert(:user, is_locked: true)
179 follower = insert(:user)
180
181 CommonAPI.follow(follower, unlocked)
182 CommonAPI.follow(follower, locked)
183
184 assert [] = User.get_follow_requests(unlocked)
185 assert [activity] = User.get_follow_requests(locked)
186
187 assert activity
188 end
189
190 test "doesn't return already accepted or duplicate follow requests" do
191 locked = insert(:user, is_locked: true)
192 pending_follower = insert(:user)
193 accepted_follower = insert(:user)
194
195 CommonAPI.follow(pending_follower, locked)
196 CommonAPI.follow(pending_follower, locked)
197 CommonAPI.follow(accepted_follower, locked)
198
199 Pleroma.FollowingRelationship.update(accepted_follower, locked, :follow_accept)
200
201 assert [^pending_follower] = User.get_follow_requests(locked)
202 end
203
204 test "doesn't return follow requests for deactivated accounts" do
205 locked = insert(:user, is_locked: true)
206 pending_follower = insert(:user, %{is_active: false})
207
208 CommonAPI.follow(pending_follower, locked)
209
210 refute pending_follower.is_active
211 assert [] = User.get_follow_requests(locked)
212 end
213
214 test "clears follow requests when requester is blocked" do
215 followed = insert(:user, is_locked: true)
216 follower = insert(:user)
217
218 CommonAPI.follow(follower, followed)
219 assert [_activity] = User.get_follow_requests(followed)
220
221 {:ok, _user_relationship} = User.block(followed, follower)
222 assert [] = User.get_follow_requests(followed)
223 end
224
225 test "follow_all follows mutliple users" do
226 user = insert(:user)
227 followed_zero = insert(:user)
228 followed_one = insert(:user)
229 followed_two = insert(:user)
230 blocked = insert(:user)
231 not_followed = insert(:user)
232 reverse_blocked = insert(:user)
233
234 {:ok, _user_relationship} = User.block(user, blocked)
235 {:ok, _user_relationship} = User.block(reverse_blocked, user)
236
237 {:ok, user, followed_zero} = User.follow(user, followed_zero)
238
239 {:ok, user} = User.follow_all(user, [followed_one, followed_two, blocked, reverse_blocked])
240
241 assert User.following?(user, followed_one)
242 assert User.following?(user, followed_two)
243 assert User.following?(user, followed_zero)
244 refute User.following?(user, not_followed)
245 refute User.following?(user, blocked)
246 refute User.following?(user, reverse_blocked)
247 end
248
249 test "follow_all follows mutliple users without duplicating" do
250 user = insert(:user)
251 followed_zero = insert(:user)
252 followed_one = insert(:user)
253 followed_two = insert(:user)
254
255 {:ok, user} = User.follow_all(user, [followed_zero, followed_one])
256 assert length(User.following(user)) == 3
257
258 {:ok, user} = User.follow_all(user, [followed_one, followed_two])
259 assert length(User.following(user)) == 4
260 end
261
262 test "follow takes a user and another user" do
263 user = insert(:user)
264 followed = insert(:user)
265
266 {:ok, user, followed} = User.follow(user, followed)
267
268 user = User.get_cached_by_id(user.id)
269 followed = User.get_cached_by_ap_id(followed.ap_id)
270
271 assert followed.follower_count == 1
272 assert user.following_count == 1
273
274 assert User.ap_followers(followed) in User.following(user)
275 end
276
277 test "can't follow a deactivated users" do
278 user = insert(:user)
279 followed = insert(:user, %{is_active: false})
280
281 {:error, _} = User.follow(user, followed)
282 end
283
284 test "can't follow a user who blocked us" do
285 blocker = insert(:user)
286 blockee = insert(:user)
287
288 {:ok, _user_relationship} = User.block(blocker, blockee)
289
290 {:error, _} = User.follow(blockee, blocker)
291 end
292
293 test "can't subscribe to a user who blocked us" do
294 blocker = insert(:user)
295 blocked = insert(:user)
296
297 {:ok, _user_relationship} = User.block(blocker, blocked)
298
299 {:error, _} = User.subscribe(blocked, blocker)
300 end
301
302 test "local users do not automatically follow local locked accounts" do
303 follower = insert(:user, is_locked: true)
304 followed = insert(:user, is_locked: true)
305
306 {:ok, follower, followed} = User.maybe_direct_follow(follower, followed)
307
308 refute User.following?(follower, followed)
309 end
310
311 describe "unfollow/2" do
312 setup do: clear_config([:instance, :external_user_synchronization])
313
314 test "unfollow with syncronizes external user" do
315 clear_config([:instance, :external_user_synchronization], true)
316
317 followed =
318 insert(:user,
319 nickname: "fuser1",
320 follower_address: "http://localhost:4001/users/fuser1/followers",
321 following_address: "http://localhost:4001/users/fuser1/following",
322 ap_id: "http://localhost:4001/users/fuser1"
323 )
324
325 user =
326 insert(:user, %{
327 local: false,
328 nickname: "fuser2",
329 ap_id: "http://localhost:4001/users/fuser2",
330 follower_address: "http://localhost:4001/users/fuser2/followers",
331 following_address: "http://localhost:4001/users/fuser2/following"
332 })
333
334 {:ok, user, followed} = User.follow(user, followed, :follow_accept)
335
336 {:ok, user, _activity} = User.unfollow(user, followed)
337
338 user = User.get_cached_by_id(user.id)
339
340 assert User.following(user) == []
341 end
342
343 test "unfollow takes a user and another user" do
344 followed = insert(:user)
345 user = insert(:user)
346
347 {:ok, user, followed} = User.follow(user, followed, :follow_accept)
348
349 assert User.following(user) == [user.follower_address, followed.follower_address]
350
351 {:ok, user, _activity} = User.unfollow(user, followed)
352
353 assert User.following(user) == [user.follower_address]
354 end
355
356 test "unfollow doesn't unfollow yourself" do
357 user = insert(:user)
358
359 {:error, _} = User.unfollow(user, user)
360
361 assert User.following(user) == [user.follower_address]
362 end
363 end
364
365 test "test if a user is following another user" do
366 followed = insert(:user)
367 user = insert(:user)
368 User.follow(user, followed, :follow_accept)
369
370 assert User.following?(user, followed)
371 refute User.following?(followed, user)
372 end
373
374 test "fetches correct profile for nickname beginning with number" do
375 # Use old-style integer ID to try to reproduce the problem
376 user = insert(:user, %{id: 1080})
377 user_with_numbers = insert(:user, %{nickname: "#{user.id}garbage"})
378 assert user_with_numbers == User.get_cached_by_nickname_or_id(user_with_numbers.nickname)
379 end
380
381 describe "user registration" do
382 @full_user_data %{
383 bio: "A guy",
384 name: "my name",
385 nickname: "nick",
386 password: "test",
387 password_confirmation: "test",
388 email: "email@example.com"
389 }
390
391 setup do: clear_config([:instance, :autofollowed_nicknames])
392 setup do: clear_config([:instance, :autofollowing_nicknames])
393 setup do: clear_config([:welcome])
394 setup do: clear_config([:instance, :account_activation_required])
395
396 test "it autofollows accounts that are set for it" do
397 user = insert(:user)
398 remote_user = insert(:user, %{local: false})
399
400 clear_config([:instance, :autofollowed_nicknames], [
401 user.nickname,
402 remote_user.nickname
403 ])
404
405 cng = User.register_changeset(%User{}, @full_user_data)
406
407 {:ok, registered_user} = User.register(cng)
408
409 assert User.following?(registered_user, user)
410 refute User.following?(registered_user, remote_user)
411 end
412
413 test "it adds automatic followers for new registered accounts" do
414 user1 = insert(:user)
415 user2 = insert(:user)
416
417 clear_config([:instance, :autofollowing_nicknames], [
418 user1.nickname,
419 user2.nickname
420 ])
421
422 cng = User.register_changeset(%User{}, @full_user_data)
423
424 {:ok, registered_user} = User.register(cng)
425
426 assert User.following?(user1, registered_user)
427 assert User.following?(user2, registered_user)
428 end
429
430 test "it sends a welcome message if it is set" do
431 welcome_user = insert(:user)
432 clear_config([:welcome, :direct_message, :enabled], true)
433 clear_config([:welcome, :direct_message, :sender_nickname], welcome_user.nickname)
434 clear_config([:welcome, :direct_message, :message], "Hello, this is a direct message")
435
436 cng = User.register_changeset(%User{}, @full_user_data)
437 {:ok, registered_user} = User.register(cng)
438 ObanHelpers.perform_all()
439
440 activity = Repo.one(Pleroma.Activity)
441 assert registered_user.ap_id in activity.recipients
442 assert Object.normalize(activity, fetch: false).data["content"] =~ "direct message"
443 assert activity.actor == welcome_user.ap_id
444 end
445
446 setup do:
447 clear_config(:mrf_simple,
448 media_removal: [],
449 media_nsfw: [],
450 federated_timeline_removal: [],
451 report_removal: [],
452 reject: [],
453 followers_only: [],
454 accept: [],
455 avatar_removal: [],
456 banner_removal: [],
457 reject_deletes: []
458 )
459
460 setup do:
461 clear_config(:mrf,
462 policies: [
463 Pleroma.Web.ActivityPub.MRF.SimplePolicy
464 ]
465 )
466
467 test "it sends a welcome email message if it is set" do
468 welcome_user = insert(:user)
469 clear_config([:welcome, :email, :enabled], true)
470 clear_config([:welcome, :email, :sender], welcome_user.email)
471
472 clear_config(
473 [:welcome, :email, :subject],
474 "Hello, welcome to cool site: <%= instance_name %>"
475 )
476
477 instance_name = Pleroma.Config.get([:instance, :name])
478
479 cng = User.register_changeset(%User{}, @full_user_data)
480 {:ok, registered_user} = User.register(cng)
481 ObanHelpers.perform_all()
482
483 assert_email_sent(
484 from: {instance_name, welcome_user.email},
485 to: {registered_user.name, registered_user.email},
486 subject: "Hello, welcome to cool site: #{instance_name}",
487 html_body: "Welcome to #{instance_name}"
488 )
489 end
490
491 test "it sends a confirm email" do
492 clear_config([:instance, :account_activation_required], true)
493
494 cng = User.register_changeset(%User{}, @full_user_data)
495 {:ok, registered_user} = User.register(cng)
496 ObanHelpers.perform_all()
497
498 Pleroma.Emails.UserEmail.account_confirmation_email(registered_user)
499 # temporary hackney fix until hackney max_connections bug is fixed
500 # https://git.pleroma.social/pleroma/pleroma/-/issues/2101
501 |> Swoosh.Email.put_private(:hackney_options, ssl_options: [versions: [:"tlsv1.2"]])
502 |> assert_email_sent()
503 end
504
505 test "sends a pending approval email" do
506 clear_config([:instance, :account_approval_required], true)
507
508 {:ok, user} =
509 User.register_changeset(%User{}, @full_user_data)
510 |> User.register()
511
512 ObanHelpers.perform_all()
513
514 assert_email_sent(
515 from: Pleroma.Config.Helpers.sender(),
516 to: {user.name, user.email},
517 subject: "Your account is awaiting approval"
518 )
519 end
520
521 test "it sends a registration confirmed email if no others will be sent" do
522 clear_config([:welcome, :email, :enabled], false)
523 clear_config([:instance, :account_activation_required], false)
524 clear_config([:instance, :account_approval_required], false)
525
526 {:ok, user} =
527 User.register_changeset(%User{}, @full_user_data)
528 |> User.register()
529
530 ObanHelpers.perform_all()
531
532 instance_name = Pleroma.Config.get([:instance, :name])
533 sender = Pleroma.Config.get([:instance, :notify_email])
534
535 assert_email_sent(
536 from: {instance_name, sender},
537 to: {user.name, user.email},
538 subject: "Account registered on #{instance_name}"
539 )
540 end
541
542 test "it fails gracefully with invalid email config" do
543 cng = User.register_changeset(%User{}, @full_user_data)
544
545 # Disable the mailer but enable all the things that want to send emails
546 clear_config([Pleroma.Emails.Mailer, :enabled], false)
547 clear_config([:instance, :account_activation_required], true)
548 clear_config([:instance, :account_approval_required], true)
549 clear_config([:welcome, :email, :enabled], true)
550 clear_config([:welcome, :email, :sender], "lain@lain.com")
551
552 # The user is still created
553 assert {:ok, %User{nickname: "nick"}} = User.register(cng)
554
555 # No emails are sent
556 ObanHelpers.perform_all()
557 refute_email_sent()
558 end
559
560 test "it requires an email, name, nickname and password, bio is optional when account_activation_required is enabled" do
561 clear_config([:instance, :account_activation_required], true)
562
563 @full_user_data
564 |> Map.keys()
565 |> Enum.each(fn key ->
566 params = Map.delete(@full_user_data, key)
567 changeset = User.register_changeset(%User{}, params)
568
569 assert if key == :bio, do: changeset.valid?, else: not changeset.valid?
570 end)
571 end
572
573 test "it requires an name, nickname and password, bio and email are optional when account_activation_required is disabled" do
574 clear_config([:instance, :account_activation_required], false)
575
576 @full_user_data
577 |> Map.keys()
578 |> Enum.each(fn key ->
579 params = Map.delete(@full_user_data, key)
580 changeset = User.register_changeset(%User{}, params)
581
582 assert if key in [:bio, :email], do: changeset.valid?, else: not changeset.valid?
583 end)
584 end
585
586 test "it restricts certain nicknames" do
587 [restricted_name | _] = Pleroma.Config.get([User, :restricted_nicknames])
588
589 assert is_bitstring(restricted_name)
590
591 params =
592 @full_user_data
593 |> Map.put(:nickname, restricted_name)
594
595 changeset = User.register_changeset(%User{}, params)
596
597 refute changeset.valid?
598 end
599
600 test "it blocks blacklisted email domains" do
601 clear_config([User, :email_blacklist], ["trolling.world"])
602
603 # Block with match
604 params = Map.put(@full_user_data, :email, "troll@trolling.world")
605 changeset = User.register_changeset(%User{}, params)
606 refute changeset.valid?
607
608 # Block with subdomain match
609 params = Map.put(@full_user_data, :email, "troll@gnomes.trolling.world")
610 changeset = User.register_changeset(%User{}, params)
611 refute changeset.valid?
612
613 # Pass with different domains that are similar
614 params = Map.put(@full_user_data, :email, "troll@gnomestrolling.world")
615 changeset = User.register_changeset(%User{}, params)
616 assert changeset.valid?
617
618 params = Map.put(@full_user_data, :email, "troll@trolling.world.us")
619 changeset = User.register_changeset(%User{}, params)
620 assert changeset.valid?
621 end
622
623 test "it sets the password_hash and ap_id" do
624 changeset = User.register_changeset(%User{}, @full_user_data)
625
626 assert changeset.valid?
627
628 assert is_binary(changeset.changes[:password_hash])
629 assert changeset.changes[:ap_id] == User.ap_id(%User{nickname: @full_user_data.nickname})
630
631 assert changeset.changes.follower_address == "#{changeset.changes.ap_id}/followers"
632 end
633
634 test "it creates a confirmed user" do
635 changeset = User.register_changeset(%User{}, @full_user_data)
636 assert changeset.valid?
637
638 {:ok, user} = Repo.insert(changeset)
639
640 assert user.is_confirmed
641 end
642 end
643
644 describe "user registration, with :account_activation_required" do
645 @full_user_data %{
646 bio: "A guy",
647 name: "my name",
648 nickname: "nick",
649 password: "test",
650 password_confirmation: "test",
651 email: "email@example.com"
652 }
653 setup do: clear_config([:instance, :account_activation_required], true)
654
655 test "it creates unconfirmed user" do
656 changeset = User.register_changeset(%User{}, @full_user_data)
657 assert changeset.valid?
658
659 {:ok, user} = Repo.insert(changeset)
660
661 refute user.is_confirmed
662 assert user.confirmation_token
663 end
664
665 test "it creates confirmed user if :confirmed option is given" do
666 changeset = User.register_changeset(%User{}, @full_user_data, confirmed: true)
667 assert changeset.valid?
668
669 {:ok, user} = Repo.insert(changeset)
670
671 assert user.is_confirmed
672 refute user.confirmation_token
673 end
674 end
675
676 describe "user registration, with :account_approval_required" do
677 @full_user_data %{
678 bio: "A guy",
679 name: "my name",
680 nickname: "nick",
681 password: "test",
682 password_confirmation: "test",
683 email: "email@example.com",
684 registration_reason: "I'm a cool guy :)"
685 }
686 setup do: clear_config([:instance, :account_approval_required], true)
687
688 test "it creates unapproved user" do
689 changeset = User.register_changeset(%User{}, @full_user_data)
690 assert changeset.valid?
691
692 {:ok, user} = Repo.insert(changeset)
693
694 refute user.is_approved
695 assert user.registration_reason == "I'm a cool guy :)"
696 end
697
698 test "it restricts length of registration reason" do
699 reason_limit = Pleroma.Config.get([:instance, :registration_reason_length])
700
701 assert is_integer(reason_limit)
702
703 params =
704 @full_user_data
705 |> Map.put(
706 :registration_reason,
707 "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."
708 )
709
710 changeset = User.register_changeset(%User{}, params)
711
712 refute changeset.valid?
713 end
714 end
715
716 describe "get_or_fetch/1" do
717 test "gets an existing user by nickname" do
718 user = insert(:user)
719 {:ok, fetched_user} = User.get_or_fetch(user.nickname)
720
721 assert user == fetched_user
722 end
723
724 test "gets an existing user by ap_id" do
725 ap_id = "http://mastodon.example.org/users/admin"
726
727 user =
728 insert(
729 :user,
730 local: false,
731 nickname: "admin@mastodon.example.org",
732 ap_id: ap_id
733 )
734
735 {:ok, fetched_user} = User.get_or_fetch(ap_id)
736 freshed_user = refresh_record(user)
737 assert freshed_user == fetched_user
738 end
739 end
740
741 describe "fetching a user from nickname or trying to build one" do
742 test "gets an existing user" do
743 user = insert(:user)
744 {:ok, fetched_user} = User.get_or_fetch_by_nickname(user.nickname)
745
746 assert user == fetched_user
747 end
748
749 test "gets an existing user, case insensitive" do
750 user = insert(:user, nickname: "nick")
751 {:ok, fetched_user} = User.get_or_fetch_by_nickname("NICK")
752
753 assert user == fetched_user
754 end
755
756 test "gets an existing user by fully qualified nickname" do
757 user = insert(:user)
758
759 {:ok, fetched_user} =
760 User.get_or_fetch_by_nickname(user.nickname <> "@" <> Pleroma.Web.Endpoint.host())
761
762 assert user == fetched_user
763 end
764
765 test "gets an existing user by fully qualified nickname, case insensitive" do
766 user = insert(:user, nickname: "nick")
767 casing_altered_fqn = String.upcase(user.nickname <> "@" <> Pleroma.Web.Endpoint.host())
768
769 {:ok, fetched_user} = User.get_or_fetch_by_nickname(casing_altered_fqn)
770
771 assert user == fetched_user
772 end
773
774 @tag capture_log: true
775 test "returns nil if no user could be fetched" do
776 {:error, fetched_user} = User.get_or_fetch_by_nickname("nonexistant@social.heldscal.la")
777 assert fetched_user == "not found nonexistant@social.heldscal.la"
778 end
779
780 test "returns nil for nonexistant local user" do
781 {:error, fetched_user} = User.get_or_fetch_by_nickname("nonexistant")
782 assert fetched_user == "not found nonexistant"
783 end
784
785 test "updates an existing user, if stale" do
786 a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
787
788 orig_user =
789 insert(
790 :user,
791 local: false,
792 nickname: "admin@mastodon.example.org",
793 ap_id: "http://mastodon.example.org/users/admin",
794 last_refreshed_at: a_week_ago
795 )
796
797 assert orig_user.last_refreshed_at == a_week_ago
798
799 {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/admin")
800
801 assert user.inbox
802
803 refute user.last_refreshed_at == orig_user.last_refreshed_at
804 end
805
806 test "if nicknames clash, the old user gets a prefix with the old id to the nickname" do
807 a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
808
809 orig_user =
810 insert(
811 :user,
812 local: false,
813 nickname: "admin@mastodon.example.org",
814 ap_id: "http://mastodon.example.org/users/harinezumigari",
815 last_refreshed_at: a_week_ago
816 )
817
818 assert orig_user.last_refreshed_at == a_week_ago
819
820 {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/admin")
821
822 assert user.inbox
823
824 refute user.id == orig_user.id
825
826 orig_user = User.get_by_id(orig_user.id)
827
828 assert orig_user.nickname == "#{orig_user.id}.admin@mastodon.example.org"
829 end
830
831 @tag capture_log: true
832 test "it returns the old user if stale, but unfetchable" do
833 a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
834
835 orig_user =
836 insert(
837 :user,
838 local: false,
839 nickname: "admin@mastodon.example.org",
840 ap_id: "http://mastodon.example.org/users/raymoo",
841 last_refreshed_at: a_week_ago
842 )
843
844 assert orig_user.last_refreshed_at == a_week_ago
845
846 {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/raymoo")
847
848 assert user.last_refreshed_at == orig_user.last_refreshed_at
849 end
850 end
851
852 test "returns an ap_id for a user" do
853 user = insert(:user)
854
855 assert User.ap_id(user) ==
856 Pleroma.Web.Router.Helpers.user_feed_url(
857 Pleroma.Web.Endpoint,
858 :feed_redirect,
859 user.nickname
860 )
861 end
862
863 test "returns an ap_followers link for a user" do
864 user = insert(:user)
865
866 assert User.ap_followers(user) ==
867 Pleroma.Web.Router.Helpers.user_feed_url(
868 Pleroma.Web.Endpoint,
869 :feed_redirect,
870 user.nickname
871 ) <> "/followers"
872 end
873
874 describe "remote user changeset" do
875 @valid_remote %{
876 bio: "hello",
877 name: "Someone",
878 nickname: "a@b.de",
879 ap_id: "http...",
880 avatar: %{some: "avatar"}
881 }
882 setup do: clear_config([:instance, :user_bio_length])
883 setup do: clear_config([:instance, :user_name_length])
884
885 test "it confirms validity" do
886 cs = User.remote_user_changeset(@valid_remote)
887 assert cs.valid?
888 end
889
890 test "it sets the follower_adress" do
891 cs = User.remote_user_changeset(@valid_remote)
892 # remote users get a fake local follower address
893 assert cs.changes.follower_address ==
894 User.ap_followers(%User{nickname: @valid_remote[:nickname]})
895 end
896
897 test "it enforces the fqn format for nicknames" do
898 cs = User.remote_user_changeset(%{@valid_remote | nickname: "bla"})
899 assert Ecto.Changeset.get_field(cs, :local) == false
900 assert cs.changes.avatar
901 refute cs.valid?
902 end
903
904 test "it has required fields" do
905 [:ap_id]
906 |> Enum.each(fn field ->
907 cs = User.remote_user_changeset(Map.delete(@valid_remote, field))
908 refute cs.valid?
909 end)
910 end
911
912 test "it is invalid given a local user" do
913 user = insert(:user)
914 cs = User.remote_user_changeset(user, %{name: "tom from myspace"})
915
916 refute cs.valid?
917 end
918 end
919
920 describe "followers and friends" do
921 test "gets all followers for a given user" do
922 user = insert(:user)
923 follower_one = insert(:user)
924 follower_two = insert(:user)
925 not_follower = insert(:user)
926
927 {:ok, follower_one, user} = User.follow(follower_one, user)
928 {:ok, follower_two, user} = User.follow(follower_two, user)
929
930 res = User.get_followers(user)
931
932 assert Enum.member?(res, follower_one)
933 assert Enum.member?(res, follower_two)
934 refute Enum.member?(res, not_follower)
935 end
936
937 test "gets all friends (followed users) for a given user" do
938 user = insert(:user)
939 followed_one = insert(:user)
940 followed_two = insert(:user)
941 not_followed = insert(:user)
942
943 {:ok, user, followed_one} = User.follow(user, followed_one)
944 {:ok, user, followed_two} = User.follow(user, followed_two)
945
946 res = User.get_friends(user)
947
948 followed_one = User.get_cached_by_ap_id(followed_one.ap_id)
949 followed_two = User.get_cached_by_ap_id(followed_two.ap_id)
950 assert Enum.member?(res, followed_one)
951 assert Enum.member?(res, followed_two)
952 refute Enum.member?(res, not_followed)
953 end
954 end
955
956 describe "updating note and follower count" do
957 test "it sets the note_count property" do
958 note = insert(:note)
959
960 user = User.get_cached_by_ap_id(note.data["actor"])
961
962 assert user.note_count == 0
963
964 {:ok, user} = User.update_note_count(user)
965
966 assert user.note_count == 1
967 end
968
969 test "it increases the note_count property" do
970 note = insert(:note)
971 user = User.get_cached_by_ap_id(note.data["actor"])
972
973 assert user.note_count == 0
974
975 {:ok, user} = User.increase_note_count(user)
976
977 assert user.note_count == 1
978
979 {:ok, user} = User.increase_note_count(user)
980
981 assert user.note_count == 2
982 end
983
984 test "it decreases the note_count property" do
985 note = insert(:note)
986 user = User.get_cached_by_ap_id(note.data["actor"])
987
988 assert user.note_count == 0
989
990 {:ok, user} = User.increase_note_count(user)
991
992 assert user.note_count == 1
993
994 {:ok, user} = User.decrease_note_count(user)
995
996 assert user.note_count == 0
997
998 {:ok, user} = User.decrease_note_count(user)
999
1000 assert user.note_count == 0
1001 end
1002
1003 test "it sets the follower_count property" do
1004 user = insert(:user)
1005 follower = insert(:user)
1006
1007 User.follow(follower, user)
1008
1009 assert user.follower_count == 0
1010
1011 {:ok, user} = User.update_follower_count(user)
1012
1013 assert user.follower_count == 1
1014 end
1015 end
1016
1017 describe "mutes" do
1018 test "it mutes people" do
1019 user = insert(:user)
1020 muted_user = insert(:user)
1021
1022 refute User.mutes?(user, muted_user)
1023 refute User.muted_notifications?(user, muted_user)
1024
1025 {:ok, _user_relationships} = User.mute(user, muted_user)
1026
1027 assert User.mutes?(user, muted_user)
1028 assert User.muted_notifications?(user, muted_user)
1029 end
1030
1031 test "expiring" do
1032 user = insert(:user)
1033 muted_user = insert(:user)
1034
1035 {:ok, _user_relationships} = User.mute(user, muted_user, %{expires_in: 60})
1036 assert User.mutes?(user, muted_user)
1037
1038 worker = Pleroma.Workers.MuteExpireWorker
1039 args = %{"op" => "unmute_user", "muter_id" => user.id, "mutee_id" => muted_user.id}
1040
1041 assert_enqueued(
1042 worker: worker,
1043 args: args
1044 )
1045
1046 assert :ok = perform_job(worker, args)
1047
1048 refute User.mutes?(user, muted_user)
1049 refute User.muted_notifications?(user, muted_user)
1050 end
1051
1052 test "it unmutes users" do
1053 user = insert(:user)
1054 muted_user = insert(:user)
1055
1056 {:ok, _user_relationships} = User.mute(user, muted_user)
1057 {:ok, _user_mute} = User.unmute(user, muted_user)
1058
1059 refute User.mutes?(user, muted_user)
1060 refute User.muted_notifications?(user, muted_user)
1061 end
1062
1063 test "it unmutes users by id" do
1064 user = insert(:user)
1065 muted_user = insert(:user)
1066
1067 {:ok, _user_relationships} = User.mute(user, muted_user)
1068 {:ok, _user_mute} = User.unmute(user.id, muted_user.id)
1069
1070 refute User.mutes?(user, muted_user)
1071 refute User.muted_notifications?(user, muted_user)
1072 end
1073
1074 test "it mutes user without notifications" do
1075 user = insert(:user)
1076 muted_user = insert(:user)
1077
1078 refute User.mutes?(user, muted_user)
1079 refute User.muted_notifications?(user, muted_user)
1080
1081 {:ok, _user_relationships} = User.mute(user, muted_user, %{notifications: false})
1082
1083 assert User.mutes?(user, muted_user)
1084 refute User.muted_notifications?(user, muted_user)
1085 end
1086 end
1087
1088 describe "blocks" do
1089 test "it blocks people" do
1090 user = insert(:user)
1091 blocked_user = insert(:user)
1092
1093 refute User.blocks?(user, blocked_user)
1094
1095 {:ok, _user_relationship} = User.block(user, blocked_user)
1096
1097 assert User.blocks?(user, blocked_user)
1098 end
1099
1100 test "it unblocks users" do
1101 user = insert(:user)
1102 blocked_user = insert(:user)
1103
1104 {:ok, _user_relationship} = User.block(user, blocked_user)
1105 {:ok, _user_block} = User.unblock(user, blocked_user)
1106
1107 refute User.blocks?(user, blocked_user)
1108 end
1109
1110 test "blocks tear down cyclical follow relationships" do
1111 blocker = insert(:user)
1112 blocked = insert(:user)
1113
1114 {:ok, blocker, blocked} = User.follow(blocker, blocked)
1115 {:ok, blocked, blocker} = User.follow(blocked, blocker)
1116
1117 assert User.following?(blocker, blocked)
1118 assert User.following?(blocked, blocker)
1119
1120 {:ok, _user_relationship} = User.block(blocker, blocked)
1121 blocked = User.get_cached_by_id(blocked.id)
1122
1123 assert User.blocks?(blocker, blocked)
1124
1125 refute User.following?(blocker, blocked)
1126 refute User.following?(blocked, blocker)
1127 end
1128
1129 test "blocks tear down blocker->blocked follow relationships" do
1130 blocker = insert(:user)
1131 blocked = insert(:user)
1132
1133 {:ok, blocker, blocked} = User.follow(blocker, blocked)
1134
1135 assert User.following?(blocker, blocked)
1136 refute User.following?(blocked, blocker)
1137
1138 {:ok, _user_relationship} = User.block(blocker, blocked)
1139 blocked = User.get_cached_by_id(blocked.id)
1140
1141 assert User.blocks?(blocker, blocked)
1142
1143 refute User.following?(blocker, blocked)
1144 refute User.following?(blocked, blocker)
1145 end
1146
1147 test "blocks tear down blocked->blocker follow relationships" do
1148 blocker = insert(:user)
1149 blocked = insert(:user)
1150
1151 {:ok, blocked, blocker} = User.follow(blocked, blocker)
1152
1153 refute User.following?(blocker, blocked)
1154 assert User.following?(blocked, blocker)
1155
1156 {:ok, _user_relationship} = User.block(blocker, blocked)
1157 blocked = User.get_cached_by_id(blocked.id)
1158
1159 assert User.blocks?(blocker, blocked)
1160
1161 refute User.following?(blocker, blocked)
1162 refute User.following?(blocked, blocker)
1163 end
1164
1165 test "blocks tear down blocked->blocker subscription relationships" do
1166 blocker = insert(:user)
1167 blocked = insert(:user)
1168
1169 {:ok, _subscription} = User.subscribe(blocked, blocker)
1170
1171 assert User.subscribed_to?(blocked, blocker)
1172 refute User.subscribed_to?(blocker, blocked)
1173
1174 {:ok, _user_relationship} = User.block(blocker, blocked)
1175
1176 assert User.blocks?(blocker, blocked)
1177 refute User.subscribed_to?(blocker, blocked)
1178 refute User.subscribed_to?(blocked, blocker)
1179 end
1180 end
1181
1182 describe "domain blocking" do
1183 test "blocks domains" do
1184 user = insert(:user)
1185 collateral_user = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1186
1187 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1188
1189 assert User.blocks?(user, collateral_user)
1190 end
1191
1192 test "does not block domain with same end" do
1193 user = insert(:user)
1194
1195 collateral_user =
1196 insert(:user, %{ap_id: "https://another-awful-and-rude-instance.com/user/bully"})
1197
1198 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1199
1200 refute User.blocks?(user, collateral_user)
1201 end
1202
1203 test "does not block domain with same end if wildcard added" do
1204 user = insert(:user)
1205
1206 collateral_user =
1207 insert(:user, %{ap_id: "https://another-awful-and-rude-instance.com/user/bully"})
1208
1209 {:ok, user} = User.block_domain(user, "*.awful-and-rude-instance.com")
1210
1211 refute User.blocks?(user, collateral_user)
1212 end
1213
1214 test "blocks domain with wildcard for subdomain" do
1215 user = insert(:user)
1216
1217 user_from_subdomain =
1218 insert(:user, %{ap_id: "https://subdomain.awful-and-rude-instance.com/user/bully"})
1219
1220 user_with_two_subdomains =
1221 insert(:user, %{
1222 ap_id: "https://subdomain.second_subdomain.awful-and-rude-instance.com/user/bully"
1223 })
1224
1225 user_domain = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1226
1227 {:ok, user} = User.block_domain(user, "*.awful-and-rude-instance.com")
1228
1229 assert User.blocks?(user, user_from_subdomain)
1230 assert User.blocks?(user, user_with_two_subdomains)
1231 assert User.blocks?(user, user_domain)
1232 end
1233
1234 test "unblocks domains" do
1235 user = insert(:user)
1236 collateral_user = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1237
1238 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1239 {:ok, user} = User.unblock_domain(user, "awful-and-rude-instance.com")
1240
1241 refute User.blocks?(user, collateral_user)
1242 end
1243
1244 test "follows take precedence over domain blocks" do
1245 user = insert(:user)
1246 good_eggo = insert(:user, %{ap_id: "https://meanies.social/user/cuteposter"})
1247
1248 {:ok, user} = User.block_domain(user, "meanies.social")
1249 {:ok, user, good_eggo} = User.follow(user, good_eggo)
1250
1251 refute User.blocks?(user, good_eggo)
1252 end
1253 end
1254
1255 describe "get_recipients_from_activity" do
1256 test "works for announces" do
1257 actor = insert(:user)
1258 user = insert(:user, local: true)
1259
1260 {:ok, activity} = CommonAPI.post(actor, %{status: "hello"})
1261 {:ok, announce} = CommonAPI.repeat(activity.id, user)
1262
1263 recipients = User.get_recipients_from_activity(announce)
1264
1265 assert user in recipients
1266 end
1267
1268 test "get recipients" do
1269 actor = insert(:user)
1270 user = insert(:user, local: true)
1271 user_two = insert(:user, local: false)
1272 addressed = insert(:user, local: true)
1273 addressed_remote = insert(:user, local: false)
1274
1275 {:ok, activity} =
1276 CommonAPI.post(actor, %{
1277 status: "hey @#{addressed.nickname} @#{addressed_remote.nickname}"
1278 })
1279
1280 assert Enum.map([actor, addressed], & &1.ap_id) --
1281 Enum.map(User.get_recipients_from_activity(activity), & &1.ap_id) == []
1282
1283 {:ok, user, actor} = User.follow(user, actor)
1284 {:ok, _user_two, _actor} = User.follow(user_two, actor)
1285 recipients = User.get_recipients_from_activity(activity)
1286 assert length(recipients) == 3
1287 assert user in recipients
1288 assert addressed in recipients
1289 end
1290
1291 test "has following" do
1292 actor = insert(:user)
1293 user = insert(:user)
1294 user_two = insert(:user)
1295 addressed = insert(:user, local: true)
1296
1297 {:ok, activity} =
1298 CommonAPI.post(actor, %{
1299 status: "hey @#{addressed.nickname}"
1300 })
1301
1302 assert Enum.map([actor, addressed], & &1.ap_id) --
1303 Enum.map(User.get_recipients_from_activity(activity), & &1.ap_id) == []
1304
1305 {:ok, _actor, _user} = User.follow(actor, user)
1306 {:ok, _actor, _user_two} = User.follow(actor, user_two)
1307 recipients = User.get_recipients_from_activity(activity)
1308 assert length(recipients) == 2
1309 assert addressed in recipients
1310 end
1311 end
1312
1313 describe ".set_activation" do
1314 test "can de-activate then re-activate a user" do
1315 user = insert(:user)
1316 assert user.is_active
1317 {:ok, user} = User.set_activation(user, false)
1318 refute user.is_active
1319 {:ok, user} = User.set_activation(user, true)
1320 assert user.is_active
1321 end
1322
1323 test "hide a user from followers" do
1324 user = insert(:user)
1325 user2 = insert(:user)
1326
1327 {:ok, user, user2} = User.follow(user, user2)
1328 {:ok, _user} = User.set_activation(user, false)
1329
1330 user2 = User.get_cached_by_id(user2.id)
1331
1332 assert user2.follower_count == 0
1333 assert [] = User.get_followers(user2)
1334 end
1335
1336 test "hide a user from friends" do
1337 user = insert(:user)
1338 user2 = insert(:user)
1339
1340 {:ok, user2, user} = User.follow(user2, user)
1341 assert user2.following_count == 1
1342 assert User.following_count(user2) == 1
1343
1344 {:ok, _user} = User.set_activation(user, false)
1345
1346 user2 = User.get_cached_by_id(user2.id)
1347
1348 assert refresh_record(user2).following_count == 0
1349 assert user2.following_count == 0
1350 assert User.following_count(user2) == 0
1351 assert [] = User.get_friends(user2)
1352 end
1353
1354 test "hide a user's statuses from timelines and notifications" do
1355 user = insert(:user)
1356 user2 = insert(:user)
1357
1358 {:ok, user2, user} = User.follow(user2, user)
1359
1360 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{user2.nickname}"})
1361
1362 activity = Repo.preload(activity, :bookmark)
1363
1364 [notification] = Pleroma.Notification.for_user(user2)
1365 assert notification.activity.id == activity.id
1366
1367 assert [activity] == ActivityPub.fetch_public_activities(%{}) |> Repo.preload(:bookmark)
1368
1369 assert [%{activity | thread_muted?: CommonAPI.thread_muted?(user2, activity)}] ==
1370 ActivityPub.fetch_activities([user2.ap_id | User.following(user2)], %{
1371 user: user2
1372 })
1373
1374 {:ok, _user} = User.set_activation(user, false)
1375
1376 assert [] == ActivityPub.fetch_public_activities(%{})
1377 assert [] == Pleroma.Notification.for_user(user2)
1378
1379 assert [] ==
1380 ActivityPub.fetch_activities([user2.ap_id | User.following(user2)], %{
1381 user: user2
1382 })
1383 end
1384 end
1385
1386 describe "approve" do
1387 test "approves a user" do
1388 user = insert(:user, is_approved: false)
1389 refute user.is_approved
1390 {:ok, user} = User.approve(user)
1391 assert user.is_approved
1392 end
1393
1394 test "approves a list of users" do
1395 unapproved_users = [
1396 insert(:user, is_approved: false),
1397 insert(:user, is_approved: false),
1398 insert(:user, is_approved: false)
1399 ]
1400
1401 {:ok, users} = User.approve(unapproved_users)
1402
1403 assert Enum.count(users) == 3
1404
1405 Enum.each(users, fn user ->
1406 assert user.is_approved
1407 end)
1408 end
1409
1410 test "it sends welcome email if it is set" do
1411 clear_config([:welcome, :email, :enabled], true)
1412 clear_config([:welcome, :email, :sender], "tester@test.me")
1413
1414 user = insert(:user, is_approved: false)
1415 welcome_user = insert(:user, email: "tester@test.me")
1416 instance_name = Pleroma.Config.get([:instance, :name])
1417
1418 User.approve(user)
1419
1420 ObanHelpers.perform_all()
1421
1422 assert_email_sent(
1423 from: {instance_name, welcome_user.email},
1424 to: {user.name, user.email},
1425 html_body: "Welcome to #{instance_name}"
1426 )
1427 end
1428
1429 test "approving an approved user does not trigger post-register actions" do
1430 clear_config([:welcome, :email, :enabled], true)
1431
1432 user = insert(:user, is_approved: true)
1433 User.approve(user)
1434
1435 ObanHelpers.perform_all()
1436
1437 assert_no_email_sent()
1438 end
1439 end
1440
1441 describe "confirm" do
1442 test "confirms a user" do
1443 user = insert(:user, is_confirmed: false)
1444 refute user.is_confirmed
1445 {:ok, user} = User.confirm(user)
1446 assert user.is_confirmed
1447 end
1448
1449 test "confirms a list of users" do
1450 unconfirmed_users = [
1451 insert(:user, is_confirmed: false),
1452 insert(:user, is_confirmed: false),
1453 insert(:user, is_confirmed: false)
1454 ]
1455
1456 {:ok, users} = User.confirm(unconfirmed_users)
1457
1458 assert Enum.count(users) == 3
1459
1460 Enum.each(users, fn user ->
1461 assert user.is_confirmed
1462 end)
1463 end
1464
1465 test "sends approval emails when `is_approved: false`" do
1466 admin = insert(:user, is_admin: true)
1467 user = insert(:user, is_confirmed: false, is_approved: false)
1468 User.confirm(user)
1469
1470 ObanHelpers.perform_all()
1471
1472 user_email = Pleroma.Emails.UserEmail.approval_pending_email(user)
1473 admin_email = Pleroma.Emails.AdminEmail.new_unapproved_registration(admin, user)
1474
1475 notify_email = Pleroma.Config.get([:instance, :notify_email])
1476 instance_name = Pleroma.Config.get([:instance, :name])
1477
1478 # User approval email
1479 assert_email_sent(
1480 from: {instance_name, notify_email},
1481 to: {user.name, user.email},
1482 html_body: user_email.html_body
1483 )
1484
1485 # Admin email
1486 assert_email_sent(
1487 from: {instance_name, notify_email},
1488 to: {admin.name, admin.email},
1489 html_body: admin_email.html_body
1490 )
1491 end
1492
1493 test "confirming a confirmed user does not trigger post-register actions" do
1494 user = insert(:user, is_confirmed: true, is_approved: false)
1495 User.confirm(user)
1496
1497 ObanHelpers.perform_all()
1498
1499 assert_no_email_sent()
1500 end
1501 end
1502
1503 describe "delete" do
1504 setup do
1505 {:ok, user} = insert(:user) |> User.set_cache()
1506
1507 [user: user]
1508 end
1509
1510 setup do: clear_config([:instance, :federating])
1511
1512 test ".delete_user_activities deletes all create activities", %{user: user} do
1513 {:ok, activity} = CommonAPI.post(user, %{status: "2hu"})
1514
1515 User.delete_user_activities(user)
1516
1517 # TODO: Test removal favorites, repeats, delete activities.
1518 refute Activity.get_by_id(activity.id)
1519 end
1520
1521 test "it deactivates a user, all follow relationships and all activities", %{user: user} do
1522 follower = insert(:user)
1523 {:ok, follower, user} = User.follow(follower, user)
1524
1525 locked_user = insert(:user, name: "locked", is_locked: true)
1526 {:ok, _, _} = User.follow(user, locked_user, :follow_pending)
1527
1528 object = insert(:note, user: user)
1529 activity = insert(:note_activity, user: user, note: object)
1530
1531 object_two = insert(:note, user: follower)
1532 activity_two = insert(:note_activity, user: follower, note: object_two)
1533
1534 {:ok, like} = CommonAPI.favorite(user, activity_two.id)
1535 {:ok, like_two} = CommonAPI.favorite(follower, activity.id)
1536 {:ok, repeat} = CommonAPI.repeat(activity_two.id, user)
1537
1538 {:ok, job} = User.delete(user)
1539 {:ok, _user} = ObanHelpers.perform(job)
1540
1541 follower = User.get_cached_by_id(follower.id)
1542
1543 refute User.following?(follower, user)
1544 assert %{is_active: false} = User.get_by_id(user.id)
1545
1546 assert [] == User.get_follow_requests(locked_user)
1547
1548 user_activities =
1549 user.ap_id
1550 |> Activity.Queries.by_actor()
1551 |> Repo.all()
1552 |> Enum.map(fn act -> act.data["type"] end)
1553
1554 assert Enum.all?(user_activities, fn act -> act in ~w(Delete Undo) end)
1555
1556 refute Activity.get_by_id(activity.id)
1557 refute Activity.get_by_id(like.id)
1558 refute Activity.get_by_id(like_two.id)
1559 refute Activity.get_by_id(repeat.id)
1560 end
1561 end
1562
1563 test "delete/1 when confirmation is pending deletes the user" do
1564 clear_config([:instance, :account_activation_required], true)
1565 user = insert(:user, is_confirmed: false)
1566
1567 {:ok, job} = User.delete(user)
1568 {:ok, _} = ObanHelpers.perform(job)
1569
1570 refute User.get_cached_by_id(user.id)
1571 refute User.get_by_id(user.id)
1572 end
1573
1574 test "delete/1 when approval is pending deletes the user" do
1575 user = insert(:user, is_approved: false)
1576
1577 {:ok, job} = User.delete(user)
1578 {:ok, _} = ObanHelpers.perform(job)
1579
1580 refute User.get_cached_by_id(user.id)
1581 refute User.get_by_id(user.id)
1582 end
1583
1584 test "delete/1 purges a user when they wouldn't be fully deleted" do
1585 user =
1586 insert(:user, %{
1587 bio: "eyy lmao",
1588 name: "qqqqqqq",
1589 password_hash: "pdfk2$1b3n159001",
1590 keys: "RSA begin buplic key",
1591 public_key: "--PRIVATE KEYE--",
1592 avatar: %{"a" => "b"},
1593 tags: ["qqqqq"],
1594 banner: %{"a" => "b"},
1595 background: %{"a" => "b"},
1596 note_count: 9,
1597 follower_count: 9,
1598 following_count: 9001,
1599 is_locked: true,
1600 is_confirmed: true,
1601 password_reset_pending: true,
1602 is_approved: true,
1603 registration_reason: "ahhhhh",
1604 confirmation_token: "qqqq",
1605 domain_blocks: ["lain.com"],
1606 is_active: false,
1607 ap_enabled: true,
1608 is_moderator: true,
1609 is_admin: true,
1610 mastofe_settings: %{"a" => "b"},
1611 mascot: %{"a" => "b"},
1612 emoji: %{"a" => "b"},
1613 pleroma_settings_store: %{"q" => "x"},
1614 fields: [%{"gg" => "qq"}],
1615 raw_fields: [%{"gg" => "qq"}],
1616 is_discoverable: true,
1617 also_known_as: ["https://lol.olo/users/loll"]
1618 })
1619
1620 {:ok, job} = User.delete(user)
1621 {:ok, _} = ObanHelpers.perform(job)
1622 user = User.get_by_id(user.id)
1623
1624 assert %User{
1625 bio: "",
1626 raw_bio: nil,
1627 email: nil,
1628 name: nil,
1629 password_hash: nil,
1630 keys: "RSA begin buplic key",
1631 public_key: "--PRIVATE KEYE--",
1632 avatar: %{},
1633 tags: [],
1634 last_refreshed_at: nil,
1635 last_digest_emailed_at: nil,
1636 banner: %{},
1637 background: %{},
1638 note_count: 0,
1639 follower_count: 0,
1640 following_count: 0,
1641 is_locked: false,
1642 is_confirmed: true,
1643 password_reset_pending: false,
1644 is_approved: true,
1645 registration_reason: nil,
1646 confirmation_token: nil,
1647 domain_blocks: [],
1648 is_active: false,
1649 ap_enabled: false,
1650 is_moderator: false,
1651 is_admin: false,
1652 mastofe_settings: nil,
1653 mascot: nil,
1654 emoji: %{},
1655 pleroma_settings_store: %{},
1656 fields: [],
1657 raw_fields: [],
1658 is_discoverable: false,
1659 also_known_as: []
1660 } = user
1661 end
1662
1663 test "delete/1 purges a remote user" do
1664 user =
1665 insert(:user, %{
1666 name: "qqqqqqq",
1667 avatar: %{"a" => "b"},
1668 banner: %{"a" => "b"},
1669 local: false
1670 })
1671
1672 {:ok, job} = User.delete(user)
1673 {:ok, _} = ObanHelpers.perform(job)
1674 user = User.get_by_id(user.id)
1675
1676 assert user.name == nil
1677 assert user.avatar == %{}
1678 assert user.banner == %{}
1679 end
1680
1681 describe "set_suggestion" do
1682 test "suggests a user" do
1683 user = insert(:user, is_suggested: false)
1684 refute user.is_suggested
1685 {:ok, user} = User.set_suggestion(user, true)
1686 assert user.is_suggested
1687 end
1688
1689 test "suggests a list of users" do
1690 unsuggested_users = [
1691 insert(:user, is_suggested: false),
1692 insert(:user, is_suggested: false),
1693 insert(:user, is_suggested: false)
1694 ]
1695
1696 {:ok, users} = User.set_suggestion(unsuggested_users, true)
1697
1698 assert Enum.count(users) == 3
1699
1700 Enum.each(users, fn user ->
1701 assert user.is_suggested
1702 end)
1703 end
1704
1705 test "unsuggests a user" do
1706 user = insert(:user, is_suggested: true)
1707 assert user.is_suggested
1708 {:ok, user} = User.set_suggestion(user, false)
1709 refute user.is_suggested
1710 end
1711 end
1712
1713 test "get_public_key_for_ap_id fetches a user that's not in the db" do
1714 assert {:ok, _key} = User.get_public_key_for_ap_id("http://mastodon.example.org/users/admin")
1715 end
1716
1717 describe "per-user rich-text filtering" do
1718 test "html_filter_policy returns default policies, when rich-text is enabled" do
1719 user = insert(:user)
1720
1721 assert Pleroma.Config.get([:markup, :scrub_policy]) == User.html_filter_policy(user)
1722 end
1723
1724 test "html_filter_policy returns TwitterText scrubber when rich-text is disabled" do
1725 user = insert(:user, no_rich_text: true)
1726
1727 assert Pleroma.HTML.Scrubber.TwitterText == User.html_filter_policy(user)
1728 end
1729 end
1730
1731 describe "caching" do
1732 test "invalidate_cache works" do
1733 user = insert(:user)
1734
1735 User.set_cache(user)
1736 User.invalidate_cache(user)
1737
1738 {:ok, nil} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1739 {:ok, nil} = Cachex.get(:user_cache, "nickname:#{user.nickname}")
1740 end
1741
1742 test "User.delete() plugs any possible zombie objects" do
1743 user = insert(:user)
1744
1745 {:ok, job} = User.delete(user)
1746 {:ok, _} = ObanHelpers.perform(job)
1747
1748 {:ok, cached_user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1749
1750 assert cached_user != user
1751
1752 {:ok, cached_user} = Cachex.get(:user_cache, "nickname:#{user.ap_id}")
1753
1754 assert cached_user != user
1755 end
1756 end
1757
1758 describe "account_status/1" do
1759 setup do: clear_config([:instance, :account_activation_required])
1760
1761 test "return confirmation_pending for unconfirm user" do
1762 clear_config([:instance, :account_activation_required], true)
1763 user = insert(:user, is_confirmed: false)
1764 assert User.account_status(user) == :confirmation_pending
1765 end
1766
1767 test "return active for confirmed user" do
1768 clear_config([:instance, :account_activation_required], true)
1769 user = insert(:user, is_confirmed: true)
1770 assert User.account_status(user) == :active
1771 end
1772
1773 test "return active for remote user" do
1774 user = insert(:user, local: false)
1775 assert User.account_status(user) == :active
1776 end
1777
1778 test "returns :password_reset_pending for user with reset password" do
1779 user = insert(:user, password_reset_pending: true)
1780 assert User.account_status(user) == :password_reset_pending
1781 end
1782
1783 test "returns :deactivated for deactivated user" do
1784 user = insert(:user, local: true, is_confirmed: true, is_active: false)
1785 assert User.account_status(user) == :deactivated
1786 end
1787
1788 test "returns :approval_pending for unapproved user" do
1789 user = insert(:user, local: true, is_approved: false)
1790 assert User.account_status(user) == :approval_pending
1791
1792 user = insert(:user, local: true, is_confirmed: false, is_approved: false)
1793 assert User.account_status(user) == :approval_pending
1794 end
1795 end
1796
1797 describe "superuser?/1" do
1798 test "returns false for unprivileged users" do
1799 user = insert(:user, local: true)
1800
1801 refute User.superuser?(user)
1802 end
1803
1804 test "returns false for remote users" do
1805 user = insert(:user, local: false)
1806 remote_admin_user = insert(:user, local: false, is_admin: true)
1807
1808 refute User.superuser?(user)
1809 refute User.superuser?(remote_admin_user)
1810 end
1811
1812 test "returns true for local moderators" do
1813 user = insert(:user, local: true, is_moderator: true)
1814
1815 assert User.superuser?(user)
1816 end
1817
1818 test "returns true for local admins" do
1819 user = insert(:user, local: true, is_admin: true)
1820
1821 assert User.superuser?(user)
1822 end
1823 end
1824
1825 describe "invisible?/1" do
1826 test "returns true for an invisible user" do
1827 user = insert(:user, local: true, invisible: true)
1828
1829 assert User.invisible?(user)
1830 end
1831
1832 test "returns false for a non-invisible user" do
1833 user = insert(:user, local: true)
1834
1835 refute User.invisible?(user)
1836 end
1837 end
1838
1839 describe "visible_for/2" do
1840 test "returns true when the account is itself" do
1841 user = insert(:user, local: true)
1842
1843 assert User.visible_for(user, user) == :visible
1844 end
1845
1846 test "returns false when the account is unconfirmed and confirmation is required" do
1847 clear_config([:instance, :account_activation_required], true)
1848
1849 user = insert(:user, local: true, is_confirmed: false)
1850 other_user = insert(:user, local: true)
1851
1852 refute User.visible_for(user, other_user) == :visible
1853 end
1854
1855 test "returns true when the account is unconfirmed and confirmation is required but the account is remote" do
1856 clear_config([:instance, :account_activation_required], true)
1857
1858 user = insert(:user, local: false, is_confirmed: false)
1859 other_user = insert(:user, local: true)
1860
1861 assert User.visible_for(user, other_user) == :visible
1862 end
1863
1864 test "returns true when the account is unconfirmed and being viewed by a privileged account (confirmation required)" do
1865 clear_config([:instance, :account_activation_required], true)
1866
1867 user = insert(:user, local: true, is_confirmed: false)
1868 other_user = insert(:user, local: true, is_admin: true)
1869
1870 assert User.visible_for(user, other_user) == :visible
1871 end
1872 end
1873
1874 describe "parse_bio/2" do
1875 test "preserves hosts in user links text" do
1876 remote_user = insert(:user, local: false, nickname: "nick@domain.com")
1877 user = insert(:user)
1878 bio = "A.k.a. @nick@domain.com"
1879
1880 expected_text =
1881 ~s(A.k.a. <span class="h-card"><a class="u-url mention" data-user="#{remote_user.id}" href="#{remote_user.ap_id}" rel="ugc">@<span>nick@domain.com</span></a></span>)
1882
1883 assert expected_text == User.parse_bio(bio, user)
1884 end
1885
1886 test "Adds rel=me on linkbacked urls" do
1887 user = insert(:user, ap_id: "https://social.example.org/users/lain")
1888
1889 bio = "http://example.com/rel_me/null"
1890 expected_text = "<a href=\"#{bio}\">#{bio}</a>"
1891 assert expected_text == User.parse_bio(bio, user)
1892
1893 bio = "http://example.com/rel_me/link"
1894 expected_text = "<a href=\"#{bio}\" rel=\"me\">#{bio}</a>"
1895 assert expected_text == User.parse_bio(bio, user)
1896
1897 bio = "http://example.com/rel_me/anchor"
1898 expected_text = "<a href=\"#{bio}\" rel=\"me\">#{bio}</a>"
1899 assert expected_text == User.parse_bio(bio, user)
1900 end
1901 end
1902
1903 test "follower count is updated when a follower is blocked" do
1904 user = insert(:user)
1905 follower = insert(:user)
1906 follower2 = insert(:user)
1907 follower3 = insert(:user)
1908
1909 {:ok, follower, user} = User.follow(follower, user)
1910 {:ok, _follower2, _user} = User.follow(follower2, user)
1911 {:ok, _follower3, _user} = User.follow(follower3, user)
1912
1913 {:ok, _user_relationship} = User.block(user, follower)
1914 user = refresh_record(user)
1915
1916 assert user.follower_count == 2
1917 end
1918
1919 describe "list_inactive_users_query/1" do
1920 defp days_ago(days) do
1921 NaiveDateTime.add(
1922 NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second),
1923 -days * 60 * 60 * 24,
1924 :second
1925 )
1926 end
1927
1928 test "Users are inactive by default" do
1929 total = 10
1930
1931 users =
1932 Enum.map(1..total, fn _ ->
1933 insert(:user, last_digest_emailed_at: days_ago(20), is_active: true)
1934 end)
1935
1936 inactive_users_ids =
1937 Pleroma.User.list_inactive_users_query()
1938 |> Pleroma.Repo.all()
1939 |> Enum.map(& &1.id)
1940
1941 Enum.each(users, fn user ->
1942 assert user.id in inactive_users_ids
1943 end)
1944 end
1945
1946 test "Only includes users who has no recent activity" do
1947 total = 10
1948
1949 users =
1950 Enum.map(1..total, fn _ ->
1951 insert(:user, last_digest_emailed_at: days_ago(20), is_active: true)
1952 end)
1953
1954 {inactive, active} = Enum.split(users, trunc(total / 2))
1955
1956 Enum.map(active, fn user ->
1957 to = Enum.random(users -- [user])
1958
1959 {:ok, _} =
1960 CommonAPI.post(user, %{
1961 status: "hey @#{to.nickname}"
1962 })
1963 end)
1964
1965 inactive_users_ids =
1966 Pleroma.User.list_inactive_users_query()
1967 |> Pleroma.Repo.all()
1968 |> Enum.map(& &1.id)
1969
1970 Enum.each(active, fn user ->
1971 refute user.id in inactive_users_ids
1972 end)
1973
1974 Enum.each(inactive, fn user ->
1975 assert user.id in inactive_users_ids
1976 end)
1977 end
1978
1979 test "Only includes users with no read notifications" do
1980 total = 10
1981
1982 users =
1983 Enum.map(1..total, fn _ ->
1984 insert(:user, last_digest_emailed_at: days_ago(20), is_active: true)
1985 end)
1986
1987 [sender | recipients] = users
1988 {inactive, active} = Enum.split(recipients, trunc(total / 2))
1989
1990 Enum.each(recipients, fn to ->
1991 {:ok, _} =
1992 CommonAPI.post(sender, %{
1993 status: "hey @#{to.nickname}"
1994 })
1995
1996 {:ok, _} =
1997 CommonAPI.post(sender, %{
1998 status: "hey again @#{to.nickname}"
1999 })
2000 end)
2001
2002 Enum.each(active, fn user ->
2003 [n1, _n2] = Pleroma.Notification.for_user(user)
2004 {:ok, _} = Pleroma.Notification.read_one(user, n1.id)
2005 end)
2006
2007 inactive_users_ids =
2008 Pleroma.User.list_inactive_users_query()
2009 |> Pleroma.Repo.all()
2010 |> Enum.map(& &1.id)
2011
2012 Enum.each(active, fn user ->
2013 refute user.id in inactive_users_ids
2014 end)
2015
2016 Enum.each(inactive, fn user ->
2017 assert user.id in inactive_users_ids
2018 end)
2019 end
2020 end
2021
2022 describe "ensure_keys_present" do
2023 test "it creates keys for a user and stores them in info" do
2024 user = insert(:user)
2025 refute is_binary(user.keys)
2026 {:ok, user} = User.ensure_keys_present(user)
2027 assert is_binary(user.keys)
2028 end
2029
2030 test "it doesn't create keys if there already are some" do
2031 user = insert(:user, keys: "xxx")
2032 {:ok, user} = User.ensure_keys_present(user)
2033 assert user.keys == "xxx"
2034 end
2035 end
2036
2037 describe "get_ap_ids_by_nicknames" do
2038 test "it returns a list of AP ids for a given set of nicknames" do
2039 user = insert(:user)
2040 user_two = insert(:user)
2041
2042 ap_ids = User.get_ap_ids_by_nicknames([user.nickname, user_two.nickname, "nonexistent"])
2043 assert length(ap_ids) == 2
2044 assert user.ap_id in ap_ids
2045 assert user_two.ap_id in ap_ids
2046 end
2047 end
2048
2049 describe "sync followers count" do
2050 setup do
2051 user1 = insert(:user, local: false, ap_id: "http://localhost:4001/users/masto_closed")
2052 user2 = insert(:user, local: false, ap_id: "http://localhost:4001/users/fuser2")
2053 insert(:user, local: true)
2054 insert(:user, local: false, is_active: false)
2055 {:ok, user1: user1, user2: user2}
2056 end
2057
2058 test "external_users/1 external active users with limit", %{user1: user1, user2: user2} do
2059 [fdb_user1] = User.external_users(limit: 1)
2060
2061 assert fdb_user1.ap_id
2062 assert fdb_user1.ap_id == user1.ap_id
2063 assert fdb_user1.id == user1.id
2064
2065 [fdb_user2] = User.external_users(max_id: fdb_user1.id, limit: 1)
2066
2067 assert fdb_user2.ap_id
2068 assert fdb_user2.ap_id == user2.ap_id
2069 assert fdb_user2.id == user2.id
2070
2071 assert User.external_users(max_id: fdb_user2.id, limit: 1) == []
2072 end
2073 end
2074
2075 describe "is_internal_user?/1" do
2076 test "non-internal user returns false" do
2077 user = insert(:user)
2078 refute User.is_internal_user?(user)
2079 end
2080
2081 test "user with no nickname returns true" do
2082 user = insert(:user, %{nickname: nil})
2083 assert User.is_internal_user?(user)
2084 end
2085
2086 test "user with internal-prefixed nickname returns true" do
2087 user = insert(:user, %{nickname: "internal.test"})
2088 assert User.is_internal_user?(user)
2089 end
2090 end
2091
2092 describe "update_and_set_cache/1" do
2093 test "returns error when user is stale instead Ecto.StaleEntryError" do
2094 user = insert(:user)
2095
2096 changeset = Ecto.Changeset.change(user, bio: "test")
2097
2098 Repo.delete(user)
2099
2100 assert {:error, %Ecto.Changeset{errors: [id: {"is stale", [stale: true]}], valid?: false}} =
2101 User.update_and_set_cache(changeset)
2102 end
2103
2104 test "performs update cache if user updated" do
2105 user = insert(:user)
2106 assert {:ok, nil} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
2107
2108 changeset = Ecto.Changeset.change(user, bio: "test-bio")
2109
2110 assert {:ok, %User{bio: "test-bio"} = user} = User.update_and_set_cache(changeset)
2111 assert {:ok, user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
2112 assert %User{bio: "test-bio"} = User.get_cached_by_ap_id(user.ap_id)
2113 end
2114
2115 test "removes report notifs when user isn't superuser any more" do
2116 report_activity = insert(:report_activity)
2117 user = insert(:user, is_moderator: true, is_admin: true)
2118 {:ok, _} = Notification.create_notifications(report_activity)
2119
2120 assert [%Pleroma.Notification{type: "pleroma:report"}] = Notification.for_user(user)
2121
2122 {:ok, user} = user |> User.admin_api_update(%{is_moderator: false})
2123 # is still superuser because still admin
2124 assert [%Pleroma.Notification{type: "pleroma:report"}] = Notification.for_user(user)
2125
2126 {:ok, user} = user |> User.admin_api_update(%{is_moderator: true, is_admin: false})
2127 # is still superuser because still moderator
2128 assert [%Pleroma.Notification{type: "pleroma:report"}] = Notification.for_user(user)
2129
2130 {:ok, user} = user |> User.admin_api_update(%{is_moderator: false})
2131 # is not a superuser any more
2132 assert [] = Notification.for_user(user)
2133 end
2134 end
2135
2136 describe "following/followers synchronization" do
2137 setup do: clear_config([:instance, :external_user_synchronization])
2138
2139 test "updates the counters normally on following/getting a follow when disabled" do
2140 clear_config([:instance, :external_user_synchronization], false)
2141 user = insert(:user)
2142
2143 other_user =
2144 insert(:user,
2145 local: false,
2146 follower_address: "http://localhost:4001/users/masto_closed/followers",
2147 following_address: "http://localhost:4001/users/masto_closed/following",
2148 ap_enabled: true
2149 )
2150
2151 assert other_user.following_count == 0
2152 assert other_user.follower_count == 0
2153
2154 {:ok, user, other_user} = Pleroma.User.follow(user, other_user)
2155
2156 assert user.following_count == 1
2157 assert other_user.follower_count == 1
2158 end
2159
2160 test "syncronizes the counters with the remote instance for the followed when enabled" do
2161 clear_config([:instance, :external_user_synchronization], false)
2162
2163 user = insert(:user)
2164
2165 other_user =
2166 insert(:user,
2167 local: false,
2168 follower_address: "http://localhost:4001/users/masto_closed/followers",
2169 following_address: "http://localhost:4001/users/masto_closed/following",
2170 ap_enabled: true
2171 )
2172
2173 assert other_user.following_count == 0
2174 assert other_user.follower_count == 0
2175
2176 clear_config([:instance, :external_user_synchronization], true)
2177 {:ok, _user, other_user} = User.follow(user, other_user)
2178
2179 assert other_user.follower_count == 437
2180 end
2181
2182 test "syncronizes the counters with the remote instance for the follower when enabled" do
2183 clear_config([:instance, :external_user_synchronization], false)
2184
2185 user = insert(:user)
2186
2187 other_user =
2188 insert(:user,
2189 local: false,
2190 follower_address: "http://localhost:4001/users/masto_closed/followers",
2191 following_address: "http://localhost:4001/users/masto_closed/following",
2192 ap_enabled: true
2193 )
2194
2195 assert other_user.following_count == 0
2196 assert other_user.follower_count == 0
2197
2198 clear_config([:instance, :external_user_synchronization], true)
2199 {:ok, other_user, _user} = User.follow(other_user, user)
2200
2201 assert other_user.following_count == 152
2202 end
2203 end
2204
2205 describe "change_email/2" do
2206 setup do
2207 [user: insert(:user)]
2208 end
2209
2210 test "blank email returns error if we require an email on registration", %{user: user} do
2211 orig_account_activation_required =
2212 Pleroma.Config.get([:instance, :account_activation_required])
2213
2214 Pleroma.Config.put([:instance, :account_activation_required], true)
2215
2216 on_exit(fn ->
2217 Pleroma.Config.put(
2218 [:instance, :account_activation_required],
2219 orig_account_activation_required
2220 )
2221 end)
2222
2223 assert {:error, %{errors: [email: {"can't be blank", _}]}} = User.change_email(user, "")
2224 assert {:error, %{errors: [email: {"can't be blank", _}]}} = User.change_email(user, nil)
2225 end
2226
2227 test "blank email should be fine if we do not require an email on registration", %{user: user} do
2228 orig_account_activation_required =
2229 Pleroma.Config.get([:instance, :account_activation_required])
2230
2231 Pleroma.Config.put([:instance, :account_activation_required], false)
2232
2233 on_exit(fn ->
2234 Pleroma.Config.put(
2235 [:instance, :account_activation_required],
2236 orig_account_activation_required
2237 )
2238 end)
2239
2240 assert {:ok, %User{email: nil}} = User.change_email(user, "")
2241 assert {:ok, %User{email: nil}} = User.change_email(user, nil)
2242 end
2243
2244 test "non unique email returns error", %{user: user} do
2245 %{email: email} = insert(:user)
2246
2247 assert {:error, %{errors: [email: {"has already been taken", _}]}} =
2248 User.change_email(user, email)
2249 end
2250
2251 test "invalid email returns error", %{user: user} do
2252 assert {:error, %{errors: [email: {"has invalid format", _}]}} =
2253 User.change_email(user, "cofe")
2254 end
2255
2256 test "changes email", %{user: user} do
2257 assert {:ok, %User{email: "cofe@cofe.party"}} = User.change_email(user, "cofe@cofe.party")
2258 end
2259
2260 test "adds email", %{user: user} do
2261 orig_account_activation_required =
2262 Pleroma.Config.get([:instance, :account_activation_required])
2263
2264 Pleroma.Config.put([:instance, :account_activation_required], false)
2265
2266 on_exit(fn ->
2267 Pleroma.Config.put(
2268 [:instance, :account_activation_required],
2269 orig_account_activation_required
2270 )
2271 end)
2272
2273 assert {:ok, _} = User.change_email(user, "")
2274 Pleroma.Config.put([:instance, :account_activation_required], true)
2275
2276 assert {:ok, %User{email: "cofe2@cofe.party"}} = User.change_email(user, "cofe2@cofe.party")
2277 end
2278 end
2279
2280 describe "get_cached_by_nickname_or_id" do
2281 setup do
2282 local_user = insert(:user)
2283 remote_user = insert(:user, nickname: "nickname@example.com", local: false)
2284
2285 [local_user: local_user, remote_user: remote_user]
2286 end
2287
2288 setup do: clear_config([:instance, :limit_to_local_content])
2289
2290 test "allows getting remote users by id no matter what :limit_to_local_content is set to", %{
2291 remote_user: remote_user
2292 } do
2293 clear_config([:instance, :limit_to_local_content], false)
2294 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2295
2296 clear_config([:instance, :limit_to_local_content], true)
2297 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2298
2299 clear_config([:instance, :limit_to_local_content], :unauthenticated)
2300 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2301 end
2302
2303 test "disallows getting remote users by nickname without authentication when :limit_to_local_content is set to :unauthenticated",
2304 %{remote_user: remote_user} do
2305 clear_config([:instance, :limit_to_local_content], :unauthenticated)
2306 assert nil == User.get_cached_by_nickname_or_id(remote_user.nickname)
2307 end
2308
2309 test "allows getting remote users by nickname with authentication when :limit_to_local_content is set to :unauthenticated",
2310 %{remote_user: remote_user, local_user: local_user} do
2311 clear_config([:instance, :limit_to_local_content], :unauthenticated)
2312 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.nickname, for: local_user)
2313 end
2314
2315 test "disallows getting remote users by nickname when :limit_to_local_content is set to true",
2316 %{remote_user: remote_user} do
2317 clear_config([:instance, :limit_to_local_content], true)
2318 assert nil == User.get_cached_by_nickname_or_id(remote_user.nickname)
2319 end
2320
2321 test "allows getting local users by nickname no matter what :limit_to_local_content is set to",
2322 %{local_user: local_user} do
2323 clear_config([:instance, :limit_to_local_content], false)
2324 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2325
2326 clear_config([:instance, :limit_to_local_content], true)
2327 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2328
2329 clear_config([:instance, :limit_to_local_content], :unauthenticated)
2330 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2331 end
2332 end
2333
2334 describe "update_email_notifications/2" do
2335 setup do
2336 user = insert(:user, email_notifications: %{"digest" => true})
2337
2338 {:ok, user: user}
2339 end
2340
2341 test "Notifications are updated", %{user: user} do
2342 true = user.email_notifications["digest"]
2343 assert {:ok, result} = User.update_email_notifications(user, %{"digest" => false})
2344 assert result.email_notifications["digest"] == false
2345 end
2346 end
2347
2348 describe "local_nickname/1" do
2349 test "returns nickname without host" do
2350 assert User.local_nickname("@mentioned") == "mentioned"
2351 assert User.local_nickname("a_local_nickname") == "a_local_nickname"
2352 assert User.local_nickname("nickname@host.com") == "nickname"
2353 end
2354 end
2355
2356 describe "full_nickname/1" do
2357 test "returns fully qualified nickname for local and remote users" do
2358 local_user =
2359 insert(:user, nickname: "local_user", ap_id: "https://somehost.com/users/local_user")
2360
2361 remote_user = insert(:user, nickname: "remote@host.com", local: false)
2362
2363 assert User.full_nickname(local_user) == "local_user@somehost.com"
2364 assert User.full_nickname(remote_user) == "remote@host.com"
2365 end
2366
2367 test "strips leading @ from mentions" do
2368 assert User.full_nickname("@mentioned") == "mentioned"
2369 assert User.full_nickname("@nickname@host.com") == "nickname@host.com"
2370 end
2371
2372 test "does not modify nicknames" do
2373 assert User.full_nickname("nickname") == "nickname"
2374 assert User.full_nickname("nickname@host.com") == "nickname@host.com"
2375 end
2376 end
2377
2378 test "avatar fallback" do
2379 user = insert(:user)
2380 assert User.avatar_url(user) =~ "/images/avi.png"
2381
2382 clear_config([:assets, :default_user_avatar], "avatar.png")
2383
2384 user = User.get_cached_by_nickname_or_id(user.nickname)
2385 assert User.avatar_url(user) =~ "avatar.png"
2386
2387 assert User.avatar_url(user, no_default: true) == nil
2388 end
2389
2390 test "get_host/1" do
2391 user = insert(:user, ap_id: "https://lain.com/users/lain", nickname: "lain")
2392 assert User.get_host(user) == "lain.com"
2393 end
2394
2395 test "update_last_active_at/1" do
2396 user = insert(:user)
2397 assert is_nil(user.last_active_at)
2398
2399 test_started_at = NaiveDateTime.utc_now() |> NaiveDateTime.truncate(:second)
2400
2401 assert {:ok, user} = User.update_last_active_at(user)
2402
2403 assert user.last_active_at >= test_started_at
2404 assert user.last_active_at <= NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second)
2405
2406 last_active_at =
2407 NaiveDateTime.utc_now()
2408 |> NaiveDateTime.add(-:timer.hours(24), :millisecond)
2409 |> NaiveDateTime.truncate(:second)
2410
2411 assert {:ok, user} =
2412 user
2413 |> cast(%{last_active_at: last_active_at}, [:last_active_at])
2414 |> User.update_and_set_cache()
2415
2416 assert user.last_active_at == last_active_at
2417 assert {:ok, user} = User.update_last_active_at(user)
2418 assert user.last_active_at >= test_started_at
2419 assert user.last_active_at <= NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second)
2420 end
2421
2422 test "active_user_count/1" do
2423 insert(:user)
2424 insert(:user, %{local: false})
2425 insert(:user, %{last_active_at: NaiveDateTime.utc_now()})
2426 insert(:user, %{last_active_at: Timex.shift(NaiveDateTime.utc_now(), days: -15)})
2427 insert(:user, %{last_active_at: Timex.shift(NaiveDateTime.utc_now(), weeks: -6)})
2428 insert(:user, %{last_active_at: Timex.shift(NaiveDateTime.utc_now(), months: -7)})
2429 insert(:user, %{last_active_at: Timex.shift(NaiveDateTime.utc_now(), years: -2)})
2430
2431 assert User.active_user_count() == 2
2432 assert User.active_user_count(180) == 3
2433 assert User.active_user_count(365) == 4
2434 assert User.active_user_count(1000) == 5
2435 end
2436
2437 describe "pins" do
2438 setup do
2439 user = insert(:user)
2440
2441 [user: user, object_id: object_id_from_created_activity(user)]
2442 end
2443
2444 test "unique pins", %{user: user, object_id: object_id} do
2445 assert {:ok, %{pinned_objects: %{^object_id => pinned_at1} = pins} = updated_user} =
2446 User.add_pinned_object_id(user, object_id)
2447
2448 assert Enum.count(pins) == 1
2449
2450 assert {:ok, %{pinned_objects: %{^object_id => pinned_at2} = pins}} =
2451 User.add_pinned_object_id(updated_user, object_id)
2452
2453 assert pinned_at1 == pinned_at2
2454
2455 assert Enum.count(pins) == 1
2456 end
2457
2458 test "respects max_pinned_statuses limit", %{user: user, object_id: object_id} do
2459 clear_config([:instance, :max_pinned_statuses], 1)
2460 {:ok, updated} = User.add_pinned_object_id(user, object_id)
2461
2462 object_id2 = object_id_from_created_activity(user)
2463
2464 {:error, %{errors: errors}} = User.add_pinned_object_id(updated, object_id2)
2465 assert Keyword.has_key?(errors, :pinned_objects)
2466 end
2467
2468 test "remove_pinned_object_id/2", %{user: user, object_id: object_id} do
2469 assert {:ok, updated} = User.add_pinned_object_id(user, object_id)
2470
2471 {:ok, after_remove} = User.remove_pinned_object_id(updated, object_id)
2472 assert after_remove.pinned_objects == %{}
2473 end
2474 end
2475
2476 defp object_id_from_created_activity(user) do
2477 %{id: id} = insert(:note_activity, user: user)
2478 %{object: %{data: %{"id" => object_id}}} = Activity.get_by_id_with_object(id)
2479 object_id
2480 end
2481
2482 describe "add_alias/2" do
2483 test "should add alias for another user" do
2484 user = insert(:user)
2485 user2 = insert(:user)
2486
2487 assert {:ok, user_updated} = user |> User.add_alias(user2)
2488
2489 assert user_updated.also_known_as |> length() == 1
2490 assert user2.ap_id in user_updated.also_known_as
2491 end
2492
2493 test "should add multiple aliases" do
2494 user = insert(:user)
2495 user2 = insert(:user)
2496 user3 = insert(:user)
2497
2498 assert {:ok, user} = user |> User.add_alias(user2)
2499 assert {:ok, user_updated} = user |> User.add_alias(user3)
2500
2501 assert user_updated.also_known_as |> length() == 2
2502 assert user2.ap_id in user_updated.also_known_as
2503 assert user3.ap_id in user_updated.also_known_as
2504 end
2505
2506 test "should not add duplicate aliases" do
2507 user = insert(:user)
2508 user2 = insert(:user)
2509
2510 assert {:ok, user} = user |> User.add_alias(user2)
2511
2512 assert {:ok, user_updated} = user |> User.add_alias(user2)
2513
2514 assert user_updated.also_known_as |> length() == 1
2515 assert user2.ap_id in user_updated.also_known_as
2516 end
2517 end
2518
2519 describe "alias_users/1" do
2520 test "should get aliases for a user" do
2521 user = insert(:user)
2522 user2 = insert(:user, also_known_as: [user.ap_id])
2523
2524 aliases = user2 |> User.alias_users()
2525
2526 assert aliases |> length() == 1
2527
2528 alias_user = aliases |> Enum.at(0)
2529
2530 assert alias_user.ap_id == user.ap_id
2531 end
2532 end
2533
2534 describe "delete_alias/2" do
2535 test "should delete existing alias" do
2536 user = insert(:user)
2537 user2 = insert(:user, also_known_as: [user.ap_id])
2538
2539 assert {:ok, user_updated} = user2 |> User.delete_alias(user)
2540
2541 assert user_updated.also_known_as == []
2542 end
2543
2544 test "should report error on non-existing alias" do
2545 user = insert(:user)
2546 user2 = insert(:user)
2547 user3 = insert(:user, also_known_as: [user.ap_id])
2548
2549 assert {:error, :no_such_alias} = user3 |> User.delete_alias(user2)
2550
2551 user3_updated = User.get_cached_by_ap_id(user3.ap_id)
2552
2553 assert user3_updated.also_known_as |> length() == 1
2554 assert user.ap_id in user3_updated.also_known_as
2555 end
2556 end
2557 end