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