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