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