generate-keys-at-registration-time (#181)
[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 and PEM key" do
624 changeset = User.register_changeset(%User{}, @full_user_data)
625
626 assert changeset.valid?
627
628 assert is_binary(changeset.changes[:password_hash])
629 assert changeset.changes[:ap_id] == User.ap_id(%User{nickname: @full_user_data.nickname})
630 assert is_binary(changeset.changes[:keys])
631
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 "ensure_keys_present" do
2134 test "it creates keys for a user and stores them in info" do
2135 user = insert(:user)
2136 refute is_binary(user.keys)
2137 {:ok, user} = User.ensure_keys_present(user)
2138 assert is_binary(user.keys)
2139 end
2140
2141 test "it doesn't create keys if there already are some" do
2142 user = insert(:user, keys: "xxx")
2143 {:ok, user} = User.ensure_keys_present(user)
2144 assert user.keys == "xxx"
2145 end
2146 end
2147
2148 describe "get_ap_ids_by_nicknames" do
2149 test "it returns a list of AP ids for a given set of nicknames" do
2150 user = insert(:user)
2151 user_two = insert(:user)
2152
2153 ap_ids = User.get_ap_ids_by_nicknames([user.nickname, user_two.nickname, "nonexistent"])
2154 assert length(ap_ids) == 2
2155 assert user.ap_id in ap_ids
2156 assert user_two.ap_id in ap_ids
2157 end
2158 end
2159
2160 describe "sync followers count" do
2161 setup do
2162 user1 = insert(:user, local: false, ap_id: "http://localhost:4001/users/masto_closed")
2163 user2 = insert(:user, local: false, ap_id: "http://localhost:4001/users/fuser2")
2164 insert(:user, local: true)
2165 insert(:user, local: false, is_active: false)
2166 {:ok, user1: user1, user2: user2}
2167 end
2168
2169 test "external_users/1 external active users with limit", %{user1: user1, user2: user2} do
2170 [fdb_user1] = User.external_users(limit: 1)
2171
2172 assert fdb_user1.ap_id
2173 assert fdb_user1.ap_id == user1.ap_id
2174 assert fdb_user1.id == user1.id
2175
2176 [fdb_user2] = User.external_users(max_id: fdb_user1.id, limit: 1)
2177
2178 assert fdb_user2.ap_id
2179 assert fdb_user2.ap_id == user2.ap_id
2180 assert fdb_user2.id == user2.id
2181
2182 assert User.external_users(max_id: fdb_user2.id, limit: 1) == []
2183 end
2184 end
2185
2186 describe "is_internal_user?/1" do
2187 test "non-internal user returns false" do
2188 user = insert(:user)
2189 refute User.is_internal_user?(user)
2190 end
2191
2192 test "user with no nickname returns true" do
2193 user = insert(:user, %{nickname: nil})
2194 assert User.is_internal_user?(user)
2195 end
2196
2197 test "user with internal-prefixed nickname returns true" do
2198 user = insert(:user, %{nickname: "internal.test"})
2199 assert User.is_internal_user?(user)
2200 end
2201 end
2202
2203 describe "update_and_set_cache/1" do
2204 test "returns error when user is stale instead Ecto.StaleEntryError" do
2205 user = insert(:user)
2206
2207 changeset = Ecto.Changeset.change(user, bio: "test")
2208
2209 Repo.delete(user)
2210
2211 assert {:error, %Ecto.Changeset{errors: [id: {"is stale", [stale: true]}], valid?: false}} =
2212 User.update_and_set_cache(changeset)
2213 end
2214
2215 test "performs update cache if user updated" do
2216 user = insert(:user)
2217 assert {:ok, nil} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
2218
2219 changeset = Ecto.Changeset.change(user, bio: "test-bio")
2220
2221 assert {:ok, %User{bio: "test-bio"} = user} = User.update_and_set_cache(changeset)
2222 assert {:ok, user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
2223 assert %User{bio: "test-bio"} = User.get_cached_by_ap_id(user.ap_id)
2224 end
2225
2226 test "removes report notifs when user isn't superuser any more" do
2227 report_activity = insert(:report_activity)
2228 user = insert(:user, is_moderator: true, is_admin: true)
2229 {:ok, _} = Notification.create_notifications(report_activity)
2230
2231 assert [%Pleroma.Notification{type: "pleroma:report"}] = Notification.for_user(user)
2232
2233 {:ok, user} = user |> User.admin_api_update(%{is_moderator: false})
2234 # is still superuser because still admin
2235 assert [%Pleroma.Notification{type: "pleroma:report"}] = Notification.for_user(user)
2236
2237 {:ok, user} = user |> User.admin_api_update(%{is_moderator: true, is_admin: false})
2238 # is still superuser because still moderator
2239 assert [%Pleroma.Notification{type: "pleroma:report"}] = Notification.for_user(user)
2240
2241 {:ok, user} = user |> User.admin_api_update(%{is_moderator: false})
2242 # is not a superuser any more
2243 assert [] = Notification.for_user(user)
2244 end
2245 end
2246
2247 describe "following/followers synchronization" do
2248 setup do: clear_config([:instance, :external_user_synchronization])
2249
2250 test "updates the counters normally on following/getting a follow when disabled" do
2251 clear_config([:instance, :external_user_synchronization], false)
2252 user = insert(:user)
2253
2254 other_user =
2255 insert(:user,
2256 local: false,
2257 follower_address: "http://localhost:4001/users/masto_closed/followers",
2258 following_address: "http://localhost:4001/users/masto_closed/following",
2259 ap_enabled: true
2260 )
2261
2262 assert other_user.following_count == 0
2263 assert other_user.follower_count == 0
2264
2265 {:ok, user, other_user} = Pleroma.User.follow(user, other_user)
2266
2267 assert user.following_count == 1
2268 assert other_user.follower_count == 1
2269 end
2270
2271 test "syncronizes the counters with the remote instance for the followed when enabled" do
2272 clear_config([:instance, :external_user_synchronization], false)
2273
2274 user = insert(:user)
2275
2276 other_user =
2277 insert(:user,
2278 local: false,
2279 follower_address: "http://localhost:4001/users/masto_closed/followers",
2280 following_address: "http://localhost:4001/users/masto_closed/following",
2281 ap_enabled: true
2282 )
2283
2284 assert other_user.following_count == 0
2285 assert other_user.follower_count == 0
2286
2287 clear_config([:instance, :external_user_synchronization], true)
2288 {:ok, _user, other_user} = User.follow(user, other_user)
2289
2290 assert other_user.follower_count == 437
2291 end
2292
2293 test "syncronizes the counters with the remote instance for the follower when enabled" do
2294 clear_config([:instance, :external_user_synchronization], false)
2295
2296 user = insert(:user)
2297
2298 other_user =
2299 insert(:user,
2300 local: false,
2301 follower_address: "http://localhost:4001/users/masto_closed/followers",
2302 following_address: "http://localhost:4001/users/masto_closed/following",
2303 ap_enabled: true
2304 )
2305
2306 assert other_user.following_count == 0
2307 assert other_user.follower_count == 0
2308
2309 clear_config([:instance, :external_user_synchronization], true)
2310 {:ok, other_user, _user} = User.follow(other_user, user)
2311
2312 assert other_user.following_count == 152
2313 end
2314 end
2315
2316 describe "change_email/2" do
2317 setup do
2318 [user: insert(:user)]
2319 end
2320
2321 test "blank email returns error if we require an email on registration", %{user: user} do
2322 orig_account_activation_required =
2323 Pleroma.Config.get([:instance, :account_activation_required])
2324
2325 Pleroma.Config.put([:instance, :account_activation_required], true)
2326
2327 on_exit(fn ->
2328 Pleroma.Config.put(
2329 [:instance, :account_activation_required],
2330 orig_account_activation_required
2331 )
2332 end)
2333
2334 assert {:error, %{errors: [email: {"can't be blank", _}]}} = User.change_email(user, "")
2335 assert {:error, %{errors: [email: {"can't be blank", _}]}} = User.change_email(user, nil)
2336 end
2337
2338 test "blank email should be fine if we do not require an email on registration", %{user: user} do
2339 orig_account_activation_required =
2340 Pleroma.Config.get([:instance, :account_activation_required])
2341
2342 Pleroma.Config.put([:instance, :account_activation_required], false)
2343
2344 on_exit(fn ->
2345 Pleroma.Config.put(
2346 [:instance, :account_activation_required],
2347 orig_account_activation_required
2348 )
2349 end)
2350
2351 assert {:ok, %User{email: nil}} = User.change_email(user, "")
2352 assert {:ok, %User{email: nil}} = User.change_email(user, nil)
2353 end
2354
2355 test "non unique email returns error", %{user: user} do
2356 %{email: email} = insert(:user)
2357
2358 assert {:error, %{errors: [email: {"has already been taken", _}]}} =
2359 User.change_email(user, email)
2360 end
2361
2362 test "invalid email returns error", %{user: user} do
2363 assert {:error, %{errors: [email: {"has invalid format", _}]}} =
2364 User.change_email(user, "cofe")
2365 end
2366
2367 test "changes email", %{user: user} do
2368 assert {:ok, %User{email: "cofe@cofe.party"}} = User.change_email(user, "cofe@cofe.party")
2369 end
2370
2371 test "adds email", %{user: user} do
2372 orig_account_activation_required =
2373 Pleroma.Config.get([:instance, :account_activation_required])
2374
2375 Pleroma.Config.put([:instance, :account_activation_required], false)
2376
2377 on_exit(fn ->
2378 Pleroma.Config.put(
2379 [:instance, :account_activation_required],
2380 orig_account_activation_required
2381 )
2382 end)
2383
2384 assert {:ok, _} = User.change_email(user, "")
2385 Pleroma.Config.put([:instance, :account_activation_required], true)
2386
2387 assert {:ok, %User{email: "cofe2@cofe.party"}} = User.change_email(user, "cofe2@cofe.party")
2388 end
2389 end
2390
2391 describe "get_cached_by_nickname_or_id" do
2392 setup do
2393 local_user = insert(:user)
2394 remote_user = insert(:user, nickname: "nickname@example.com", local: false)
2395
2396 [local_user: local_user, remote_user: remote_user]
2397 end
2398
2399 setup do: clear_config([:instance, :limit_to_local_content])
2400
2401 test "allows getting remote users by id no matter what :limit_to_local_content is set to", %{
2402 remote_user: remote_user
2403 } do
2404 clear_config([:instance, :limit_to_local_content], false)
2405 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2406
2407 clear_config([:instance, :limit_to_local_content], true)
2408 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2409
2410 clear_config([:instance, :limit_to_local_content], :unauthenticated)
2411 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2412 end
2413
2414 test "disallows getting remote users by nickname without authentication when :limit_to_local_content is set to :unauthenticated",
2415 %{remote_user: remote_user} do
2416 clear_config([:instance, :limit_to_local_content], :unauthenticated)
2417 assert nil == User.get_cached_by_nickname_or_id(remote_user.nickname)
2418 end
2419
2420 test "allows getting remote users by nickname with authentication when :limit_to_local_content is set to :unauthenticated",
2421 %{remote_user: remote_user, local_user: local_user} do
2422 clear_config([:instance, :limit_to_local_content], :unauthenticated)
2423 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.nickname, for: local_user)
2424 end
2425
2426 test "disallows getting remote users by nickname when :limit_to_local_content is set to true",
2427 %{remote_user: remote_user} do
2428 clear_config([:instance, :limit_to_local_content], true)
2429 assert nil == User.get_cached_by_nickname_or_id(remote_user.nickname)
2430 end
2431
2432 test "allows getting local users by nickname no matter what :limit_to_local_content is set to",
2433 %{local_user: local_user} do
2434 clear_config([:instance, :limit_to_local_content], false)
2435 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2436
2437 clear_config([:instance, :limit_to_local_content], true)
2438 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2439
2440 clear_config([:instance, :limit_to_local_content], :unauthenticated)
2441 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2442 end
2443 end
2444
2445 describe "update_email_notifications/2" do
2446 setup do
2447 user = insert(:user, email_notifications: %{"digest" => true})
2448
2449 {:ok, user: user}
2450 end
2451
2452 test "Notifications are updated", %{user: user} do
2453 true = user.email_notifications["digest"]
2454 assert {:ok, result} = User.update_email_notifications(user, %{"digest" => false})
2455 assert result.email_notifications["digest"] == false
2456 end
2457 end
2458
2459 describe "local_nickname/1" do
2460 test "returns nickname without host" do
2461 assert User.local_nickname("@mentioned") == "mentioned"
2462 assert User.local_nickname("a_local_nickname") == "a_local_nickname"
2463 assert User.local_nickname("nickname@host.com") == "nickname"
2464 end
2465 end
2466
2467 describe "full_nickname/1" do
2468 test "returns fully qualified nickname for local and remote users" do
2469 local_user =
2470 insert(:user, nickname: "local_user", ap_id: "https://somehost.com/users/local_user")
2471
2472 remote_user = insert(:user, nickname: "remote@host.com", local: false)
2473
2474 assert User.full_nickname(local_user) == "local_user@somehost.com"
2475 assert User.full_nickname(remote_user) == "remote@host.com"
2476 end
2477
2478 test "strips leading @ from mentions" do
2479 assert User.full_nickname("@mentioned") == "mentioned"
2480 assert User.full_nickname("@nickname@host.com") == "nickname@host.com"
2481 end
2482
2483 test "does not modify nicknames" do
2484 assert User.full_nickname("nickname") == "nickname"
2485 assert User.full_nickname("nickname@host.com") == "nickname@host.com"
2486 end
2487 end
2488
2489 test "avatar fallback" do
2490 user = insert(:user)
2491 assert User.avatar_url(user) =~ "/images/avi.png"
2492
2493 clear_config([:assets, :default_user_avatar], "avatar.png")
2494
2495 user = User.get_cached_by_nickname_or_id(user.nickname)
2496 assert User.avatar_url(user) =~ "avatar.png"
2497
2498 assert User.avatar_url(user, no_default: true) == nil
2499 end
2500
2501 test "get_host/1" do
2502 user = insert(:user, ap_id: "https://lain.com/users/lain", nickname: "lain")
2503 assert User.get_host(user) == "lain.com"
2504 end
2505
2506 test "update_last_active_at/1" do
2507 user = insert(:user)
2508 assert is_nil(user.last_active_at)
2509
2510 test_started_at = NaiveDateTime.utc_now() |> NaiveDateTime.truncate(:second)
2511
2512 assert {:ok, user} = User.update_last_active_at(user)
2513
2514 assert user.last_active_at >= test_started_at
2515 assert user.last_active_at <= NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second)
2516
2517 last_active_at =
2518 NaiveDateTime.utc_now()
2519 |> NaiveDateTime.add(-:timer.hours(24), :millisecond)
2520 |> NaiveDateTime.truncate(:second)
2521
2522 assert {:ok, user} =
2523 user
2524 |> cast(%{last_active_at: last_active_at}, [:last_active_at])
2525 |> User.update_and_set_cache()
2526
2527 assert user.last_active_at == last_active_at
2528 assert {:ok, user} = User.update_last_active_at(user)
2529 assert user.last_active_at >= test_started_at
2530 assert user.last_active_at <= NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second)
2531 end
2532
2533 test "active_user_count/1" do
2534 insert(:user)
2535 insert(:user, %{local: false})
2536 insert(:user, %{last_active_at: NaiveDateTime.utc_now()})
2537 insert(:user, %{last_active_at: Timex.shift(NaiveDateTime.utc_now(), days: -15)})
2538 insert(:user, %{last_active_at: Timex.shift(NaiveDateTime.utc_now(), weeks: -6)})
2539 insert(:user, %{last_active_at: Timex.shift(NaiveDateTime.utc_now(), months: -7)})
2540 insert(:user, %{last_active_at: Timex.shift(NaiveDateTime.utc_now(), years: -2)})
2541
2542 assert User.active_user_count() == 2
2543 assert User.active_user_count(180) == 3
2544 assert User.active_user_count(365) == 4
2545 assert User.active_user_count(1000) == 5
2546 end
2547
2548 describe "pins" do
2549 setup do
2550 user = insert(:user)
2551
2552 [user: user, object_id: object_id_from_created_activity(user)]
2553 end
2554
2555 test "unique pins", %{user: user, object_id: object_id} do
2556 assert {:ok, %{pinned_objects: %{^object_id => pinned_at1} = pins} = updated_user} =
2557 User.add_pinned_object_id(user, object_id)
2558
2559 assert Enum.count(pins) == 1
2560
2561 assert {:ok, %{pinned_objects: %{^object_id => pinned_at2} = pins}} =
2562 User.add_pinned_object_id(updated_user, object_id)
2563
2564 assert pinned_at1 == pinned_at2
2565
2566 assert Enum.count(pins) == 1
2567 end
2568
2569 test "respects max_pinned_statuses limit", %{user: user, object_id: object_id} do
2570 clear_config([:instance, :max_pinned_statuses], 1)
2571 {:ok, updated} = User.add_pinned_object_id(user, object_id)
2572
2573 object_id2 = object_id_from_created_activity(user)
2574
2575 {:error, %{errors: errors}} = User.add_pinned_object_id(updated, object_id2)
2576 assert Keyword.has_key?(errors, :pinned_objects)
2577 end
2578
2579 test "remove_pinned_object_id/2", %{user: user, object_id: object_id} do
2580 assert {:ok, updated} = User.add_pinned_object_id(user, object_id)
2581
2582 {:ok, after_remove} = User.remove_pinned_object_id(updated, object_id)
2583 assert after_remove.pinned_objects == %{}
2584 end
2585 end
2586
2587 defp object_id_from_created_activity(user) do
2588 %{id: id} = insert(:note_activity, user: user)
2589 %{object: %{data: %{"id" => object_id}}} = Activity.get_by_id_with_object(id)
2590 object_id
2591 end
2592
2593 describe "add_alias/2" do
2594 test "should add alias for another user" do
2595 user = insert(:user)
2596 user2 = insert(:user)
2597
2598 assert {:ok, user_updated} = user |> User.add_alias(user2)
2599
2600 assert user_updated.also_known_as |> length() == 1
2601 assert user2.ap_id in user_updated.also_known_as
2602 end
2603
2604 test "should add multiple aliases" do
2605 user = insert(:user)
2606 user2 = insert(:user)
2607 user3 = insert(:user)
2608
2609 assert {:ok, user} = user |> User.add_alias(user2)
2610 assert {:ok, user_updated} = user |> User.add_alias(user3)
2611
2612 assert user_updated.also_known_as |> length() == 2
2613 assert user2.ap_id in user_updated.also_known_as
2614 assert user3.ap_id in user_updated.also_known_as
2615 end
2616
2617 test "should not add duplicate aliases" do
2618 user = insert(:user)
2619 user2 = insert(:user)
2620
2621 assert {:ok, user} = user |> User.add_alias(user2)
2622
2623 assert {:ok, user_updated} = user |> User.add_alias(user2)
2624
2625 assert user_updated.also_known_as |> length() == 1
2626 assert user2.ap_id in user_updated.also_known_as
2627 end
2628 end
2629
2630 describe "alias_users/1" do
2631 test "should get aliases for a user" do
2632 user = insert(:user)
2633 user2 = insert(:user, also_known_as: [user.ap_id])
2634
2635 aliases = user2 |> User.alias_users()
2636
2637 assert aliases |> length() == 1
2638
2639 alias_user = aliases |> Enum.at(0)
2640
2641 assert alias_user.ap_id == user.ap_id
2642 end
2643 end
2644
2645 describe "delete_alias/2" do
2646 test "should delete existing alias" do
2647 user = insert(:user)
2648 user2 = insert(:user, also_known_as: [user.ap_id])
2649
2650 assert {:ok, user_updated} = user2 |> User.delete_alias(user)
2651
2652 assert user_updated.also_known_as == []
2653 end
2654
2655 test "should report error on non-existing alias" do
2656 user = insert(:user)
2657 user2 = insert(:user)
2658 user3 = insert(:user, also_known_as: [user.ap_id])
2659
2660 assert {:error, :no_such_alias} = user3 |> User.delete_alias(user2)
2661
2662 user3_updated = User.get_cached_by_ap_id(user3.ap_id)
2663
2664 assert user3_updated.also_known_as |> length() == 1
2665 assert user.ap_id in user3_updated.also_known_as
2666 end
2667 end
2668 end