67136e95b45dbcb80507b2383d2eacd0206e121c
[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 "get_or_fetch/1 remote users with tld, while BE is runned on subdomain" do
742 setup do: clear_config([Pleroma.Web.WebFinger, :update_nickname_on_user_fetch], true)
743
744 test "for mastodon" do
745 Tesla.Mock.mock(fn
746 %{url: "https://example.com/.well-known/host-meta"} ->
747 %Tesla.Env{
748 status: 302,
749 headers: [{"location", "https://sub.example.com/.well-known/host-meta"}]
750 }
751
752 %{url: "https://sub.example.com/.well-known/host-meta"} ->
753 %Tesla.Env{
754 status: 200,
755 body:
756 "test/fixtures/webfinger/masto-host-meta.xml"
757 |> File.read!()
758 |> String.replace("{{domain}}", "sub.example.com")
759 }
760
761 %{url: "https://sub.example.com/.well-known/webfinger?resource=acct:a@example.com"} ->
762 %Tesla.Env{
763 status: 200,
764 body:
765 "test/fixtures/webfinger/masto-webfinger.json"
766 |> File.read!()
767 |> String.replace("{{nickname}}", "a")
768 |> String.replace("{{domain}}", "example.com")
769 |> String.replace("{{subdomain}}", "sub.example.com"),
770 headers: [{"content-type", "application/jrd+json"}]
771 }
772
773 %{url: "https://sub.example.com/users/a"} ->
774 %Tesla.Env{
775 status: 200,
776 body:
777 "test/fixtures/webfinger/masto-user.json"
778 |> File.read!()
779 |> String.replace("{{nickname}}", "a")
780 |> String.replace("{{domain}}", "sub.example.com"),
781 headers: [{"content-type", "application/activity+json"}]
782 }
783
784 %{url: "https://sub.example.com/users/a/collections/featured"} ->
785 %Tesla.Env{
786 status: 200,
787 body:
788 File.read!("test/fixtures/users_mock/masto_featured.json")
789 |> String.replace("{{domain}}", "sub.example.com")
790 |> String.replace("{{nickname}}", "a"),
791 headers: [{"content-type", "application/activity+json"}]
792 }
793 end)
794
795 ap_id = "a@example.com"
796 {:ok, fetched_user} = User.get_or_fetch(ap_id)
797
798 assert fetched_user.ap_id == "https://sub.example.com/users/a"
799 assert fetched_user.nickname == "a@example.com"
800 end
801
802 test "for pleroma" do
803 Tesla.Mock.mock(fn
804 %{url: "https://example.com/.well-known/host-meta"} ->
805 %Tesla.Env{
806 status: 302,
807 headers: [{"location", "https://sub.example.com/.well-known/host-meta"}]
808 }
809
810 %{url: "https://sub.example.com/.well-known/host-meta"} ->
811 %Tesla.Env{
812 status: 200,
813 body:
814 "test/fixtures/webfinger/pleroma-host-meta.xml"
815 |> File.read!()
816 |> String.replace("{{domain}}", "sub.example.com")
817 }
818
819 %{url: "https://sub.example.com/.well-known/webfinger?resource=acct:a@example.com"} ->
820 %Tesla.Env{
821 status: 200,
822 body:
823 "test/fixtures/webfinger/pleroma-webfinger.json"
824 |> File.read!()
825 |> String.replace("{{nickname}}", "a")
826 |> String.replace("{{domain}}", "example.com")
827 |> String.replace("{{subdomain}}", "sub.example.com"),
828 headers: [{"content-type", "application/jrd+json"}]
829 }
830
831 %{url: "https://sub.example.com/users/a"} ->
832 %Tesla.Env{
833 status: 200,
834 body:
835 "test/fixtures/webfinger/pleroma-user.json"
836 |> File.read!()
837 |> String.replace("{{nickname}}", "a")
838 |> String.replace("{{domain}}", "sub.example.com"),
839 headers: [{"content-type", "application/activity+json"}]
840 }
841 end)
842
843 ap_id = "a@example.com"
844 {:ok, fetched_user} = User.get_or_fetch(ap_id)
845
846 assert fetched_user.ap_id == "https://sub.example.com/users/a"
847 assert fetched_user.nickname == "a@example.com"
848 end
849 end
850
851 describe "fetching a user from nickname or trying to build one" do
852 test "gets an existing user" do
853 user = insert(:user)
854 {:ok, fetched_user} = User.get_or_fetch_by_nickname(user.nickname)
855
856 assert user == fetched_user
857 end
858
859 test "gets an existing user, case insensitive" do
860 user = insert(:user, nickname: "nick")
861 {:ok, fetched_user} = User.get_or_fetch_by_nickname("NICK")
862
863 assert user == fetched_user
864 end
865
866 test "gets an existing user by fully qualified nickname" do
867 user = insert(:user)
868
869 {:ok, fetched_user} =
870 User.get_or_fetch_by_nickname(user.nickname <> "@" <> Pleroma.Web.Endpoint.host())
871
872 assert user == fetched_user
873 end
874
875 test "gets an existing user by fully qualified nickname, case insensitive" do
876 user = insert(:user, nickname: "nick")
877 casing_altered_fqn = String.upcase(user.nickname <> "@" <> Pleroma.Web.Endpoint.host())
878
879 {:ok, fetched_user} = User.get_or_fetch_by_nickname(casing_altered_fqn)
880
881 assert user == fetched_user
882 end
883
884 @tag capture_log: true
885 test "returns nil if no user could be fetched" do
886 {:error, fetched_user} = User.get_or_fetch_by_nickname("nonexistant@social.heldscal.la")
887 assert fetched_user == "not found nonexistant@social.heldscal.la"
888 end
889
890 test "returns nil for nonexistant local user" do
891 {:error, fetched_user} = User.get_or_fetch_by_nickname("nonexistant")
892 assert fetched_user == "not found nonexistant"
893 end
894
895 test "updates an existing user, if stale" do
896 a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
897
898 orig_user =
899 insert(
900 :user,
901 local: false,
902 nickname: "admin@mastodon.example.org",
903 ap_id: "http://mastodon.example.org/users/admin",
904 last_refreshed_at: a_week_ago
905 )
906
907 assert orig_user.last_refreshed_at == a_week_ago
908
909 {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/admin")
910
911 assert user.inbox
912
913 refute user.last_refreshed_at == orig_user.last_refreshed_at
914 end
915
916 test "if nicknames clash, the old user gets a prefix with the old id to the nickname" do
917 a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
918
919 orig_user =
920 insert(
921 :user,
922 local: false,
923 nickname: "admin@mastodon.example.org",
924 ap_id: "http://mastodon.example.org/users/harinezumigari",
925 last_refreshed_at: a_week_ago
926 )
927
928 assert orig_user.last_refreshed_at == a_week_ago
929
930 {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/admin")
931
932 assert user.inbox
933
934 refute user.id == orig_user.id
935
936 orig_user = User.get_by_id(orig_user.id)
937
938 assert orig_user.nickname == "#{orig_user.id}.admin@mastodon.example.org"
939 end
940
941 @tag capture_log: true
942 test "it returns the old user if stale, but unfetchable" do
943 a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
944
945 orig_user =
946 insert(
947 :user,
948 local: false,
949 nickname: "admin@mastodon.example.org",
950 ap_id: "http://mastodon.example.org/users/raymoo",
951 last_refreshed_at: a_week_ago
952 )
953
954 assert orig_user.last_refreshed_at == a_week_ago
955
956 {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/raymoo")
957
958 assert user.last_refreshed_at == orig_user.last_refreshed_at
959 end
960 end
961
962 test "returns an ap_id for a user" do
963 user = insert(:user)
964
965 assert User.ap_id(user) ==
966 Pleroma.Web.Router.Helpers.user_feed_url(
967 Pleroma.Web.Endpoint,
968 :feed_redirect,
969 user.nickname
970 )
971 end
972
973 test "returns an ap_followers link for a user" do
974 user = insert(:user)
975
976 assert User.ap_followers(user) ==
977 Pleroma.Web.Router.Helpers.user_feed_url(
978 Pleroma.Web.Endpoint,
979 :feed_redirect,
980 user.nickname
981 ) <> "/followers"
982 end
983
984 describe "remote user changeset" do
985 @valid_remote %{
986 bio: "hello",
987 name: "Someone",
988 nickname: "a@b.de",
989 ap_id: "http...",
990 avatar: %{some: "avatar"}
991 }
992 setup do: clear_config([:instance, :user_bio_length])
993 setup do: clear_config([:instance, :user_name_length])
994
995 test "it confirms validity" do
996 cs = User.remote_user_changeset(@valid_remote)
997 assert cs.valid?
998 end
999
1000 test "it sets the follower_adress" do
1001 cs = User.remote_user_changeset(@valid_remote)
1002 # remote users get a fake local follower address
1003 assert cs.changes.follower_address ==
1004 User.ap_followers(%User{nickname: @valid_remote[:nickname]})
1005 end
1006
1007 test "it enforces the fqn format for nicknames" do
1008 cs = User.remote_user_changeset(%{@valid_remote | nickname: "bla"})
1009 assert Ecto.Changeset.get_field(cs, :local) == false
1010 assert cs.changes.avatar
1011 refute cs.valid?
1012 end
1013
1014 test "it has required fields" do
1015 [:ap_id]
1016 |> Enum.each(fn field ->
1017 cs = User.remote_user_changeset(Map.delete(@valid_remote, field))
1018 refute cs.valid?
1019 end)
1020 end
1021
1022 test "it is invalid given a local user" do
1023 user = insert(:user)
1024 cs = User.remote_user_changeset(user, %{name: "tom from myspace"})
1025
1026 refute cs.valid?
1027 end
1028 end
1029
1030 describe "followers and friends" do
1031 test "gets all followers for a given user" do
1032 user = insert(:user)
1033 follower_one = insert(:user)
1034 follower_two = insert(:user)
1035 not_follower = insert(:user)
1036
1037 {:ok, follower_one, user} = User.follow(follower_one, user)
1038 {:ok, follower_two, user} = User.follow(follower_two, user)
1039
1040 res = User.get_followers(user)
1041
1042 assert Enum.member?(res, follower_one)
1043 assert Enum.member?(res, follower_two)
1044 refute Enum.member?(res, not_follower)
1045 end
1046
1047 test "gets all friends (followed users) for a given user" do
1048 user = insert(:user)
1049 followed_one = insert(:user)
1050 followed_two = insert(:user)
1051 not_followed = insert(:user)
1052
1053 {:ok, user, followed_one} = User.follow(user, followed_one)
1054 {:ok, user, followed_two} = User.follow(user, followed_two)
1055
1056 res = User.get_friends(user)
1057
1058 followed_one = User.get_cached_by_ap_id(followed_one.ap_id)
1059 followed_two = User.get_cached_by_ap_id(followed_two.ap_id)
1060 assert Enum.member?(res, followed_one)
1061 assert Enum.member?(res, followed_two)
1062 refute Enum.member?(res, not_followed)
1063 end
1064 end
1065
1066 describe "updating note and follower count" do
1067 test "it sets the note_count property" do
1068 note = insert(:note)
1069
1070 user = User.get_cached_by_ap_id(note.data["actor"])
1071
1072 assert user.note_count == 0
1073
1074 {:ok, user} = User.update_note_count(user)
1075
1076 assert user.note_count == 1
1077 end
1078
1079 test "it increases the note_count property" do
1080 note = insert(:note)
1081 user = User.get_cached_by_ap_id(note.data["actor"])
1082
1083 assert user.note_count == 0
1084
1085 {:ok, user} = User.increase_note_count(user)
1086
1087 assert user.note_count == 1
1088
1089 {:ok, user} = User.increase_note_count(user)
1090
1091 assert user.note_count == 2
1092 end
1093
1094 test "it decreases the note_count property" do
1095 note = insert(:note)
1096 user = User.get_cached_by_ap_id(note.data["actor"])
1097
1098 assert user.note_count == 0
1099
1100 {:ok, user} = User.increase_note_count(user)
1101
1102 assert user.note_count == 1
1103
1104 {:ok, user} = User.decrease_note_count(user)
1105
1106 assert user.note_count == 0
1107
1108 {:ok, user} = User.decrease_note_count(user)
1109
1110 assert user.note_count == 0
1111 end
1112
1113 test "it sets the follower_count property" do
1114 user = insert(:user)
1115 follower = insert(:user)
1116
1117 User.follow(follower, user)
1118
1119 assert user.follower_count == 0
1120
1121 {:ok, user} = User.update_follower_count(user)
1122
1123 assert user.follower_count == 1
1124 end
1125 end
1126
1127 describe "mutes" do
1128 test "it mutes people" do
1129 user = insert(:user)
1130 muted_user = insert(:user)
1131
1132 refute User.mutes?(user, muted_user)
1133 refute User.muted_notifications?(user, muted_user)
1134
1135 {:ok, _user_relationships} = User.mute(user, muted_user)
1136
1137 assert User.mutes?(user, muted_user)
1138 assert User.muted_notifications?(user, muted_user)
1139 end
1140
1141 test "expiring" do
1142 user = insert(:user)
1143 muted_user = insert(:user)
1144
1145 {:ok, _user_relationships} = User.mute(user, muted_user, %{expires_in: 60})
1146 assert User.mutes?(user, muted_user)
1147
1148 worker = Pleroma.Workers.MuteExpireWorker
1149 args = %{"op" => "unmute_user", "muter_id" => user.id, "mutee_id" => muted_user.id}
1150
1151 assert_enqueued(
1152 worker: worker,
1153 args: args
1154 )
1155
1156 assert :ok = perform_job(worker, args)
1157
1158 refute User.mutes?(user, muted_user)
1159 refute User.muted_notifications?(user, muted_user)
1160 end
1161
1162 test "it unmutes users" do
1163 user = insert(:user)
1164 muted_user = insert(:user)
1165
1166 {:ok, _user_relationships} = User.mute(user, muted_user)
1167 {:ok, _user_mute} = User.unmute(user, muted_user)
1168
1169 refute User.mutes?(user, muted_user)
1170 refute User.muted_notifications?(user, muted_user)
1171 end
1172
1173 test "it unmutes users by id" do
1174 user = insert(:user)
1175 muted_user = insert(:user)
1176
1177 {:ok, _user_relationships} = User.mute(user, muted_user)
1178 {:ok, _user_mute} = User.unmute(user.id, muted_user.id)
1179
1180 refute User.mutes?(user, muted_user)
1181 refute User.muted_notifications?(user, muted_user)
1182 end
1183
1184 test "it mutes user without notifications" do
1185 user = insert(:user)
1186 muted_user = insert(:user)
1187
1188 refute User.mutes?(user, muted_user)
1189 refute User.muted_notifications?(user, muted_user)
1190
1191 {:ok, _user_relationships} = User.mute(user, muted_user, %{notifications: false})
1192
1193 assert User.mutes?(user, muted_user)
1194 refute User.muted_notifications?(user, muted_user)
1195 end
1196 end
1197
1198 describe "blocks" do
1199 test "it blocks people" do
1200 user = insert(:user)
1201 blocked_user = insert(:user)
1202
1203 refute User.blocks?(user, blocked_user)
1204
1205 {:ok, _user_relationship} = User.block(user, blocked_user)
1206
1207 assert User.blocks?(user, blocked_user)
1208 end
1209
1210 test "it unblocks users" do
1211 user = insert(:user)
1212 blocked_user = insert(:user)
1213
1214 {:ok, _user_relationship} = User.block(user, blocked_user)
1215 {:ok, _user_block} = User.unblock(user, blocked_user)
1216
1217 refute User.blocks?(user, blocked_user)
1218 end
1219
1220 test "blocks tear down cyclical follow relationships" do
1221 blocker = insert(:user)
1222 blocked = insert(:user)
1223
1224 {:ok, blocker, blocked} = User.follow(blocker, blocked)
1225 {:ok, blocked, blocker} = User.follow(blocked, blocker)
1226
1227 assert User.following?(blocker, blocked)
1228 assert User.following?(blocked, blocker)
1229
1230 {:ok, _user_relationship} = User.block(blocker, blocked)
1231 blocked = User.get_cached_by_id(blocked.id)
1232
1233 assert User.blocks?(blocker, blocked)
1234
1235 refute User.following?(blocker, blocked)
1236 refute User.following?(blocked, blocker)
1237 end
1238
1239 test "blocks tear down blocker->blocked follow relationships" do
1240 blocker = insert(:user)
1241 blocked = insert(:user)
1242
1243 {:ok, blocker, blocked} = User.follow(blocker, blocked)
1244
1245 assert User.following?(blocker, blocked)
1246 refute User.following?(blocked, blocker)
1247
1248 {:ok, _user_relationship} = User.block(blocker, blocked)
1249 blocked = User.get_cached_by_id(blocked.id)
1250
1251 assert User.blocks?(blocker, blocked)
1252
1253 refute User.following?(blocker, blocked)
1254 refute User.following?(blocked, blocker)
1255 end
1256
1257 test "blocks tear down blocked->blocker follow relationships" do
1258 blocker = insert(:user)
1259 blocked = insert(:user)
1260
1261 {:ok, blocked, blocker} = User.follow(blocked, blocker)
1262
1263 refute User.following?(blocker, blocked)
1264 assert User.following?(blocked, blocker)
1265
1266 {:ok, _user_relationship} = User.block(blocker, blocked)
1267 blocked = User.get_cached_by_id(blocked.id)
1268
1269 assert User.blocks?(blocker, blocked)
1270
1271 refute User.following?(blocker, blocked)
1272 refute User.following?(blocked, blocker)
1273 end
1274
1275 test "blocks tear down blocked->blocker subscription relationships" do
1276 blocker = insert(:user)
1277 blocked = insert(:user)
1278
1279 {:ok, _subscription} = User.subscribe(blocked, blocker)
1280
1281 assert User.subscribed_to?(blocked, blocker)
1282 refute User.subscribed_to?(blocker, blocked)
1283
1284 {:ok, _user_relationship} = User.block(blocker, blocked)
1285
1286 assert User.blocks?(blocker, blocked)
1287 refute User.subscribed_to?(blocker, blocked)
1288 refute User.subscribed_to?(blocked, blocker)
1289 end
1290 end
1291
1292 describe "domain blocking" do
1293 test "blocks domains" do
1294 user = insert(:user)
1295 collateral_user = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1296
1297 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1298
1299 assert User.blocks?(user, collateral_user)
1300 end
1301
1302 test "does not block domain with same end" do
1303 user = insert(:user)
1304
1305 collateral_user =
1306 insert(:user, %{ap_id: "https://another-awful-and-rude-instance.com/user/bully"})
1307
1308 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1309
1310 refute User.blocks?(user, collateral_user)
1311 end
1312
1313 test "does not block domain with same end if wildcard added" do
1314 user = insert(:user)
1315
1316 collateral_user =
1317 insert(:user, %{ap_id: "https://another-awful-and-rude-instance.com/user/bully"})
1318
1319 {:ok, user} = User.block_domain(user, "*.awful-and-rude-instance.com")
1320
1321 refute User.blocks?(user, collateral_user)
1322 end
1323
1324 test "blocks domain with wildcard for subdomain" do
1325 user = insert(:user)
1326
1327 user_from_subdomain =
1328 insert(:user, %{ap_id: "https://subdomain.awful-and-rude-instance.com/user/bully"})
1329
1330 user_with_two_subdomains =
1331 insert(:user, %{
1332 ap_id: "https://subdomain.second_subdomain.awful-and-rude-instance.com/user/bully"
1333 })
1334
1335 user_domain = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1336
1337 {:ok, user} = User.block_domain(user, "*.awful-and-rude-instance.com")
1338
1339 assert User.blocks?(user, user_from_subdomain)
1340 assert User.blocks?(user, user_with_two_subdomains)
1341 assert User.blocks?(user, user_domain)
1342 end
1343
1344 test "unblocks domains" do
1345 user = insert(:user)
1346 collateral_user = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1347
1348 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1349 {:ok, user} = User.unblock_domain(user, "awful-and-rude-instance.com")
1350
1351 refute User.blocks?(user, collateral_user)
1352 end
1353
1354 test "follows take precedence over domain blocks" do
1355 user = insert(:user)
1356 good_eggo = insert(:user, %{ap_id: "https://meanies.social/user/cuteposter"})
1357
1358 {:ok, user} = User.block_domain(user, "meanies.social")
1359 {:ok, user, good_eggo} = User.follow(user, good_eggo)
1360
1361 refute User.blocks?(user, good_eggo)
1362 end
1363 end
1364
1365 describe "get_recipients_from_activity" do
1366 test "works for announces" do
1367 actor = insert(:user)
1368 user = insert(:user, local: true)
1369
1370 {:ok, activity} = CommonAPI.post(actor, %{status: "hello"})
1371 {:ok, announce} = CommonAPI.repeat(activity.id, user)
1372
1373 recipients = User.get_recipients_from_activity(announce)
1374
1375 assert user in recipients
1376 end
1377
1378 test "get recipients" do
1379 actor = insert(:user)
1380 user = insert(:user, local: true)
1381 user_two = insert(:user, local: false)
1382 addressed = insert(:user, local: true)
1383 addressed_remote = insert(:user, local: false)
1384
1385 {:ok, activity} =
1386 CommonAPI.post(actor, %{
1387 status: "hey @#{addressed.nickname} @#{addressed_remote.nickname}"
1388 })
1389
1390 assert Enum.map([actor, addressed], & &1.ap_id) --
1391 Enum.map(User.get_recipients_from_activity(activity), & &1.ap_id) == []
1392
1393 {:ok, user, actor} = User.follow(user, actor)
1394 {:ok, _user_two, _actor} = User.follow(user_two, actor)
1395 recipients = User.get_recipients_from_activity(activity)
1396 assert length(recipients) == 3
1397 assert user in recipients
1398 assert addressed in recipients
1399 end
1400
1401 test "has following" do
1402 actor = insert(:user)
1403 user = insert(:user)
1404 user_two = insert(:user)
1405 addressed = insert(:user, local: true)
1406
1407 {:ok, activity} =
1408 CommonAPI.post(actor, %{
1409 status: "hey @#{addressed.nickname}"
1410 })
1411
1412 assert Enum.map([actor, addressed], & &1.ap_id) --
1413 Enum.map(User.get_recipients_from_activity(activity), & &1.ap_id) == []
1414
1415 {:ok, _actor, _user} = User.follow(actor, user)
1416 {:ok, _actor, _user_two} = User.follow(actor, user_two)
1417 recipients = User.get_recipients_from_activity(activity)
1418 assert length(recipients) == 2
1419 assert addressed in recipients
1420 end
1421 end
1422
1423 describe ".set_activation" do
1424 test "can de-activate then re-activate a user" do
1425 user = insert(:user)
1426 assert user.is_active
1427 {:ok, user} = User.set_activation(user, false)
1428 refute user.is_active
1429 {:ok, user} = User.set_activation(user, true)
1430 assert user.is_active
1431 end
1432
1433 test "hide a user from followers" do
1434 user = insert(:user)
1435 user2 = insert(:user)
1436
1437 {:ok, user, user2} = User.follow(user, user2)
1438 {:ok, _user} = User.set_activation(user, false)
1439
1440 user2 = User.get_cached_by_id(user2.id)
1441
1442 assert user2.follower_count == 0
1443 assert [] = User.get_followers(user2)
1444 end
1445
1446 test "hide a user from friends" do
1447 user = insert(:user)
1448 user2 = insert(:user)
1449
1450 {:ok, user2, user} = User.follow(user2, user)
1451 assert user2.following_count == 1
1452 assert User.following_count(user2) == 1
1453
1454 {:ok, _user} = User.set_activation(user, false)
1455
1456 user2 = User.get_cached_by_id(user2.id)
1457
1458 assert refresh_record(user2).following_count == 0
1459 assert user2.following_count == 0
1460 assert User.following_count(user2) == 0
1461 assert [] = User.get_friends(user2)
1462 end
1463
1464 test "hide a user's statuses from timelines and notifications" do
1465 user = insert(:user)
1466 user2 = insert(:user)
1467
1468 {:ok, user2, user} = User.follow(user2, user)
1469
1470 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{user2.nickname}"})
1471
1472 activity = Repo.preload(activity, :bookmark)
1473
1474 [notification] = Pleroma.Notification.for_user(user2)
1475 assert notification.activity.id == activity.id
1476
1477 assert [activity] == ActivityPub.fetch_public_activities(%{}) |> Repo.preload(:bookmark)
1478
1479 assert [%{activity | thread_muted?: CommonAPI.thread_muted?(user2, activity)}] ==
1480 ActivityPub.fetch_activities([user2.ap_id | User.following(user2)], %{
1481 user: user2
1482 })
1483
1484 {:ok, _user} = User.set_activation(user, false)
1485
1486 assert [] == ActivityPub.fetch_public_activities(%{})
1487 assert [] == Pleroma.Notification.for_user(user2)
1488
1489 assert [] ==
1490 ActivityPub.fetch_activities([user2.ap_id | User.following(user2)], %{
1491 user: user2
1492 })
1493 end
1494 end
1495
1496 describe "approve" do
1497 test "approves a user" do
1498 user = insert(:user, is_approved: false)
1499 refute user.is_approved
1500 {:ok, user} = User.approve(user)
1501 assert user.is_approved
1502 end
1503
1504 test "approves a list of users" do
1505 unapproved_users = [
1506 insert(:user, is_approved: false),
1507 insert(:user, is_approved: false),
1508 insert(:user, is_approved: false)
1509 ]
1510
1511 {:ok, users} = User.approve(unapproved_users)
1512
1513 assert Enum.count(users) == 3
1514
1515 Enum.each(users, fn user ->
1516 assert user.is_approved
1517 end)
1518 end
1519
1520 test "it sends welcome email if it is set" do
1521 clear_config([:welcome, :email, :enabled], true)
1522 clear_config([:welcome, :email, :sender], "tester@test.me")
1523
1524 user = insert(:user, is_approved: false)
1525 welcome_user = insert(:user, email: "tester@test.me")
1526 instance_name = Pleroma.Config.get([:instance, :name])
1527
1528 User.approve(user)
1529
1530 ObanHelpers.perform_all()
1531
1532 assert_email_sent(
1533 from: {instance_name, welcome_user.email},
1534 to: {user.name, user.email},
1535 html_body: "Welcome to #{instance_name}"
1536 )
1537 end
1538
1539 test "approving an approved user does not trigger post-register actions" do
1540 clear_config([:welcome, :email, :enabled], true)
1541
1542 user = insert(:user, is_approved: true)
1543 User.approve(user)
1544
1545 ObanHelpers.perform_all()
1546
1547 assert_no_email_sent()
1548 end
1549 end
1550
1551 describe "confirm" do
1552 test "confirms a user" do
1553 user = insert(:user, is_confirmed: false)
1554 refute user.is_confirmed
1555 {:ok, user} = User.confirm(user)
1556 assert user.is_confirmed
1557 end
1558
1559 test "confirms a list of users" do
1560 unconfirmed_users = [
1561 insert(:user, is_confirmed: false),
1562 insert(:user, is_confirmed: false),
1563 insert(:user, is_confirmed: false)
1564 ]
1565
1566 {:ok, users} = User.confirm(unconfirmed_users)
1567
1568 assert Enum.count(users) == 3
1569
1570 Enum.each(users, fn user ->
1571 assert user.is_confirmed
1572 end)
1573 end
1574
1575 test "sends approval emails when `is_approved: false`" do
1576 admin = insert(:user, is_admin: true)
1577 user = insert(:user, is_confirmed: false, is_approved: false)
1578 User.confirm(user)
1579
1580 ObanHelpers.perform_all()
1581
1582 user_email = Pleroma.Emails.UserEmail.approval_pending_email(user)
1583 admin_email = Pleroma.Emails.AdminEmail.new_unapproved_registration(admin, user)
1584
1585 notify_email = Pleroma.Config.get([:instance, :notify_email])
1586 instance_name = Pleroma.Config.get([:instance, :name])
1587
1588 # User approval email
1589 assert_email_sent(
1590 from: {instance_name, notify_email},
1591 to: {user.name, user.email},
1592 html_body: user_email.html_body
1593 )
1594
1595 # Admin email
1596 assert_email_sent(
1597 from: {instance_name, notify_email},
1598 to: {admin.name, admin.email},
1599 html_body: admin_email.html_body
1600 )
1601 end
1602
1603 test "confirming a confirmed user does not trigger post-register actions" do
1604 user = insert(:user, is_confirmed: true, is_approved: false)
1605 User.confirm(user)
1606
1607 ObanHelpers.perform_all()
1608
1609 assert_no_email_sent()
1610 end
1611 end
1612
1613 describe "delete" do
1614 setup do
1615 {:ok, user} = insert(:user) |> User.set_cache()
1616
1617 [user: user]
1618 end
1619
1620 setup do: clear_config([:instance, :federating])
1621
1622 test ".delete_user_activities deletes all create activities", %{user: user} do
1623 {:ok, activity} = CommonAPI.post(user, %{status: "2hu"})
1624
1625 User.delete_user_activities(user)
1626
1627 # TODO: Test removal favorites, repeats, delete activities.
1628 refute Activity.get_by_id(activity.id)
1629 end
1630
1631 test "it deactivates a user, all follow relationships and all activities", %{user: user} do
1632 follower = insert(:user)
1633 {:ok, follower, user} = User.follow(follower, user)
1634
1635 locked_user = insert(:user, name: "locked", is_locked: true)
1636 {:ok, _, _} = User.follow(user, locked_user, :follow_pending)
1637
1638 object = insert(:note, user: user)
1639 activity = insert(:note_activity, user: user, note: object)
1640
1641 object_two = insert(:note, user: follower)
1642 activity_two = insert(:note_activity, user: follower, note: object_two)
1643
1644 {:ok, like} = CommonAPI.favorite(user, activity_two.id)
1645 {:ok, like_two} = CommonAPI.favorite(follower, activity.id)
1646 {:ok, repeat} = CommonAPI.repeat(activity_two.id, user)
1647
1648 {:ok, job} = User.delete(user)
1649 {:ok, _user} = ObanHelpers.perform(job)
1650
1651 follower = User.get_cached_by_id(follower.id)
1652
1653 refute User.following?(follower, user)
1654 assert %{is_active: false} = User.get_by_id(user.id)
1655
1656 assert [] == User.get_follow_requests(locked_user)
1657
1658 user_activities =
1659 user.ap_id
1660 |> Activity.Queries.by_actor()
1661 |> Repo.all()
1662 |> Enum.map(fn act -> act.data["type"] end)
1663
1664 assert Enum.all?(user_activities, fn act -> act in ~w(Delete Undo) end)
1665
1666 refute Activity.get_by_id(activity.id)
1667 refute Activity.get_by_id(like.id)
1668 refute Activity.get_by_id(like_two.id)
1669 refute Activity.get_by_id(repeat.id)
1670 end
1671 end
1672
1673 test "delete/1 when confirmation is pending deletes the user" do
1674 clear_config([:instance, :account_activation_required], true)
1675 user = insert(:user, is_confirmed: false)
1676
1677 {:ok, job} = User.delete(user)
1678 {:ok, _} = ObanHelpers.perform(job)
1679
1680 refute User.get_cached_by_id(user.id)
1681 refute User.get_by_id(user.id)
1682 end
1683
1684 test "delete/1 when approval is pending deletes the user" do
1685 user = insert(:user, is_approved: false)
1686
1687 {:ok, job} = User.delete(user)
1688 {:ok, _} = ObanHelpers.perform(job)
1689
1690 refute User.get_cached_by_id(user.id)
1691 refute User.get_by_id(user.id)
1692 end
1693
1694 test "delete/1 purges a user when they wouldn't be fully deleted" do
1695 user =
1696 insert(:user, %{
1697 bio: "eyy lmao",
1698 name: "qqqqqqq",
1699 password_hash: "pdfk2$1b3n159001",
1700 keys: "RSA begin buplic key",
1701 public_key: "--PRIVATE KEYE--",
1702 avatar: %{"a" => "b"},
1703 tags: ["qqqqq"],
1704 banner: %{"a" => "b"},
1705 background: %{"a" => "b"},
1706 note_count: 9,
1707 follower_count: 9,
1708 following_count: 9001,
1709 is_locked: true,
1710 is_confirmed: true,
1711 password_reset_pending: true,
1712 is_approved: true,
1713 registration_reason: "ahhhhh",
1714 confirmation_token: "qqqq",
1715 domain_blocks: ["lain.com"],
1716 is_active: false,
1717 ap_enabled: true,
1718 is_moderator: true,
1719 is_admin: true,
1720 mastofe_settings: %{"a" => "b"},
1721 mascot: %{"a" => "b"},
1722 emoji: %{"a" => "b"},
1723 pleroma_settings_store: %{"q" => "x"},
1724 fields: [%{"gg" => "qq"}],
1725 raw_fields: [%{"gg" => "qq"}],
1726 is_discoverable: true,
1727 also_known_as: ["https://lol.olo/users/loll"]
1728 })
1729
1730 {:ok, job} = User.delete(user)
1731 {:ok, _} = ObanHelpers.perform(job)
1732 user = User.get_by_id(user.id)
1733
1734 assert %User{
1735 bio: "",
1736 raw_bio: nil,
1737 email: nil,
1738 name: nil,
1739 password_hash: nil,
1740 keys: "RSA begin buplic key",
1741 public_key: "--PRIVATE KEYE--",
1742 avatar: %{},
1743 tags: [],
1744 last_refreshed_at: nil,
1745 last_digest_emailed_at: nil,
1746 banner: %{},
1747 background: %{},
1748 note_count: 0,
1749 follower_count: 0,
1750 following_count: 0,
1751 is_locked: false,
1752 is_confirmed: true,
1753 password_reset_pending: false,
1754 is_approved: true,
1755 registration_reason: nil,
1756 confirmation_token: nil,
1757 domain_blocks: [],
1758 is_active: false,
1759 ap_enabled: false,
1760 is_moderator: false,
1761 is_admin: false,
1762 mastofe_settings: nil,
1763 mascot: nil,
1764 emoji: %{},
1765 pleroma_settings_store: %{},
1766 fields: [],
1767 raw_fields: [],
1768 is_discoverable: false,
1769 also_known_as: []
1770 } = user
1771 end
1772
1773 test "delete/1 purges a remote user" do
1774 user =
1775 insert(:user, %{
1776 name: "qqqqqqq",
1777 avatar: %{"a" => "b"},
1778 banner: %{"a" => "b"},
1779 local: false
1780 })
1781
1782 {:ok, job} = User.delete(user)
1783 {:ok, _} = ObanHelpers.perform(job)
1784 user = User.get_by_id(user.id)
1785
1786 assert user.name == nil
1787 assert user.avatar == %{}
1788 assert user.banner == %{}
1789 end
1790
1791 describe "set_suggestion" do
1792 test "suggests a user" do
1793 user = insert(:user, is_suggested: false)
1794 refute user.is_suggested
1795 {:ok, user} = User.set_suggestion(user, true)
1796 assert user.is_suggested
1797 end
1798
1799 test "suggests a list of users" do
1800 unsuggested_users = [
1801 insert(:user, is_suggested: false),
1802 insert(:user, is_suggested: false),
1803 insert(:user, is_suggested: false)
1804 ]
1805
1806 {:ok, users} = User.set_suggestion(unsuggested_users, true)
1807
1808 assert Enum.count(users) == 3
1809
1810 Enum.each(users, fn user ->
1811 assert user.is_suggested
1812 end)
1813 end
1814
1815 test "unsuggests a user" do
1816 user = insert(:user, is_suggested: true)
1817 assert user.is_suggested
1818 {:ok, user} = User.set_suggestion(user, false)
1819 refute user.is_suggested
1820 end
1821 end
1822
1823 test "get_public_key_for_ap_id fetches a user that's not in the db" do
1824 assert {:ok, _key} = User.get_public_key_for_ap_id("http://mastodon.example.org/users/admin")
1825 end
1826
1827 describe "per-user rich-text filtering" do
1828 test "html_filter_policy returns default policies, when rich-text is enabled" do
1829 user = insert(:user)
1830
1831 assert Pleroma.Config.get([:markup, :scrub_policy]) == User.html_filter_policy(user)
1832 end
1833
1834 test "html_filter_policy returns TwitterText scrubber when rich-text is disabled" do
1835 user = insert(:user, no_rich_text: true)
1836
1837 assert Pleroma.HTML.Scrubber.TwitterText == User.html_filter_policy(user)
1838 end
1839 end
1840
1841 describe "caching" do
1842 test "invalidate_cache works" do
1843 user = insert(:user)
1844
1845 User.set_cache(user)
1846 User.invalidate_cache(user)
1847
1848 {:ok, nil} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1849 {:ok, nil} = Cachex.get(:user_cache, "nickname:#{user.nickname}")
1850 end
1851
1852 test "User.delete() plugs any possible zombie objects" do
1853 user = insert(:user)
1854
1855 {:ok, job} = User.delete(user)
1856 {:ok, _} = ObanHelpers.perform(job)
1857
1858 {:ok, cached_user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1859
1860 assert cached_user != user
1861
1862 {:ok, cached_user} = Cachex.get(:user_cache, "nickname:#{user.ap_id}")
1863
1864 assert cached_user != user
1865 end
1866 end
1867
1868 describe "account_status/1" do
1869 setup do: clear_config([:instance, :account_activation_required])
1870
1871 test "return confirmation_pending for unconfirm user" do
1872 clear_config([:instance, :account_activation_required], true)
1873 user = insert(:user, is_confirmed: false)
1874 assert User.account_status(user) == :confirmation_pending
1875 end
1876
1877 test "return active for confirmed user" do
1878 clear_config([:instance, :account_activation_required], true)
1879 user = insert(:user, is_confirmed: true)
1880 assert User.account_status(user) == :active
1881 end
1882
1883 test "return active for remote user" do
1884 user = insert(:user, local: false)
1885 assert User.account_status(user) == :active
1886 end
1887
1888 test "returns :password_reset_pending for user with reset password" do
1889 user = insert(:user, password_reset_pending: true)
1890 assert User.account_status(user) == :password_reset_pending
1891 end
1892
1893 test "returns :deactivated for deactivated user" do
1894 user = insert(:user, local: true, is_confirmed: true, is_active: false)
1895 assert User.account_status(user) == :deactivated
1896 end
1897
1898 test "returns :approval_pending for unapproved user" do
1899 user = insert(:user, local: true, is_approved: false)
1900 assert User.account_status(user) == :approval_pending
1901
1902 user = insert(:user, local: true, is_confirmed: false, is_approved: false)
1903 assert User.account_status(user) == :approval_pending
1904 end
1905 end
1906
1907 describe "superuser?/1" do
1908 test "returns false for unprivileged users" do
1909 user = insert(:user, local: true)
1910
1911 refute User.superuser?(user)
1912 end
1913
1914 test "returns false for remote users" do
1915 user = insert(:user, local: false)
1916 remote_admin_user = insert(:user, local: false, is_admin: true)
1917
1918 refute User.superuser?(user)
1919 refute User.superuser?(remote_admin_user)
1920 end
1921
1922 test "returns true for local moderators" do
1923 user = insert(:user, local: true, is_moderator: true)
1924
1925 assert User.superuser?(user)
1926 end
1927
1928 test "returns true for local admins" do
1929 user = insert(:user, local: true, is_admin: true)
1930
1931 assert User.superuser?(user)
1932 end
1933 end
1934
1935 describe "invisible?/1" do
1936 test "returns true for an invisible user" do
1937 user = insert(:user, local: true, invisible: true)
1938
1939 assert User.invisible?(user)
1940 end
1941
1942 test "returns false for a non-invisible user" do
1943 user = insert(:user, local: true)
1944
1945 refute User.invisible?(user)
1946 end
1947 end
1948
1949 describe "visible_for/2" do
1950 test "returns true when the account is itself" do
1951 user = insert(:user, local: true)
1952
1953 assert User.visible_for(user, user) == :visible
1954 end
1955
1956 test "returns false when the account is unconfirmed and confirmation is required" do
1957 clear_config([:instance, :account_activation_required], true)
1958
1959 user = insert(:user, local: true, is_confirmed: false)
1960 other_user = insert(:user, local: true)
1961
1962 refute User.visible_for(user, other_user) == :visible
1963 end
1964
1965 test "returns true when the account is unconfirmed and confirmation is required but the account is remote" do
1966 clear_config([:instance, :account_activation_required], true)
1967
1968 user = insert(:user, local: false, is_confirmed: false)
1969 other_user = insert(:user, local: true)
1970
1971 assert User.visible_for(user, other_user) == :visible
1972 end
1973
1974 test "returns true when the account is unconfirmed and being viewed by a privileged account (confirmation required)" do
1975 clear_config([:instance, :account_activation_required], true)
1976
1977 user = insert(:user, local: true, is_confirmed: false)
1978 other_user = insert(:user, local: true, is_admin: true)
1979
1980 assert User.visible_for(user, other_user) == :visible
1981 end
1982 end
1983
1984 describe "parse_bio/2" do
1985 test "preserves hosts in user links text" do
1986 remote_user = insert(:user, local: false, nickname: "nick@domain.com")
1987 user = insert(:user)
1988 bio = "A.k.a. @nick@domain.com"
1989
1990 expected_text =
1991 ~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>)
1992
1993 assert expected_text == User.parse_bio(bio, user)
1994 end
1995
1996 test "Adds rel=me on linkbacked urls" do
1997 user = insert(:user, ap_id: "https://social.example.org/users/lain")
1998
1999 bio = "http://example.com/rel_me/null"
2000 expected_text = "<a href=\"#{bio}\">#{bio}</a>"
2001 assert expected_text == User.parse_bio(bio, user)
2002
2003 bio = "http://example.com/rel_me/link"
2004 expected_text = "<a href=\"#{bio}\" rel=\"me\">#{bio}</a>"
2005 assert expected_text == User.parse_bio(bio, user)
2006
2007 bio = "http://example.com/rel_me/anchor"
2008 expected_text = "<a href=\"#{bio}\" rel=\"me\">#{bio}</a>"
2009 assert expected_text == User.parse_bio(bio, user)
2010 end
2011 end
2012
2013 test "follower count is updated when a follower is blocked" do
2014 user = insert(:user)
2015 follower = insert(:user)
2016 follower2 = insert(:user)
2017 follower3 = insert(:user)
2018
2019 {:ok, follower, user} = User.follow(follower, user)
2020 {:ok, _follower2, _user} = User.follow(follower2, user)
2021 {:ok, _follower3, _user} = User.follow(follower3, user)
2022
2023 {:ok, _user_relationship} = User.block(user, follower)
2024 user = refresh_record(user)
2025
2026 assert user.follower_count == 2
2027 end
2028
2029 describe "list_inactive_users_query/1" do
2030 defp days_ago(days) do
2031 NaiveDateTime.add(
2032 NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second),
2033 -days * 60 * 60 * 24,
2034 :second
2035 )
2036 end
2037
2038 test "Users are inactive by default" do
2039 total = 10
2040
2041 users =
2042 Enum.map(1..total, fn _ ->
2043 insert(:user, last_digest_emailed_at: days_ago(20), is_active: true)
2044 end)
2045
2046 inactive_users_ids =
2047 Pleroma.User.list_inactive_users_query()
2048 |> Pleroma.Repo.all()
2049 |> Enum.map(& &1.id)
2050
2051 Enum.each(users, fn user ->
2052 assert user.id in inactive_users_ids
2053 end)
2054 end
2055
2056 test "Only includes users who has no recent activity" do
2057 total = 10
2058
2059 users =
2060 Enum.map(1..total, fn _ ->
2061 insert(:user, last_digest_emailed_at: days_ago(20), is_active: true)
2062 end)
2063
2064 {inactive, active} = Enum.split(users, trunc(total / 2))
2065
2066 Enum.map(active, fn user ->
2067 to = Enum.random(users -- [user])
2068
2069 {:ok, _} =
2070 CommonAPI.post(user, %{
2071 status: "hey @#{to.nickname}"
2072 })
2073 end)
2074
2075 inactive_users_ids =
2076 Pleroma.User.list_inactive_users_query()
2077 |> Pleroma.Repo.all()
2078 |> Enum.map(& &1.id)
2079
2080 Enum.each(active, fn user ->
2081 refute user.id in inactive_users_ids
2082 end)
2083
2084 Enum.each(inactive, fn user ->
2085 assert user.id in inactive_users_ids
2086 end)
2087 end
2088
2089 test "Only includes users with no read notifications" do
2090 total = 10
2091
2092 users =
2093 Enum.map(1..total, fn _ ->
2094 insert(:user, last_digest_emailed_at: days_ago(20), is_active: true)
2095 end)
2096
2097 [sender | recipients] = users
2098 {inactive, active} = Enum.split(recipients, trunc(total / 2))
2099
2100 Enum.each(recipients, fn to ->
2101 {:ok, _} =
2102 CommonAPI.post(sender, %{
2103 status: "hey @#{to.nickname}"
2104 })
2105
2106 {:ok, _} =
2107 CommonAPI.post(sender, %{
2108 status: "hey again @#{to.nickname}"
2109 })
2110 end)
2111
2112 Enum.each(active, fn user ->
2113 [n1, _n2] = Pleroma.Notification.for_user(user)
2114 {:ok, _} = Pleroma.Notification.read_one(user, n1.id)
2115 end)
2116
2117 inactive_users_ids =
2118 Pleroma.User.list_inactive_users_query()
2119 |> Pleroma.Repo.all()
2120 |> Enum.map(& &1.id)
2121
2122 Enum.each(active, fn user ->
2123 refute user.id in inactive_users_ids
2124 end)
2125
2126 Enum.each(inactive, fn user ->
2127 assert user.id in inactive_users_ids
2128 end)
2129 end
2130 end
2131
2132 describe "ensure_keys_present" do
2133 test "it creates keys for a user and stores them in info" do
2134 user = insert(:user)
2135 refute is_binary(user.keys)
2136 {:ok, user} = User.ensure_keys_present(user)
2137 assert is_binary(user.keys)
2138 end
2139
2140 test "it doesn't create keys if there already are some" do
2141 user = insert(:user, keys: "xxx")
2142 {:ok, user} = User.ensure_keys_present(user)
2143 assert user.keys == "xxx"
2144 end
2145 end
2146
2147 describe "get_ap_ids_by_nicknames" do
2148 test "it returns a list of AP ids for a given set of nicknames" do
2149 user = insert(:user)
2150 user_two = insert(:user)
2151
2152 ap_ids = User.get_ap_ids_by_nicknames([user.nickname, user_two.nickname, "nonexistent"])
2153 assert length(ap_ids) == 2
2154 assert user.ap_id in ap_ids
2155 assert user_two.ap_id in ap_ids
2156 end
2157 end
2158
2159 describe "sync followers count" do
2160 setup do
2161 user1 = insert(:user, local: false, ap_id: "http://localhost:4001/users/masto_closed")
2162 user2 = insert(:user, local: false, ap_id: "http://localhost:4001/users/fuser2")
2163 insert(:user, local: true)
2164 insert(:user, local: false, is_active: false)
2165 {:ok, user1: user1, user2: user2}
2166 end
2167
2168 test "external_users/1 external active users with limit", %{user1: user1, user2: user2} do
2169 [fdb_user1] = User.external_users(limit: 1)
2170
2171 assert fdb_user1.ap_id
2172 assert fdb_user1.ap_id == user1.ap_id
2173 assert fdb_user1.id == user1.id
2174
2175 [fdb_user2] = User.external_users(max_id: fdb_user1.id, limit: 1)
2176
2177 assert fdb_user2.ap_id
2178 assert fdb_user2.ap_id == user2.ap_id
2179 assert fdb_user2.id == user2.id
2180
2181 assert User.external_users(max_id: fdb_user2.id, limit: 1) == []
2182 end
2183 end
2184
2185 describe "is_internal_user?/1" do
2186 test "non-internal user returns false" do
2187 user = insert(:user)
2188 refute User.is_internal_user?(user)
2189 end
2190
2191 test "user with no nickname returns true" do
2192 user = insert(:user, %{nickname: nil})
2193 assert User.is_internal_user?(user)
2194 end
2195
2196 test "user with internal-prefixed nickname returns true" do
2197 user = insert(:user, %{nickname: "internal.test"})
2198 assert User.is_internal_user?(user)
2199 end
2200 end
2201
2202 describe "update_and_set_cache/1" do
2203 test "returns error when user is stale instead Ecto.StaleEntryError" do
2204 user = insert(:user)
2205
2206 changeset = Ecto.Changeset.change(user, bio: "test")
2207
2208 Repo.delete(user)
2209
2210 assert {:error, %Ecto.Changeset{errors: [id: {"is stale", [stale: true]}], valid?: false}} =
2211 User.update_and_set_cache(changeset)
2212 end
2213
2214 test "performs update cache if user updated" do
2215 user = insert(:user)
2216 assert {:ok, nil} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
2217
2218 changeset = Ecto.Changeset.change(user, bio: "test-bio")
2219
2220 assert {:ok, %User{bio: "test-bio"} = user} = User.update_and_set_cache(changeset)
2221 assert {:ok, user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
2222 assert %User{bio: "test-bio"} = User.get_cached_by_ap_id(user.ap_id)
2223 end
2224
2225 test "removes report notifs when user isn't superuser any more" do
2226 report_activity = insert(:report_activity)
2227 user = insert(:user, is_moderator: true, is_admin: true)
2228 {:ok, _} = Notification.create_notifications(report_activity)
2229
2230 assert [%Pleroma.Notification{type: "pleroma:report"}] = Notification.for_user(user)
2231
2232 {:ok, user} = user |> User.admin_api_update(%{is_moderator: false})
2233 # is still superuser because still admin
2234 assert [%Pleroma.Notification{type: "pleroma:report"}] = Notification.for_user(user)
2235
2236 {:ok, user} = user |> User.admin_api_update(%{is_moderator: true, is_admin: false})
2237 # is still superuser because still moderator
2238 assert [%Pleroma.Notification{type: "pleroma:report"}] = Notification.for_user(user)
2239
2240 {:ok, user} = user |> User.admin_api_update(%{is_moderator: false})
2241 # is not a superuser any more
2242 assert [] = Notification.for_user(user)
2243 end
2244 end
2245
2246 describe "following/followers synchronization" do
2247 setup do: clear_config([:instance, :external_user_synchronization])
2248
2249 test "updates the counters normally on following/getting a follow when disabled" do
2250 clear_config([:instance, :external_user_synchronization], false)
2251 user = insert(:user)
2252
2253 other_user =
2254 insert(:user,
2255 local: false,
2256 follower_address: "http://localhost:4001/users/masto_closed/followers",
2257 following_address: "http://localhost:4001/users/masto_closed/following",
2258 ap_enabled: true
2259 )
2260
2261 assert other_user.following_count == 0
2262 assert other_user.follower_count == 0
2263
2264 {:ok, user, other_user} = Pleroma.User.follow(user, other_user)
2265
2266 assert user.following_count == 1
2267 assert other_user.follower_count == 1
2268 end
2269
2270 test "syncronizes the counters with the remote instance for the followed when enabled" do
2271 clear_config([:instance, :external_user_synchronization], false)
2272
2273 user = insert(:user)
2274
2275 other_user =
2276 insert(:user,
2277 local: false,
2278 follower_address: "http://localhost:4001/users/masto_closed/followers",
2279 following_address: "http://localhost:4001/users/masto_closed/following",
2280 ap_enabled: true
2281 )
2282
2283 assert other_user.following_count == 0
2284 assert other_user.follower_count == 0
2285
2286 clear_config([:instance, :external_user_synchronization], true)
2287 {:ok, _user, other_user} = User.follow(user, other_user)
2288
2289 assert other_user.follower_count == 437
2290 end
2291
2292 test "syncronizes the counters with the remote instance for the follower when enabled" do
2293 clear_config([:instance, :external_user_synchronization], false)
2294
2295 user = insert(:user)
2296
2297 other_user =
2298 insert(:user,
2299 local: false,
2300 follower_address: "http://localhost:4001/users/masto_closed/followers",
2301 following_address: "http://localhost:4001/users/masto_closed/following",
2302 ap_enabled: true
2303 )
2304
2305 assert other_user.following_count == 0
2306 assert other_user.follower_count == 0
2307
2308 clear_config([:instance, :external_user_synchronization], true)
2309 {:ok, other_user, _user} = User.follow(other_user, user)
2310
2311 assert other_user.following_count == 152
2312 end
2313 end
2314
2315 describe "change_email/2" do
2316 setup do
2317 [user: insert(:user)]
2318 end
2319
2320 test "blank email returns error if we require an email on registration", %{user: user} do
2321 orig_account_activation_required =
2322 Pleroma.Config.get([:instance, :account_activation_required])
2323
2324 Pleroma.Config.put([:instance, :account_activation_required], true)
2325
2326 on_exit(fn ->
2327 Pleroma.Config.put(
2328 [:instance, :account_activation_required],
2329 orig_account_activation_required
2330 )
2331 end)
2332
2333 assert {:error, %{errors: [email: {"can't be blank", _}]}} = User.change_email(user, "")
2334 assert {:error, %{errors: [email: {"can't be blank", _}]}} = User.change_email(user, nil)
2335 end
2336
2337 test "blank email should be fine if we do not require an email on registration", %{user: user} do
2338 orig_account_activation_required =
2339 Pleroma.Config.get([:instance, :account_activation_required])
2340
2341 Pleroma.Config.put([:instance, :account_activation_required], false)
2342
2343 on_exit(fn ->
2344 Pleroma.Config.put(
2345 [:instance, :account_activation_required],
2346 orig_account_activation_required
2347 )
2348 end)
2349
2350 assert {:ok, %User{email: nil}} = User.change_email(user, "")
2351 assert {:ok, %User{email: nil}} = User.change_email(user, nil)
2352 end
2353
2354 test "non unique email returns error", %{user: user} do
2355 %{email: email} = insert(:user)
2356
2357 assert {:error, %{errors: [email: {"has already been taken", _}]}} =
2358 User.change_email(user, email)
2359 end
2360
2361 test "invalid email returns error", %{user: user} do
2362 assert {:error, %{errors: [email: {"has invalid format", _}]}} =
2363 User.change_email(user, "cofe")
2364 end
2365
2366 test "changes email", %{user: user} do
2367 assert {:ok, %User{email: "cofe@cofe.party"}} = User.change_email(user, "cofe@cofe.party")
2368 end
2369
2370 test "adds email", %{user: user} do
2371 orig_account_activation_required =
2372 Pleroma.Config.get([:instance, :account_activation_required])
2373
2374 Pleroma.Config.put([:instance, :account_activation_required], false)
2375
2376 on_exit(fn ->
2377 Pleroma.Config.put(
2378 [:instance, :account_activation_required],
2379 orig_account_activation_required
2380 )
2381 end)
2382
2383 assert {:ok, _} = User.change_email(user, "")
2384 Pleroma.Config.put([:instance, :account_activation_required], true)
2385
2386 assert {:ok, %User{email: "cofe2@cofe.party"}} = User.change_email(user, "cofe2@cofe.party")
2387 end
2388 end
2389
2390 describe "get_cached_by_nickname_or_id" do
2391 setup do
2392 local_user = insert(:user)
2393 remote_user = insert(:user, nickname: "nickname@example.com", local: false)
2394
2395 [local_user: local_user, remote_user: remote_user]
2396 end
2397
2398 setup do: clear_config([:instance, :limit_to_local_content])
2399
2400 test "allows getting remote users by id no matter what :limit_to_local_content is set to", %{
2401 remote_user: remote_user
2402 } do
2403 clear_config([:instance, :limit_to_local_content], false)
2404 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2405
2406 clear_config([:instance, :limit_to_local_content], true)
2407 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2408
2409 clear_config([:instance, :limit_to_local_content], :unauthenticated)
2410 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2411 end
2412
2413 test "disallows getting remote users by nickname without authentication when :limit_to_local_content is set to :unauthenticated",
2414 %{remote_user: remote_user} do
2415 clear_config([:instance, :limit_to_local_content], :unauthenticated)
2416 assert nil == User.get_cached_by_nickname_or_id(remote_user.nickname)
2417 end
2418
2419 test "allows getting remote users by nickname with authentication when :limit_to_local_content is set to :unauthenticated",
2420 %{remote_user: remote_user, local_user: local_user} do
2421 clear_config([:instance, :limit_to_local_content], :unauthenticated)
2422 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.nickname, for: local_user)
2423 end
2424
2425 test "disallows getting remote users by nickname when :limit_to_local_content is set to true",
2426 %{remote_user: remote_user} do
2427 clear_config([:instance, :limit_to_local_content], true)
2428 assert nil == User.get_cached_by_nickname_or_id(remote_user.nickname)
2429 end
2430
2431 test "allows getting local users by nickname no matter what :limit_to_local_content is set to",
2432 %{local_user: local_user} do
2433 clear_config([:instance, :limit_to_local_content], false)
2434 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2435
2436 clear_config([:instance, :limit_to_local_content], true)
2437 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2438
2439 clear_config([:instance, :limit_to_local_content], :unauthenticated)
2440 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2441 end
2442 end
2443
2444 describe "update_email_notifications/2" do
2445 setup do
2446 user = insert(:user, email_notifications: %{"digest" => true})
2447
2448 {:ok, user: user}
2449 end
2450
2451 test "Notifications are updated", %{user: user} do
2452 true = user.email_notifications["digest"]
2453 assert {:ok, result} = User.update_email_notifications(user, %{"digest" => false})
2454 assert result.email_notifications["digest"] == false
2455 end
2456 end
2457
2458 describe "local_nickname/1" do
2459 test "returns nickname without host" do
2460 assert User.local_nickname("@mentioned") == "mentioned"
2461 assert User.local_nickname("a_local_nickname") == "a_local_nickname"
2462 assert User.local_nickname("nickname@host.com") == "nickname"
2463 end
2464 end
2465
2466 describe "full_nickname/1" do
2467 test "returns fully qualified nickname for local and remote users" do
2468 local_user =
2469 insert(:user, nickname: "local_user", ap_id: "https://somehost.com/users/local_user")
2470
2471 remote_user = insert(:user, nickname: "remote@host.com", local: false)
2472
2473 assert User.full_nickname(local_user) == "local_user@somehost.com"
2474 assert User.full_nickname(remote_user) == "remote@host.com"
2475 end
2476
2477 test "strips leading @ from mentions" do
2478 assert User.full_nickname("@mentioned") == "mentioned"
2479 assert User.full_nickname("@nickname@host.com") == "nickname@host.com"
2480 end
2481
2482 test "does not modify nicknames" do
2483 assert User.full_nickname("nickname") == "nickname"
2484 assert User.full_nickname("nickname@host.com") == "nickname@host.com"
2485 end
2486 end
2487
2488 test "avatar fallback" do
2489 user = insert(:user)
2490 assert User.avatar_url(user) =~ "/images/avi.png"
2491
2492 clear_config([:assets, :default_user_avatar], "avatar.png")
2493
2494 user = User.get_cached_by_nickname_or_id(user.nickname)
2495 assert User.avatar_url(user) =~ "avatar.png"
2496
2497 assert User.avatar_url(user, no_default: true) == nil
2498 end
2499
2500 test "get_host/1" do
2501 user = insert(:user, ap_id: "https://lain.com/users/lain", nickname: "lain")
2502 assert User.get_host(user) == "lain.com"
2503 end
2504
2505 test "update_last_active_at/1" do
2506 user = insert(:user)
2507 assert is_nil(user.last_active_at)
2508
2509 test_started_at = NaiveDateTime.utc_now() |> NaiveDateTime.truncate(:second)
2510
2511 assert {:ok, user} = User.update_last_active_at(user)
2512
2513 assert user.last_active_at >= test_started_at
2514 assert user.last_active_at <= NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second)
2515
2516 last_active_at =
2517 NaiveDateTime.utc_now()
2518 |> NaiveDateTime.add(-:timer.hours(24), :millisecond)
2519 |> NaiveDateTime.truncate(:second)
2520
2521 assert {:ok, user} =
2522 user
2523 |> cast(%{last_active_at: last_active_at}, [:last_active_at])
2524 |> User.update_and_set_cache()
2525
2526 assert user.last_active_at == last_active_at
2527 assert {:ok, user} = User.update_last_active_at(user)
2528 assert user.last_active_at >= test_started_at
2529 assert user.last_active_at <= NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second)
2530 end
2531
2532 test "active_user_count/1" do
2533 insert(:user)
2534 insert(:user, %{local: false})
2535 insert(:user, %{last_active_at: NaiveDateTime.utc_now()})
2536 insert(:user, %{last_active_at: Timex.shift(NaiveDateTime.utc_now(), days: -15)})
2537 insert(:user, %{last_active_at: Timex.shift(NaiveDateTime.utc_now(), weeks: -6)})
2538 insert(:user, %{last_active_at: Timex.shift(NaiveDateTime.utc_now(), months: -7)})
2539 insert(:user, %{last_active_at: Timex.shift(NaiveDateTime.utc_now(), years: -2)})
2540
2541 assert User.active_user_count() == 2
2542 assert User.active_user_count(180) == 3
2543 assert User.active_user_count(365) == 4
2544 assert User.active_user_count(1000) == 5
2545 end
2546
2547 describe "pins" do
2548 setup do
2549 user = insert(:user)
2550
2551 [user: user, object_id: object_id_from_created_activity(user)]
2552 end
2553
2554 test "unique pins", %{user: user, object_id: object_id} do
2555 assert {:ok, %{pinned_objects: %{^object_id => pinned_at1} = pins} = updated_user} =
2556 User.add_pinned_object_id(user, object_id)
2557
2558 assert Enum.count(pins) == 1
2559
2560 assert {:ok, %{pinned_objects: %{^object_id => pinned_at2} = pins}} =
2561 User.add_pinned_object_id(updated_user, object_id)
2562
2563 assert pinned_at1 == pinned_at2
2564
2565 assert Enum.count(pins) == 1
2566 end
2567
2568 test "respects max_pinned_statuses limit", %{user: user, object_id: object_id} do
2569 clear_config([:instance, :max_pinned_statuses], 1)
2570 {:ok, updated} = User.add_pinned_object_id(user, object_id)
2571
2572 object_id2 = object_id_from_created_activity(user)
2573
2574 {:error, %{errors: errors}} = User.add_pinned_object_id(updated, object_id2)
2575 assert Keyword.has_key?(errors, :pinned_objects)
2576 end
2577
2578 test "remove_pinned_object_id/2", %{user: user, object_id: object_id} do
2579 assert {:ok, updated} = User.add_pinned_object_id(user, object_id)
2580
2581 {:ok, after_remove} = User.remove_pinned_object_id(updated, object_id)
2582 assert after_remove.pinned_objects == %{}
2583 end
2584 end
2585
2586 defp object_id_from_created_activity(user) do
2587 %{id: id} = insert(:note_activity, user: user)
2588 %{object: %{data: %{"id" => object_id}}} = Activity.get_by_id_with_object(id)
2589 object_id
2590 end
2591
2592 describe "add_alias/2" do
2593 test "should add alias for another user" do
2594 user = insert(:user)
2595 user2 = insert(:user)
2596
2597 assert {:ok, user_updated} = user |> User.add_alias(user2)
2598
2599 assert user_updated.also_known_as |> length() == 1
2600 assert user2.ap_id in user_updated.also_known_as
2601 end
2602
2603 test "should add multiple aliases" do
2604 user = insert(:user)
2605 user2 = insert(:user)
2606 user3 = insert(:user)
2607
2608 assert {:ok, user} = user |> User.add_alias(user2)
2609 assert {:ok, user_updated} = user |> User.add_alias(user3)
2610
2611 assert user_updated.also_known_as |> length() == 2
2612 assert user2.ap_id in user_updated.also_known_as
2613 assert user3.ap_id in user_updated.also_known_as
2614 end
2615
2616 test "should not add duplicate aliases" do
2617 user = insert(:user)
2618 user2 = insert(:user)
2619
2620 assert {:ok, user} = user |> User.add_alias(user2)
2621
2622 assert {:ok, user_updated} = user |> User.add_alias(user2)
2623
2624 assert user_updated.also_known_as |> length() == 1
2625 assert user2.ap_id in user_updated.also_known_as
2626 end
2627 end
2628
2629 describe "alias_users/1" do
2630 test "should get aliases for a user" do
2631 user = insert(:user)
2632 user2 = insert(:user, also_known_as: [user.ap_id])
2633
2634 aliases = user2 |> User.alias_users()
2635
2636 assert aliases |> length() == 1
2637
2638 alias_user = aliases |> Enum.at(0)
2639
2640 assert alias_user.ap_id == user.ap_id
2641 end
2642 end
2643
2644 describe "delete_alias/2" do
2645 test "should delete existing alias" do
2646 user = insert(:user)
2647 user2 = insert(:user, also_known_as: [user.ap_id])
2648
2649 assert {:ok, user_updated} = user2 |> User.delete_alias(user)
2650
2651 assert user_updated.also_known_as == []
2652 end
2653
2654 test "should report error on non-existing alias" do
2655 user = insert(:user)
2656 user2 = insert(:user)
2657 user3 = insert(:user, also_known_as: [user.ap_id])
2658
2659 assert {:error, :no_such_alias} = user3 |> User.delete_alias(user2)
2660
2661 user3_updated = User.get_cached_by_ap_id(user3.ap_id)
2662
2663 assert user3_updated.also_known_as |> length() == 1
2664 assert user.ap_id in user3_updated.also_known_as
2665 end
2666 end
2667 end