Merge remote-tracking branch 'upstream/develop' into email-fix-develop
[akkoma] / test / user_test.exs
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2020 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.Object
9 alias Pleroma.Repo
10 alias Pleroma.Tests.ObanHelpers
11 alias Pleroma.User
12 alias Pleroma.Web.ActivityPub.ActivityPub
13 alias Pleroma.Web.CommonAPI
14
15 use Pleroma.DataCase
16 use Oban.Testing, repo: Pleroma.Repo
17
18 import Pleroma.Factory
19 import ExUnit.CaptureLog
20 import Swoosh.TestAssertions
21
22 setup_all do
23 Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
24 :ok
25 end
26
27 setup do: clear_config([:instance, :account_activation_required])
28
29 describe "service actors" do
30 test "returns updated invisible actor" do
31 uri = "#{Pleroma.Web.Endpoint.url()}/relay"
32 followers_uri = "#{uri}/followers"
33
34 insert(
35 :user,
36 %{
37 nickname: "relay",
38 invisible: false,
39 local: true,
40 ap_id: uri,
41 follower_address: followers_uri
42 }
43 )
44
45 actor = User.get_or_create_service_actor_by_ap_id(uri, "relay")
46 assert actor.invisible
47 end
48
49 test "returns relay user" do
50 uri = "#{Pleroma.Web.Endpoint.url()}/relay"
51 followers_uri = "#{uri}/followers"
52
53 assert %User{
54 nickname: "relay",
55 invisible: true,
56 local: true,
57 ap_id: ^uri,
58 follower_address: ^followers_uri
59 } = User.get_or_create_service_actor_by_ap_id(uri, "relay")
60
61 assert capture_log(fn ->
62 refute User.get_or_create_service_actor_by_ap_id("/relay", "relay")
63 end) =~ "Cannot create service actor:"
64 end
65
66 test "returns invisible actor" do
67 uri = "#{Pleroma.Web.Endpoint.url()}/internal/fetch-test"
68 followers_uri = "#{uri}/followers"
69 user = User.get_or_create_service_actor_by_ap_id(uri, "internal.fetch-test")
70
71 assert %User{
72 nickname: "internal.fetch-test",
73 invisible: true,
74 local: true,
75 ap_id: ^uri,
76 follower_address: ^followers_uri
77 } = user
78
79 user2 = User.get_or_create_service_actor_by_ap_id(uri, "internal.fetch-test")
80 assert user.id == user2.id
81 end
82 end
83
84 describe "AP ID user relationships" do
85 setup do
86 {:ok, user: insert(:user)}
87 end
88
89 test "outgoing_relationships_ap_ids/1", %{user: user} do
90 rel_types = [:block, :mute, :notification_mute, :reblog_mute, :inverse_subscription]
91
92 ap_ids_by_rel =
93 Enum.into(
94 rel_types,
95 %{},
96 fn rel_type ->
97 rel_records =
98 insert_list(2, :user_relationship, %{source: user, relationship_type: rel_type})
99
100 ap_ids = Enum.map(rel_records, fn rr -> Repo.preload(rr, :target).target.ap_id end)
101 {rel_type, Enum.sort(ap_ids)}
102 end
103 )
104
105 assert ap_ids_by_rel[:block] == Enum.sort(User.blocked_users_ap_ids(user))
106 assert ap_ids_by_rel[:block] == Enum.sort(Enum.map(User.blocked_users(user), & &1.ap_id))
107
108 assert ap_ids_by_rel[:mute] == Enum.sort(User.muted_users_ap_ids(user))
109 assert ap_ids_by_rel[:mute] == Enum.sort(Enum.map(User.muted_users(user), & &1.ap_id))
110
111 assert ap_ids_by_rel[:notification_mute] ==
112 Enum.sort(User.notification_muted_users_ap_ids(user))
113
114 assert ap_ids_by_rel[:notification_mute] ==
115 Enum.sort(Enum.map(User.notification_muted_users(user), & &1.ap_id))
116
117 assert ap_ids_by_rel[:reblog_mute] == Enum.sort(User.reblog_muted_users_ap_ids(user))
118
119 assert ap_ids_by_rel[:reblog_mute] ==
120 Enum.sort(Enum.map(User.reblog_muted_users(user), & &1.ap_id))
121
122 assert ap_ids_by_rel[:inverse_subscription] == Enum.sort(User.subscriber_users_ap_ids(user))
123
124 assert ap_ids_by_rel[:inverse_subscription] ==
125 Enum.sort(Enum.map(User.subscriber_users(user), & &1.ap_id))
126
127 outgoing_relationships_ap_ids = User.outgoing_relationships_ap_ids(user, rel_types)
128
129 assert ap_ids_by_rel ==
130 Enum.into(outgoing_relationships_ap_ids, %{}, fn {k, v} -> {k, Enum.sort(v)} end)
131 end
132 end
133
134 describe "when tags are nil" do
135 test "tagging a user" do
136 user = insert(:user, %{tags: nil})
137 user = User.tag(user, ["cool", "dude"])
138
139 assert "cool" in user.tags
140 assert "dude" in user.tags
141 end
142
143 test "untagging a user" do
144 user = insert(:user, %{tags: nil})
145 user = User.untag(user, ["cool", "dude"])
146
147 assert user.tags == []
148 end
149 end
150
151 test "ap_id returns the activity pub id for the user" do
152 user = UserBuilder.build()
153
154 expected_ap_id = "#{Pleroma.Web.base_url()}/users/#{user.nickname}"
155
156 assert expected_ap_id == User.ap_id(user)
157 end
158
159 test "ap_followers returns the followers collection for the user" do
160 user = UserBuilder.build()
161
162 expected_followers_collection = "#{User.ap_id(user)}/followers"
163
164 assert expected_followers_collection == User.ap_followers(user)
165 end
166
167 test "ap_following returns the following collection for the user" do
168 user = UserBuilder.build()
169
170 expected_followers_collection = "#{User.ap_id(user)}/following"
171
172 assert expected_followers_collection == User.ap_following(user)
173 end
174
175 test "returns all pending follow requests" do
176 unlocked = insert(:user)
177 locked = insert(:user, locked: true)
178 follower = insert(:user)
179
180 CommonAPI.follow(follower, unlocked)
181 CommonAPI.follow(follower, locked)
182
183 assert [] = User.get_follow_requests(unlocked)
184 assert [activity] = User.get_follow_requests(locked)
185
186 assert activity
187 end
188
189 test "doesn't return already accepted or duplicate follow requests" do
190 locked = insert(:user, locked: true)
191 pending_follower = insert(:user)
192 accepted_follower = insert(:user)
193
194 CommonAPI.follow(pending_follower, locked)
195 CommonAPI.follow(pending_follower, locked)
196 CommonAPI.follow(accepted_follower, locked)
197
198 Pleroma.FollowingRelationship.update(accepted_follower, locked, :follow_accept)
199
200 assert [^pending_follower] = User.get_follow_requests(locked)
201 end
202
203 test "doesn't return follow requests for deactivated accounts" do
204 locked = insert(:user, locked: true)
205 pending_follower = insert(:user, %{deactivated: true})
206
207 CommonAPI.follow(pending_follower, locked)
208
209 assert true == pending_follower.deactivated
210 assert [] = User.get_follow_requests(locked)
211 end
212
213 test "clears follow requests when requester is blocked" do
214 followed = insert(:user, locked: true)
215 follower = insert(:user)
216
217 CommonAPI.follow(follower, followed)
218 assert [_activity] = User.get_follow_requests(followed)
219
220 {:ok, _user_relationship} = User.block(followed, follower)
221 assert [] = User.get_follow_requests(followed)
222 end
223
224 test "follow_all follows mutliple users" do
225 user = insert(:user)
226 followed_zero = insert(:user)
227 followed_one = insert(:user)
228 followed_two = insert(:user)
229 blocked = insert(:user)
230 not_followed = insert(:user)
231 reverse_blocked = insert(:user)
232
233 {:ok, _user_relationship} = User.block(user, blocked)
234 {:ok, _user_relationship} = User.block(reverse_blocked, user)
235
236 {:ok, user} = User.follow(user, followed_zero)
237
238 {:ok, user} = User.follow_all(user, [followed_one, followed_two, blocked, reverse_blocked])
239
240 assert User.following?(user, followed_one)
241 assert User.following?(user, followed_two)
242 assert User.following?(user, followed_zero)
243 refute User.following?(user, not_followed)
244 refute User.following?(user, blocked)
245 refute User.following?(user, reverse_blocked)
246 end
247
248 test "follow_all follows mutliple users without duplicating" do
249 user = insert(:user)
250 followed_zero = insert(:user)
251 followed_one = insert(:user)
252 followed_two = insert(:user)
253
254 {:ok, user} = User.follow_all(user, [followed_zero, followed_one])
255 assert length(User.following(user)) == 3
256
257 {:ok, user} = User.follow_all(user, [followed_one, followed_two])
258 assert length(User.following(user)) == 4
259 end
260
261 test "follow takes a user and another user" do
262 user = insert(:user)
263 followed = insert(:user)
264
265 {:ok, user} = User.follow(user, followed)
266
267 user = User.get_cached_by_id(user.id)
268 followed = User.get_cached_by_ap_id(followed.ap_id)
269
270 assert followed.follower_count == 1
271 assert user.following_count == 1
272
273 assert User.ap_followers(followed) in User.following(user)
274 end
275
276 test "can't follow a deactivated users" do
277 user = insert(:user)
278 followed = insert(:user, %{deactivated: true})
279
280 {:error, _} = User.follow(user, followed)
281 end
282
283 test "can't follow a user who blocked us" do
284 blocker = insert(:user)
285 blockee = insert(:user)
286
287 {:ok, _user_relationship} = User.block(blocker, blockee)
288
289 {:error, _} = User.follow(blockee, blocker)
290 end
291
292 test "can't subscribe to a user who blocked us" do
293 blocker = insert(:user)
294 blocked = insert(:user)
295
296 {:ok, _user_relationship} = User.block(blocker, blocked)
297
298 {:error, _} = User.subscribe(blocked, blocker)
299 end
300
301 test "local users do not automatically follow local locked accounts" do
302 follower = insert(:user, locked: true)
303 followed = insert(:user, locked: true)
304
305 {:ok, follower} = User.maybe_direct_follow(follower, followed)
306
307 refute User.following?(follower, followed)
308 end
309
310 describe "unfollow/2" do
311 setup do: clear_config([:instance, :external_user_synchronization])
312
313 test "unfollow with syncronizes external user" do
314 Pleroma.Config.put([:instance, :external_user_synchronization], true)
315
316 followed =
317 insert(:user,
318 nickname: "fuser1",
319 follower_address: "http://localhost:4001/users/fuser1/followers",
320 following_address: "http://localhost:4001/users/fuser1/following",
321 ap_id: "http://localhost:4001/users/fuser1"
322 )
323
324 user =
325 insert(:user, %{
326 local: false,
327 nickname: "fuser2",
328 ap_id: "http://localhost:4001/users/fuser2",
329 follower_address: "http://localhost:4001/users/fuser2/followers",
330 following_address: "http://localhost:4001/users/fuser2/following"
331 })
332
333 {:ok, user} = User.follow(user, followed, :follow_accept)
334
335 {:ok, user, _activity} = User.unfollow(user, followed)
336
337 user = User.get_cached_by_id(user.id)
338
339 assert User.following(user) == []
340 end
341
342 test "unfollow takes a user and another user" do
343 followed = insert(:user)
344 user = insert(:user)
345
346 {:ok, user} = User.follow(user, followed, :follow_accept)
347
348 assert User.following(user) == [user.follower_address, followed.follower_address]
349
350 {:ok, user, _activity} = User.unfollow(user, followed)
351
352 assert User.following(user) == [user.follower_address]
353 end
354
355 test "unfollow doesn't unfollow yourself" do
356 user = insert(:user)
357
358 {:error, _} = User.unfollow(user, user)
359
360 assert User.following(user) == [user.follower_address]
361 end
362 end
363
364 test "test if a user is following another user" do
365 followed = insert(:user)
366 user = insert(:user)
367 User.follow(user, followed, :follow_accept)
368
369 assert User.following?(user, followed)
370 refute User.following?(followed, user)
371 end
372
373 test "fetches correct profile for nickname beginning with number" do
374 # Use old-style integer ID to try to reproduce the problem
375 user = insert(:user, %{id: 1080})
376 user_with_numbers = insert(:user, %{nickname: "#{user.id}garbage"})
377 assert user_with_numbers == User.get_cached_by_nickname_or_id(user_with_numbers.nickname)
378 end
379
380 describe "user registration" do
381 @full_user_data %{
382 bio: "A guy",
383 name: "my name",
384 nickname: "nick",
385 password: "test",
386 password_confirmation: "test",
387 email: "email@example.com"
388 }
389
390 setup do: clear_config([:instance, :autofollowed_nicknames])
391 setup do: clear_config([:welcome])
392 setup do: clear_config([:instance, :account_activation_required])
393
394 test "it autofollows accounts that are set for it" do
395 user = insert(:user)
396 remote_user = insert(:user, %{local: false})
397
398 Pleroma.Config.put([:instance, :autofollowed_nicknames], [
399 user.nickname,
400 remote_user.nickname
401 ])
402
403 cng = User.register_changeset(%User{}, @full_user_data)
404
405 {:ok, registered_user} = User.register(cng)
406
407 assert User.following?(registered_user, user)
408 refute User.following?(registered_user, remote_user)
409 end
410
411 test "it sends a welcome message if it is set" do
412 welcome_user = insert(:user)
413 Pleroma.Config.put([:welcome, :direct_message, :enabled], true)
414 Pleroma.Config.put([:welcome, :direct_message, :sender_nickname], welcome_user.nickname)
415 Pleroma.Config.put([:welcome, :direct_message, :message], "Hello, this is a direct message")
416
417 cng = User.register_changeset(%User{}, @full_user_data)
418 {:ok, registered_user} = User.register(cng)
419 ObanHelpers.perform_all()
420
421 activity = Repo.one(Pleroma.Activity)
422 assert registered_user.ap_id in activity.recipients
423 assert Object.normalize(activity).data["content"] =~ "direct message"
424 assert activity.actor == welcome_user.ap_id
425 end
426
427 test "it sends a welcome chat message if it is set" do
428 welcome_user = insert(:user)
429 Pleroma.Config.put([:welcome, :chat_message, :enabled], true)
430 Pleroma.Config.put([:welcome, :chat_message, :sender_nickname], welcome_user.nickname)
431 Pleroma.Config.put([:welcome, :chat_message, :message], "Hello, this is a chat message")
432
433 cng = User.register_changeset(%User{}, @full_user_data)
434 {:ok, registered_user} = User.register(cng)
435 ObanHelpers.perform_all()
436
437 activity = Repo.one(Pleroma.Activity)
438 assert registered_user.ap_id in activity.recipients
439 assert Object.normalize(activity).data["content"] =~ "chat message"
440 assert activity.actor == welcome_user.ap_id
441 end
442
443 setup do:
444 clear_config(:mrf_simple,
445 media_removal: [],
446 media_nsfw: [],
447 federated_timeline_removal: [],
448 report_removal: [],
449 reject: [],
450 followers_only: [],
451 accept: [],
452 avatar_removal: [],
453 banner_removal: [],
454 reject_deletes: []
455 )
456
457 setup do:
458 clear_config(:mrf,
459 policies: [
460 Pleroma.Web.ActivityPub.MRF.SimplePolicy
461 ]
462 )
463
464 test "it sends a welcome chat message when Simple policy applied to local instance" do
465 Pleroma.Config.put([:mrf_simple, :media_nsfw], ["localhost"])
466
467 welcome_user = insert(:user)
468 Pleroma.Config.put([:welcome, :chat_message, :enabled], true)
469 Pleroma.Config.put([:welcome, :chat_message, :sender_nickname], welcome_user.nickname)
470 Pleroma.Config.put([:welcome, :chat_message, :message], "Hello, this is a chat message")
471
472 cng = User.register_changeset(%User{}, @full_user_data)
473 {:ok, registered_user} = User.register(cng)
474 ObanHelpers.perform_all()
475
476 activity = Repo.one(Pleroma.Activity)
477 assert registered_user.ap_id in activity.recipients
478 assert Object.normalize(activity).data["content"] =~ "chat message"
479 assert activity.actor == welcome_user.ap_id
480 end
481
482 test "it sends a welcome email message if it is set" do
483 welcome_user = insert(:user)
484 Pleroma.Config.put([:welcome, :email, :enabled], true)
485 Pleroma.Config.put([:welcome, :email, :sender], welcome_user.email)
486
487 Pleroma.Config.put(
488 [:welcome, :email, :subject],
489 "Hello, welcome to cool site: <%= instance_name %>"
490 )
491
492 instance_name = Pleroma.Config.get([:instance, :name])
493
494 cng = User.register_changeset(%User{}, @full_user_data)
495 {:ok, registered_user} = User.register(cng)
496 ObanHelpers.perform_all()
497
498 assert_email_sent(
499 from: {instance_name, welcome_user.email},
500 to: {registered_user.name, registered_user.email},
501 subject: "Hello, welcome to cool site: #{instance_name}",
502 html_body: "Welcome to #{instance_name}"
503 )
504 end
505
506 test "it sends a confirm email" do
507 Pleroma.Config.put([:instance, :account_activation_required], true)
508
509 cng = User.register_changeset(%User{}, @full_user_data)
510 {:ok, registered_user} = User.register(cng)
511 ObanHelpers.perform_all()
512
513 Pleroma.Emails.UserEmail.account_confirmation_email(registered_user)
514 # temporary hackney fix until hackney max_connections bug is fixed
515 # https://git.pleroma.social/pleroma/pleroma/-/issues/2101
516 |> Swoosh.Email.put_private(:hackney_options, ssl_options: [versions: [:"tlsv1.2"]])
517 |> assert_email_sent()
518 end
519
520 test "it requires an email, name, nickname and password, bio is optional when account_activation_required is enabled" do
521 Pleroma.Config.put([:instance, :account_activation_required], true)
522
523 @full_user_data
524 |> Map.keys()
525 |> Enum.each(fn key ->
526 params = Map.delete(@full_user_data, key)
527 changeset = User.register_changeset(%User{}, params)
528
529 assert if key == :bio, do: changeset.valid?, else: not changeset.valid?
530 end)
531 end
532
533 test "it requires an name, nickname and password, bio and email are optional when account_activation_required is disabled" do
534 Pleroma.Config.put([:instance, :account_activation_required], false)
535
536 @full_user_data
537 |> Map.keys()
538 |> Enum.each(fn key ->
539 params = Map.delete(@full_user_data, key)
540 changeset = User.register_changeset(%User{}, params)
541
542 assert if key in [:bio, :email], do: changeset.valid?, else: not changeset.valid?
543 end)
544 end
545
546 test "it restricts certain nicknames" do
547 [restricted_name | _] = Pleroma.Config.get([User, :restricted_nicknames])
548
549 assert is_bitstring(restricted_name)
550
551 params =
552 @full_user_data
553 |> Map.put(:nickname, restricted_name)
554
555 changeset = User.register_changeset(%User{}, params)
556
557 refute changeset.valid?
558 end
559
560 test "it blocks blacklisted email domains" do
561 clear_config([User, :email_blacklist], ["trolling.world"])
562
563 # Block with match
564 params = Map.put(@full_user_data, :email, "troll@trolling.world")
565 changeset = User.register_changeset(%User{}, params)
566 refute changeset.valid?
567
568 # Block with subdomain match
569 params = Map.put(@full_user_data, :email, "troll@gnomes.trolling.world")
570 changeset = User.register_changeset(%User{}, params)
571 refute changeset.valid?
572
573 # Pass with different domains that are similar
574 params = Map.put(@full_user_data, :email, "troll@gnomestrolling.world")
575 changeset = User.register_changeset(%User{}, params)
576 assert changeset.valid?
577
578 params = Map.put(@full_user_data, :email, "troll@trolling.world.us")
579 changeset = User.register_changeset(%User{}, params)
580 assert changeset.valid?
581 end
582
583 test "it sets the password_hash and ap_id" do
584 changeset = User.register_changeset(%User{}, @full_user_data)
585
586 assert changeset.valid?
587
588 assert is_binary(changeset.changes[:password_hash])
589 assert changeset.changes[:ap_id] == User.ap_id(%User{nickname: @full_user_data.nickname})
590
591 assert changeset.changes.follower_address == "#{changeset.changes.ap_id}/followers"
592 end
593
594 test "it sets the 'accepts_chat_messages' set to true" do
595 changeset = User.register_changeset(%User{}, @full_user_data)
596 assert changeset.valid?
597
598 {:ok, user} = Repo.insert(changeset)
599
600 assert user.accepts_chat_messages
601 end
602
603 test "it creates a confirmed user" do
604 changeset = User.register_changeset(%User{}, @full_user_data)
605 assert changeset.valid?
606
607 {:ok, user} = Repo.insert(changeset)
608
609 refute user.confirmation_pending
610 end
611 end
612
613 describe "user registration, with :account_activation_required" do
614 @full_user_data %{
615 bio: "A guy",
616 name: "my name",
617 nickname: "nick",
618 password: "test",
619 password_confirmation: "test",
620 email: "email@example.com"
621 }
622 setup do: clear_config([:instance, :account_activation_required], true)
623
624 test "it creates unconfirmed user" do
625 changeset = User.register_changeset(%User{}, @full_user_data)
626 assert changeset.valid?
627
628 {:ok, user} = Repo.insert(changeset)
629
630 assert user.confirmation_pending
631 assert user.confirmation_token
632 end
633
634 test "it creates confirmed user if :confirmed option is given" do
635 changeset = User.register_changeset(%User{}, @full_user_data, need_confirmation: false)
636 assert changeset.valid?
637
638 {:ok, user} = Repo.insert(changeset)
639
640 refute user.confirmation_pending
641 refute user.confirmation_token
642 end
643 end
644
645 describe "user registration, with :account_approval_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 registration_reason: "I'm a cool guy :)"
654 }
655 setup do: clear_config([:instance, :account_approval_required], true)
656
657 test "it creates unapproved user" do
658 changeset = User.register_changeset(%User{}, @full_user_data)
659 assert changeset.valid?
660
661 {:ok, user} = Repo.insert(changeset)
662
663 assert user.approval_pending
664 assert user.registration_reason == "I'm a cool guy :)"
665 end
666
667 test "it restricts length of registration reason" do
668 reason_limit = Pleroma.Config.get([:instance, :registration_reason_length])
669
670 assert is_integer(reason_limit)
671
672 params =
673 @full_user_data
674 |> Map.put(
675 :registration_reason,
676 "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."
677 )
678
679 changeset = User.register_changeset(%User{}, params)
680
681 refute changeset.valid?
682 end
683 end
684
685 describe "get_or_fetch/1" do
686 test "gets an existing user by nickname" do
687 user = insert(:user)
688 {:ok, fetched_user} = User.get_or_fetch(user.nickname)
689
690 assert user == fetched_user
691 end
692
693 test "gets an existing user by ap_id" do
694 ap_id = "http://mastodon.example.org/users/admin"
695
696 user =
697 insert(
698 :user,
699 local: false,
700 nickname: "admin@mastodon.example.org",
701 ap_id: ap_id
702 )
703
704 {:ok, fetched_user} = User.get_or_fetch(ap_id)
705 freshed_user = refresh_record(user)
706 assert freshed_user == fetched_user
707 end
708 end
709
710 describe "fetching a user from nickname or trying to build one" do
711 test "gets an existing user" do
712 user = insert(:user)
713 {:ok, fetched_user} = User.get_or_fetch_by_nickname(user.nickname)
714
715 assert user == fetched_user
716 end
717
718 test "gets an existing user, case insensitive" do
719 user = insert(:user, nickname: "nick")
720 {:ok, fetched_user} = User.get_or_fetch_by_nickname("NICK")
721
722 assert user == fetched_user
723 end
724
725 test "gets an existing user by fully qualified nickname" do
726 user = insert(:user)
727
728 {:ok, fetched_user} =
729 User.get_or_fetch_by_nickname(user.nickname <> "@" <> Pleroma.Web.Endpoint.host())
730
731 assert user == fetched_user
732 end
733
734 test "gets an existing user by fully qualified nickname, case insensitive" do
735 user = insert(:user, nickname: "nick")
736 casing_altered_fqn = String.upcase(user.nickname <> "@" <> Pleroma.Web.Endpoint.host())
737
738 {:ok, fetched_user} = User.get_or_fetch_by_nickname(casing_altered_fqn)
739
740 assert user == fetched_user
741 end
742
743 @tag capture_log: true
744 test "returns nil if no user could be fetched" do
745 {:error, fetched_user} = User.get_or_fetch_by_nickname("nonexistant@social.heldscal.la")
746 assert fetched_user == "not found nonexistant@social.heldscal.la"
747 end
748
749 test "returns nil for nonexistant local user" do
750 {:error, fetched_user} = User.get_or_fetch_by_nickname("nonexistant")
751 assert fetched_user == "not found nonexistant"
752 end
753
754 test "updates an existing user, if stale" do
755 a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
756
757 orig_user =
758 insert(
759 :user,
760 local: false,
761 nickname: "admin@mastodon.example.org",
762 ap_id: "http://mastodon.example.org/users/admin",
763 last_refreshed_at: a_week_ago
764 )
765
766 assert orig_user.last_refreshed_at == a_week_ago
767
768 {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/admin")
769
770 assert user.inbox
771
772 refute user.last_refreshed_at == orig_user.last_refreshed_at
773 end
774
775 test "if nicknames clash, the old user gets a prefix with the old id to the nickname" do
776 a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
777
778 orig_user =
779 insert(
780 :user,
781 local: false,
782 nickname: "admin@mastodon.example.org",
783 ap_id: "http://mastodon.example.org/users/harinezumigari",
784 last_refreshed_at: a_week_ago
785 )
786
787 assert orig_user.last_refreshed_at == a_week_ago
788
789 {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/admin")
790
791 assert user.inbox
792
793 refute user.id == orig_user.id
794
795 orig_user = User.get_by_id(orig_user.id)
796
797 assert orig_user.nickname == "#{orig_user.id}.admin@mastodon.example.org"
798 end
799
800 @tag capture_log: true
801 test "it returns the old user if stale, but unfetchable" do
802 a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
803
804 orig_user =
805 insert(
806 :user,
807 local: false,
808 nickname: "admin@mastodon.example.org",
809 ap_id: "http://mastodon.example.org/users/raymoo",
810 last_refreshed_at: a_week_ago
811 )
812
813 assert orig_user.last_refreshed_at == a_week_ago
814
815 {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/raymoo")
816
817 assert user.last_refreshed_at == orig_user.last_refreshed_at
818 end
819 end
820
821 test "returns an ap_id for a user" do
822 user = insert(:user)
823
824 assert User.ap_id(user) ==
825 Pleroma.Web.Router.Helpers.user_feed_url(
826 Pleroma.Web.Endpoint,
827 :feed_redirect,
828 user.nickname
829 )
830 end
831
832 test "returns an ap_followers link for a user" do
833 user = insert(:user)
834
835 assert User.ap_followers(user) ==
836 Pleroma.Web.Router.Helpers.user_feed_url(
837 Pleroma.Web.Endpoint,
838 :feed_redirect,
839 user.nickname
840 ) <> "/followers"
841 end
842
843 describe "remote user changeset" do
844 @valid_remote %{
845 bio: "hello",
846 name: "Someone",
847 nickname: "a@b.de",
848 ap_id: "http...",
849 avatar: %{some: "avatar"}
850 }
851 setup do: clear_config([:instance, :user_bio_length])
852 setup do: clear_config([:instance, :user_name_length])
853
854 test "it confirms validity" do
855 cs = User.remote_user_changeset(@valid_remote)
856 assert cs.valid?
857 end
858
859 test "it sets the follower_adress" do
860 cs = User.remote_user_changeset(@valid_remote)
861 # remote users get a fake local follower address
862 assert cs.changes.follower_address ==
863 User.ap_followers(%User{nickname: @valid_remote[:nickname]})
864 end
865
866 test "it enforces the fqn format for nicknames" do
867 cs = User.remote_user_changeset(%{@valid_remote | nickname: "bla"})
868 assert Ecto.Changeset.get_field(cs, :local) == false
869 assert cs.changes.avatar
870 refute cs.valid?
871 end
872
873 test "it has required fields" do
874 [:ap_id]
875 |> Enum.each(fn field ->
876 cs = User.remote_user_changeset(Map.delete(@valid_remote, field))
877 refute cs.valid?
878 end)
879 end
880 end
881
882 describe "followers and friends" do
883 test "gets all followers for a given user" do
884 user = insert(:user)
885 follower_one = insert(:user)
886 follower_two = insert(:user)
887 not_follower = insert(:user)
888
889 {:ok, follower_one} = User.follow(follower_one, user)
890 {:ok, follower_two} = User.follow(follower_two, user)
891
892 res = User.get_followers(user)
893
894 assert Enum.member?(res, follower_one)
895 assert Enum.member?(res, follower_two)
896 refute Enum.member?(res, not_follower)
897 end
898
899 test "gets all friends (followed users) for a given user" do
900 user = insert(:user)
901 followed_one = insert(:user)
902 followed_two = insert(:user)
903 not_followed = insert(:user)
904
905 {:ok, user} = User.follow(user, followed_one)
906 {:ok, user} = User.follow(user, followed_two)
907
908 res = User.get_friends(user)
909
910 followed_one = User.get_cached_by_ap_id(followed_one.ap_id)
911 followed_two = User.get_cached_by_ap_id(followed_two.ap_id)
912 assert Enum.member?(res, followed_one)
913 assert Enum.member?(res, followed_two)
914 refute Enum.member?(res, not_followed)
915 end
916 end
917
918 describe "updating note and follower count" do
919 test "it sets the note_count property" do
920 note = insert(:note)
921
922 user = User.get_cached_by_ap_id(note.data["actor"])
923
924 assert user.note_count == 0
925
926 {:ok, user} = User.update_note_count(user)
927
928 assert user.note_count == 1
929 end
930
931 test "it increases the note_count property" do
932 note = insert(:note)
933 user = User.get_cached_by_ap_id(note.data["actor"])
934
935 assert user.note_count == 0
936
937 {:ok, user} = User.increase_note_count(user)
938
939 assert user.note_count == 1
940
941 {:ok, user} = User.increase_note_count(user)
942
943 assert user.note_count == 2
944 end
945
946 test "it decreases the note_count property" do
947 note = insert(:note)
948 user = User.get_cached_by_ap_id(note.data["actor"])
949
950 assert user.note_count == 0
951
952 {:ok, user} = User.increase_note_count(user)
953
954 assert user.note_count == 1
955
956 {:ok, user} = User.decrease_note_count(user)
957
958 assert user.note_count == 0
959
960 {:ok, user} = User.decrease_note_count(user)
961
962 assert user.note_count == 0
963 end
964
965 test "it sets the follower_count property" do
966 user = insert(:user)
967 follower = insert(:user)
968
969 User.follow(follower, user)
970
971 assert user.follower_count == 0
972
973 {:ok, user} = User.update_follower_count(user)
974
975 assert user.follower_count == 1
976 end
977 end
978
979 describe "mutes" do
980 test "it mutes people" do
981 user = insert(:user)
982 muted_user = insert(:user)
983
984 refute User.mutes?(user, muted_user)
985 refute User.muted_notifications?(user, muted_user)
986
987 {:ok, _user_relationships} = User.mute(user, muted_user)
988
989 assert User.mutes?(user, muted_user)
990 assert User.muted_notifications?(user, muted_user)
991 end
992
993 test "it unmutes users" do
994 user = insert(:user)
995 muted_user = insert(:user)
996
997 {:ok, _user_relationships} = User.mute(user, muted_user)
998 {:ok, _user_mute} = User.unmute(user, muted_user)
999
1000 refute User.mutes?(user, muted_user)
1001 refute User.muted_notifications?(user, muted_user)
1002 end
1003
1004 test "it mutes user without notifications" do
1005 user = insert(:user)
1006 muted_user = insert(:user)
1007
1008 refute User.mutes?(user, muted_user)
1009 refute User.muted_notifications?(user, muted_user)
1010
1011 {:ok, _user_relationships} = User.mute(user, muted_user, false)
1012
1013 assert User.mutes?(user, muted_user)
1014 refute User.muted_notifications?(user, muted_user)
1015 end
1016 end
1017
1018 describe "blocks" do
1019 test "it blocks people" do
1020 user = insert(:user)
1021 blocked_user = insert(:user)
1022
1023 refute User.blocks?(user, blocked_user)
1024
1025 {:ok, _user_relationship} = User.block(user, blocked_user)
1026
1027 assert User.blocks?(user, blocked_user)
1028 end
1029
1030 test "it unblocks users" do
1031 user = insert(:user)
1032 blocked_user = insert(:user)
1033
1034 {:ok, _user_relationship} = User.block(user, blocked_user)
1035 {:ok, _user_block} = User.unblock(user, blocked_user)
1036
1037 refute User.blocks?(user, blocked_user)
1038 end
1039
1040 test "blocks tear down cyclical follow relationships" do
1041 blocker = insert(:user)
1042 blocked = insert(:user)
1043
1044 {:ok, blocker} = User.follow(blocker, blocked)
1045 {:ok, blocked} = User.follow(blocked, blocker)
1046
1047 assert User.following?(blocker, blocked)
1048 assert User.following?(blocked, blocker)
1049
1050 {:ok, _user_relationship} = User.block(blocker, blocked)
1051 blocked = User.get_cached_by_id(blocked.id)
1052
1053 assert User.blocks?(blocker, blocked)
1054
1055 refute User.following?(blocker, blocked)
1056 refute User.following?(blocked, blocker)
1057 end
1058
1059 test "blocks tear down blocker->blocked follow relationships" do
1060 blocker = insert(:user)
1061 blocked = insert(:user)
1062
1063 {:ok, blocker} = User.follow(blocker, blocked)
1064
1065 assert User.following?(blocker, blocked)
1066 refute User.following?(blocked, blocker)
1067
1068 {:ok, _user_relationship} = User.block(blocker, blocked)
1069 blocked = User.get_cached_by_id(blocked.id)
1070
1071 assert User.blocks?(blocker, blocked)
1072
1073 refute User.following?(blocker, blocked)
1074 refute User.following?(blocked, blocker)
1075 end
1076
1077 test "blocks tear down blocked->blocker follow relationships" do
1078 blocker = insert(:user)
1079 blocked = insert(:user)
1080
1081 {:ok, blocked} = User.follow(blocked, blocker)
1082
1083 refute User.following?(blocker, blocked)
1084 assert User.following?(blocked, blocker)
1085
1086 {:ok, _user_relationship} = User.block(blocker, blocked)
1087 blocked = User.get_cached_by_id(blocked.id)
1088
1089 assert User.blocks?(blocker, blocked)
1090
1091 refute User.following?(blocker, blocked)
1092 refute User.following?(blocked, blocker)
1093 end
1094
1095 test "blocks tear down blocked->blocker subscription relationships" do
1096 blocker = insert(:user)
1097 blocked = insert(:user)
1098
1099 {:ok, _subscription} = User.subscribe(blocked, blocker)
1100
1101 assert User.subscribed_to?(blocked, blocker)
1102 refute User.subscribed_to?(blocker, blocked)
1103
1104 {:ok, _user_relationship} = User.block(blocker, blocked)
1105
1106 assert User.blocks?(blocker, blocked)
1107 refute User.subscribed_to?(blocker, blocked)
1108 refute User.subscribed_to?(blocked, blocker)
1109 end
1110 end
1111
1112 describe "domain blocking" do
1113 test "blocks domains" do
1114 user = insert(:user)
1115 collateral_user = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1116
1117 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1118
1119 assert User.blocks?(user, collateral_user)
1120 end
1121
1122 test "does not block domain with same end" do
1123 user = insert(:user)
1124
1125 collateral_user =
1126 insert(:user, %{ap_id: "https://another-awful-and-rude-instance.com/user/bully"})
1127
1128 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1129
1130 refute User.blocks?(user, collateral_user)
1131 end
1132
1133 test "does not block domain with same end if wildcard added" do
1134 user = insert(:user)
1135
1136 collateral_user =
1137 insert(:user, %{ap_id: "https://another-awful-and-rude-instance.com/user/bully"})
1138
1139 {:ok, user} = User.block_domain(user, "*.awful-and-rude-instance.com")
1140
1141 refute User.blocks?(user, collateral_user)
1142 end
1143
1144 test "blocks domain with wildcard for subdomain" do
1145 user = insert(:user)
1146
1147 user_from_subdomain =
1148 insert(:user, %{ap_id: "https://subdomain.awful-and-rude-instance.com/user/bully"})
1149
1150 user_with_two_subdomains =
1151 insert(:user, %{
1152 ap_id: "https://subdomain.second_subdomain.awful-and-rude-instance.com/user/bully"
1153 })
1154
1155 user_domain = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1156
1157 {:ok, user} = User.block_domain(user, "*.awful-and-rude-instance.com")
1158
1159 assert User.blocks?(user, user_from_subdomain)
1160 assert User.blocks?(user, user_with_two_subdomains)
1161 assert User.blocks?(user, user_domain)
1162 end
1163
1164 test "unblocks domains" do
1165 user = insert(:user)
1166 collateral_user = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1167
1168 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1169 {:ok, user} = User.unblock_domain(user, "awful-and-rude-instance.com")
1170
1171 refute User.blocks?(user, collateral_user)
1172 end
1173
1174 test "follows take precedence over domain blocks" do
1175 user = insert(:user)
1176 good_eggo = insert(:user, %{ap_id: "https://meanies.social/user/cuteposter"})
1177
1178 {:ok, user} = User.block_domain(user, "meanies.social")
1179 {:ok, user} = User.follow(user, good_eggo)
1180
1181 refute User.blocks?(user, good_eggo)
1182 end
1183 end
1184
1185 describe "get_recipients_from_activity" do
1186 test "works for announces" do
1187 actor = insert(:user)
1188 user = insert(:user, local: true)
1189
1190 {:ok, activity} = CommonAPI.post(actor, %{status: "hello"})
1191 {:ok, announce} = CommonAPI.repeat(activity.id, user)
1192
1193 recipients = User.get_recipients_from_activity(announce)
1194
1195 assert user in recipients
1196 end
1197
1198 test "get recipients" do
1199 actor = insert(:user)
1200 user = insert(:user, local: true)
1201 user_two = insert(:user, local: false)
1202 addressed = insert(:user, local: true)
1203 addressed_remote = insert(:user, local: false)
1204
1205 {:ok, activity} =
1206 CommonAPI.post(actor, %{
1207 status: "hey @#{addressed.nickname} @#{addressed_remote.nickname}"
1208 })
1209
1210 assert Enum.map([actor, addressed], & &1.ap_id) --
1211 Enum.map(User.get_recipients_from_activity(activity), & &1.ap_id) == []
1212
1213 {:ok, user} = User.follow(user, actor)
1214 {:ok, _user_two} = User.follow(user_two, actor)
1215 recipients = User.get_recipients_from_activity(activity)
1216 assert length(recipients) == 3
1217 assert user in recipients
1218 assert addressed in recipients
1219 end
1220
1221 test "has following" do
1222 actor = insert(:user)
1223 user = insert(:user)
1224 user_two = insert(:user)
1225 addressed = insert(:user, local: true)
1226
1227 {:ok, activity} =
1228 CommonAPI.post(actor, %{
1229 status: "hey @#{addressed.nickname}"
1230 })
1231
1232 assert Enum.map([actor, addressed], & &1.ap_id) --
1233 Enum.map(User.get_recipients_from_activity(activity), & &1.ap_id) == []
1234
1235 {:ok, _actor} = User.follow(actor, user)
1236 {:ok, _actor} = User.follow(actor, user_two)
1237 recipients = User.get_recipients_from_activity(activity)
1238 assert length(recipients) == 2
1239 assert addressed in recipients
1240 end
1241 end
1242
1243 describe ".deactivate" do
1244 test "can de-activate then re-activate a user" do
1245 user = insert(:user)
1246 assert false == user.deactivated
1247 {:ok, user} = User.deactivate(user)
1248 assert true == user.deactivated
1249 {:ok, user} = User.deactivate(user, false)
1250 assert false == user.deactivated
1251 end
1252
1253 test "hide a user from followers" do
1254 user = insert(:user)
1255 user2 = insert(:user)
1256
1257 {:ok, user} = User.follow(user, user2)
1258 {:ok, _user} = User.deactivate(user)
1259
1260 user2 = User.get_cached_by_id(user2.id)
1261
1262 assert user2.follower_count == 0
1263 assert [] = User.get_followers(user2)
1264 end
1265
1266 test "hide a user from friends" do
1267 user = insert(:user)
1268 user2 = insert(:user)
1269
1270 {:ok, user2} = User.follow(user2, user)
1271 assert user2.following_count == 1
1272 assert User.following_count(user2) == 1
1273
1274 {:ok, _user} = User.deactivate(user)
1275
1276 user2 = User.get_cached_by_id(user2.id)
1277
1278 assert refresh_record(user2).following_count == 0
1279 assert user2.following_count == 0
1280 assert User.following_count(user2) == 0
1281 assert [] = User.get_friends(user2)
1282 end
1283
1284 test "hide a user's statuses from timelines and notifications" do
1285 user = insert(:user)
1286 user2 = insert(:user)
1287
1288 {:ok, user2} = User.follow(user2, user)
1289
1290 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{user2.nickname}"})
1291
1292 activity = Repo.preload(activity, :bookmark)
1293
1294 [notification] = Pleroma.Notification.for_user(user2)
1295 assert notification.activity.id == activity.id
1296
1297 assert [activity] == ActivityPub.fetch_public_activities(%{}) |> Repo.preload(:bookmark)
1298
1299 assert [%{activity | thread_muted?: CommonAPI.thread_muted?(user2, activity)}] ==
1300 ActivityPub.fetch_activities([user2.ap_id | User.following(user2)], %{
1301 user: user2
1302 })
1303
1304 {:ok, _user} = User.deactivate(user)
1305
1306 assert [] == ActivityPub.fetch_public_activities(%{})
1307 assert [] == Pleroma.Notification.for_user(user2)
1308
1309 assert [] ==
1310 ActivityPub.fetch_activities([user2.ap_id | User.following(user2)], %{
1311 user: user2
1312 })
1313 end
1314 end
1315
1316 describe "approve" do
1317 test "approves a user" do
1318 user = insert(:user, approval_pending: true)
1319 assert true == user.approval_pending
1320 {:ok, user} = User.approve(user)
1321 assert false == user.approval_pending
1322 end
1323
1324 test "approves a list of users" do
1325 unapproved_users = [
1326 insert(:user, approval_pending: true),
1327 insert(:user, approval_pending: true),
1328 insert(:user, approval_pending: true)
1329 ]
1330
1331 {:ok, users} = User.approve(unapproved_users)
1332
1333 assert Enum.count(users) == 3
1334
1335 Enum.each(users, fn user ->
1336 assert false == user.approval_pending
1337 end)
1338 end
1339 end
1340
1341 describe "delete" do
1342 setup do
1343 {:ok, user} = insert(:user) |> User.set_cache()
1344
1345 [user: user]
1346 end
1347
1348 setup do: clear_config([:instance, :federating])
1349
1350 test ".delete_user_activities deletes all create activities", %{user: user} do
1351 {:ok, activity} = CommonAPI.post(user, %{status: "2hu"})
1352
1353 User.delete_user_activities(user)
1354
1355 # TODO: Test removal favorites, repeats, delete activities.
1356 refute Activity.get_by_id(activity.id)
1357 end
1358
1359 test "it deactivates a user, all follow relationships and all activities", %{user: user} do
1360 follower = insert(:user)
1361 {:ok, follower} = User.follow(follower, user)
1362
1363 locked_user = insert(:user, name: "locked", locked: true)
1364 {:ok, _} = User.follow(user, locked_user, :follow_pending)
1365
1366 object = insert(:note, user: user)
1367 activity = insert(:note_activity, user: user, note: object)
1368
1369 object_two = insert(:note, user: follower)
1370 activity_two = insert(:note_activity, user: follower, note: object_two)
1371
1372 {:ok, like} = CommonAPI.favorite(user, activity_two.id)
1373 {:ok, like_two} = CommonAPI.favorite(follower, activity.id)
1374 {:ok, repeat} = CommonAPI.repeat(activity_two.id, user)
1375
1376 {:ok, job} = User.delete(user)
1377 {:ok, _user} = ObanHelpers.perform(job)
1378
1379 follower = User.get_cached_by_id(follower.id)
1380
1381 refute User.following?(follower, user)
1382 assert %{deactivated: true} = User.get_by_id(user.id)
1383
1384 assert [] == User.get_follow_requests(locked_user)
1385
1386 user_activities =
1387 user.ap_id
1388 |> Activity.Queries.by_actor()
1389 |> Repo.all()
1390 |> Enum.map(fn act -> act.data["type"] end)
1391
1392 assert Enum.all?(user_activities, fn act -> act in ~w(Delete Undo) end)
1393
1394 refute Activity.get_by_id(activity.id)
1395 refute Activity.get_by_id(like.id)
1396 refute Activity.get_by_id(like_two.id)
1397 refute Activity.get_by_id(repeat.id)
1398 end
1399 end
1400
1401 describe "delete/1 when confirmation is pending" do
1402 setup do
1403 user = insert(:user, confirmation_pending: true)
1404 {:ok, user: user}
1405 end
1406
1407 test "deletes user from database when activation required", %{user: user} do
1408 clear_config([:instance, :account_activation_required], true)
1409
1410 {:ok, job} = User.delete(user)
1411 {:ok, _} = ObanHelpers.perform(job)
1412
1413 refute User.get_cached_by_id(user.id)
1414 refute User.get_by_id(user.id)
1415 end
1416
1417 test "deactivates user when activation is not required", %{user: user} do
1418 clear_config([:instance, :account_activation_required], false)
1419
1420 {:ok, job} = User.delete(user)
1421 {:ok, _} = ObanHelpers.perform(job)
1422
1423 assert %{deactivated: true} = User.get_cached_by_id(user.id)
1424 assert %{deactivated: true} = User.get_by_id(user.id)
1425 end
1426 end
1427
1428 test "delete/1 when approval is pending deletes the user" do
1429 user = insert(:user, approval_pending: true)
1430
1431 {:ok, job} = User.delete(user)
1432 {:ok, _} = ObanHelpers.perform(job)
1433
1434 refute User.get_cached_by_id(user.id)
1435 refute User.get_by_id(user.id)
1436 end
1437
1438 test "delete/1 purges a user when they wouldn't be fully deleted" do
1439 user =
1440 insert(:user, %{
1441 bio: "eyy lmao",
1442 name: "qqqqqqq",
1443 password_hash: "pdfk2$1b3n159001",
1444 keys: "RSA begin buplic key",
1445 public_key: "--PRIVATE KEYE--",
1446 avatar: %{"a" => "b"},
1447 tags: ["qqqqq"],
1448 banner: %{"a" => "b"},
1449 background: %{"a" => "b"},
1450 note_count: 9,
1451 follower_count: 9,
1452 following_count: 9001,
1453 locked: true,
1454 confirmation_pending: true,
1455 password_reset_pending: true,
1456 approval_pending: true,
1457 registration_reason: "ahhhhh",
1458 confirmation_token: "qqqq",
1459 domain_blocks: ["lain.com"],
1460 deactivated: true,
1461 ap_enabled: true,
1462 is_moderator: true,
1463 is_admin: true,
1464 mastofe_settings: %{"a" => "b"},
1465 mascot: %{"a" => "b"},
1466 emoji: %{"a" => "b"},
1467 pleroma_settings_store: %{"q" => "x"},
1468 fields: [%{"gg" => "qq"}],
1469 raw_fields: [%{"gg" => "qq"}],
1470 discoverable: true,
1471 also_known_as: ["https://lol.olo/users/loll"]
1472 })
1473
1474 {:ok, job} = User.delete(user)
1475 {:ok, _} = ObanHelpers.perform(job)
1476 user = User.get_by_id(user.id)
1477
1478 assert %User{
1479 bio: "",
1480 raw_bio: nil,
1481 email: nil,
1482 name: nil,
1483 password_hash: nil,
1484 keys: nil,
1485 public_key: nil,
1486 avatar: %{},
1487 tags: [],
1488 last_refreshed_at: nil,
1489 last_digest_emailed_at: nil,
1490 banner: %{},
1491 background: %{},
1492 note_count: 0,
1493 follower_count: 0,
1494 following_count: 0,
1495 locked: false,
1496 confirmation_pending: false,
1497 password_reset_pending: false,
1498 approval_pending: false,
1499 registration_reason: nil,
1500 confirmation_token: nil,
1501 domain_blocks: [],
1502 deactivated: true,
1503 ap_enabled: false,
1504 is_moderator: false,
1505 is_admin: false,
1506 mastofe_settings: nil,
1507 mascot: nil,
1508 emoji: %{},
1509 pleroma_settings_store: %{},
1510 fields: [],
1511 raw_fields: [],
1512 discoverable: false,
1513 also_known_as: []
1514 } = user
1515 end
1516
1517 test "get_public_key_for_ap_id fetches a user that's not in the db" do
1518 assert {:ok, _key} = User.get_public_key_for_ap_id("http://mastodon.example.org/users/admin")
1519 end
1520
1521 describe "per-user rich-text filtering" do
1522 test "html_filter_policy returns default policies, when rich-text is enabled" do
1523 user = insert(:user)
1524
1525 assert Pleroma.Config.get([:markup, :scrub_policy]) == User.html_filter_policy(user)
1526 end
1527
1528 test "html_filter_policy returns TwitterText scrubber when rich-text is disabled" do
1529 user = insert(:user, no_rich_text: true)
1530
1531 assert Pleroma.HTML.Scrubber.TwitterText == User.html_filter_policy(user)
1532 end
1533 end
1534
1535 describe "caching" do
1536 test "invalidate_cache works" do
1537 user = insert(:user)
1538
1539 User.set_cache(user)
1540 User.invalidate_cache(user)
1541
1542 {:ok, nil} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1543 {:ok, nil} = Cachex.get(:user_cache, "nickname:#{user.nickname}")
1544 end
1545
1546 test "User.delete() plugs any possible zombie objects" do
1547 user = insert(:user)
1548
1549 {:ok, job} = User.delete(user)
1550 {:ok, _} = ObanHelpers.perform(job)
1551
1552 {:ok, cached_user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1553
1554 assert cached_user != user
1555
1556 {:ok, cached_user} = Cachex.get(:user_cache, "nickname:#{user.ap_id}")
1557
1558 assert cached_user != user
1559 end
1560 end
1561
1562 describe "account_status/1" do
1563 setup do: clear_config([:instance, :account_activation_required])
1564
1565 test "return confirmation_pending for unconfirm user" do
1566 Pleroma.Config.put([:instance, :account_activation_required], true)
1567 user = insert(:user, confirmation_pending: true)
1568 assert User.account_status(user) == :confirmation_pending
1569 end
1570
1571 test "return active for confirmed user" do
1572 Pleroma.Config.put([:instance, :account_activation_required], true)
1573 user = insert(:user, confirmation_pending: false)
1574 assert User.account_status(user) == :active
1575 end
1576
1577 test "return active for remote user" do
1578 user = insert(:user, local: false)
1579 assert User.account_status(user) == :active
1580 end
1581
1582 test "returns :password_reset_pending for user with reset password" do
1583 user = insert(:user, password_reset_pending: true)
1584 assert User.account_status(user) == :password_reset_pending
1585 end
1586
1587 test "returns :deactivated for deactivated user" do
1588 user = insert(:user, local: true, confirmation_pending: false, deactivated: true)
1589 assert User.account_status(user) == :deactivated
1590 end
1591
1592 test "returns :approval_pending for unapproved user" do
1593 user = insert(:user, local: true, approval_pending: true)
1594 assert User.account_status(user) == :approval_pending
1595
1596 user = insert(:user, local: true, confirmation_pending: true, approval_pending: true)
1597 assert User.account_status(user) == :approval_pending
1598 end
1599 end
1600
1601 describe "superuser?/1" do
1602 test "returns false for unprivileged users" do
1603 user = insert(:user, local: true)
1604
1605 refute User.superuser?(user)
1606 end
1607
1608 test "returns false for remote users" do
1609 user = insert(:user, local: false)
1610 remote_admin_user = insert(:user, local: false, is_admin: true)
1611
1612 refute User.superuser?(user)
1613 refute User.superuser?(remote_admin_user)
1614 end
1615
1616 test "returns true for local moderators" do
1617 user = insert(:user, local: true, is_moderator: true)
1618
1619 assert User.superuser?(user)
1620 end
1621
1622 test "returns true for local admins" do
1623 user = insert(:user, local: true, is_admin: true)
1624
1625 assert User.superuser?(user)
1626 end
1627 end
1628
1629 describe "invisible?/1" do
1630 test "returns true for an invisible user" do
1631 user = insert(:user, local: true, invisible: true)
1632
1633 assert User.invisible?(user)
1634 end
1635
1636 test "returns false for a non-invisible user" do
1637 user = insert(:user, local: true)
1638
1639 refute User.invisible?(user)
1640 end
1641 end
1642
1643 describe "visible_for/2" do
1644 test "returns true when the account is itself" do
1645 user = insert(:user, local: true)
1646
1647 assert User.visible_for(user, user) == :visible
1648 end
1649
1650 test "returns false when the account is unconfirmed and confirmation is required" do
1651 Pleroma.Config.put([:instance, :account_activation_required], true)
1652
1653 user = insert(:user, local: true, confirmation_pending: true)
1654 other_user = insert(:user, local: true)
1655
1656 refute User.visible_for(user, other_user) == :visible
1657 end
1658
1659 test "returns true when the account is unconfirmed and confirmation is required but the account is remote" do
1660 Pleroma.Config.put([:instance, :account_activation_required], true)
1661
1662 user = insert(:user, local: false, confirmation_pending: true)
1663 other_user = insert(:user, local: true)
1664
1665 assert User.visible_for(user, other_user) == :visible
1666 end
1667
1668 test "returns true when the account is unconfirmed and confirmation is not required" do
1669 user = insert(:user, local: true, confirmation_pending: true)
1670 other_user = insert(:user, local: true)
1671
1672 assert User.visible_for(user, other_user) == :visible
1673 end
1674
1675 test "returns true when the account is unconfirmed and being viewed by a privileged account (confirmation required)" do
1676 Pleroma.Config.put([:instance, :account_activation_required], true)
1677
1678 user = insert(:user, local: true, confirmation_pending: true)
1679 other_user = insert(:user, local: true, is_admin: true)
1680
1681 assert User.visible_for(user, other_user) == :visible
1682 end
1683 end
1684
1685 describe "parse_bio/2" do
1686 test "preserves hosts in user links text" do
1687 remote_user = insert(:user, local: false, nickname: "nick@domain.com")
1688 user = insert(:user)
1689 bio = "A.k.a. @nick@domain.com"
1690
1691 expected_text =
1692 ~s(A.k.a. <span class="h-card"><a class="u-url mention" data-user="#{remote_user.id}" href="#{
1693 remote_user.ap_id
1694 }" rel="ugc">@<span>nick@domain.com</span></a></span>)
1695
1696 assert expected_text == User.parse_bio(bio, user)
1697 end
1698
1699 test "Adds rel=me on linkbacked urls" do
1700 user = insert(:user, ap_id: "https://social.example.org/users/lain")
1701
1702 bio = "http://example.com/rel_me/null"
1703 expected_text = "<a href=\"#{bio}\">#{bio}</a>"
1704 assert expected_text == User.parse_bio(bio, user)
1705
1706 bio = "http://example.com/rel_me/link"
1707 expected_text = "<a href=\"#{bio}\" rel=\"me\">#{bio}</a>"
1708 assert expected_text == User.parse_bio(bio, user)
1709
1710 bio = "http://example.com/rel_me/anchor"
1711 expected_text = "<a href=\"#{bio}\" rel=\"me\">#{bio}</a>"
1712 assert expected_text == User.parse_bio(bio, user)
1713 end
1714 end
1715
1716 test "follower count is updated when a follower is blocked" do
1717 user = insert(:user)
1718 follower = insert(:user)
1719 follower2 = insert(:user)
1720 follower3 = insert(:user)
1721
1722 {:ok, follower} = User.follow(follower, user)
1723 {:ok, _follower2} = User.follow(follower2, user)
1724 {:ok, _follower3} = User.follow(follower3, user)
1725
1726 {:ok, _user_relationship} = User.block(user, follower)
1727 user = refresh_record(user)
1728
1729 assert user.follower_count == 2
1730 end
1731
1732 describe "list_inactive_users_query/1" do
1733 defp days_ago(days) do
1734 NaiveDateTime.add(
1735 NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second),
1736 -days * 60 * 60 * 24,
1737 :second
1738 )
1739 end
1740
1741 test "Users are inactive by default" do
1742 total = 10
1743
1744 users =
1745 Enum.map(1..total, fn _ ->
1746 insert(:user, last_digest_emailed_at: days_ago(20), deactivated: false)
1747 end)
1748
1749 inactive_users_ids =
1750 Pleroma.User.list_inactive_users_query()
1751 |> Pleroma.Repo.all()
1752 |> Enum.map(& &1.id)
1753
1754 Enum.each(users, fn user ->
1755 assert user.id in inactive_users_ids
1756 end)
1757 end
1758
1759 test "Only includes users who has no recent activity" do
1760 total = 10
1761
1762 users =
1763 Enum.map(1..total, fn _ ->
1764 insert(:user, last_digest_emailed_at: days_ago(20), deactivated: false)
1765 end)
1766
1767 {inactive, active} = Enum.split(users, trunc(total / 2))
1768
1769 Enum.map(active, fn user ->
1770 to = Enum.random(users -- [user])
1771
1772 {:ok, _} =
1773 CommonAPI.post(user, %{
1774 status: "hey @#{to.nickname}"
1775 })
1776 end)
1777
1778 inactive_users_ids =
1779 Pleroma.User.list_inactive_users_query()
1780 |> Pleroma.Repo.all()
1781 |> Enum.map(& &1.id)
1782
1783 Enum.each(active, fn user ->
1784 refute user.id in inactive_users_ids
1785 end)
1786
1787 Enum.each(inactive, fn user ->
1788 assert user.id in inactive_users_ids
1789 end)
1790 end
1791
1792 test "Only includes users with no read notifications" do
1793 total = 10
1794
1795 users =
1796 Enum.map(1..total, fn _ ->
1797 insert(:user, last_digest_emailed_at: days_ago(20), deactivated: false)
1798 end)
1799
1800 [sender | recipients] = users
1801 {inactive, active} = Enum.split(recipients, trunc(total / 2))
1802
1803 Enum.each(recipients, fn to ->
1804 {:ok, _} =
1805 CommonAPI.post(sender, %{
1806 status: "hey @#{to.nickname}"
1807 })
1808
1809 {:ok, _} =
1810 CommonAPI.post(sender, %{
1811 status: "hey again @#{to.nickname}"
1812 })
1813 end)
1814
1815 Enum.each(active, fn user ->
1816 [n1, _n2] = Pleroma.Notification.for_user(user)
1817 {:ok, _} = Pleroma.Notification.read_one(user, n1.id)
1818 end)
1819
1820 inactive_users_ids =
1821 Pleroma.User.list_inactive_users_query()
1822 |> Pleroma.Repo.all()
1823 |> Enum.map(& &1.id)
1824
1825 Enum.each(active, fn user ->
1826 refute user.id in inactive_users_ids
1827 end)
1828
1829 Enum.each(inactive, fn user ->
1830 assert user.id in inactive_users_ids
1831 end)
1832 end
1833 end
1834
1835 describe "toggle_confirmation/1" do
1836 test "if user is confirmed" do
1837 user = insert(:user, confirmation_pending: false)
1838 {:ok, user} = User.toggle_confirmation(user)
1839
1840 assert user.confirmation_pending
1841 assert user.confirmation_token
1842 end
1843
1844 test "if user is unconfirmed" do
1845 user = insert(:user, confirmation_pending: true, confirmation_token: "some token")
1846 {:ok, user} = User.toggle_confirmation(user)
1847
1848 refute user.confirmation_pending
1849 refute user.confirmation_token
1850 end
1851 end
1852
1853 describe "ensure_keys_present" do
1854 test "it creates keys for a user and stores them in info" do
1855 user = insert(:user)
1856 refute is_binary(user.keys)
1857 {:ok, user} = User.ensure_keys_present(user)
1858 assert is_binary(user.keys)
1859 end
1860
1861 test "it doesn't create keys if there already are some" do
1862 user = insert(:user, keys: "xxx")
1863 {:ok, user} = User.ensure_keys_present(user)
1864 assert user.keys == "xxx"
1865 end
1866 end
1867
1868 describe "get_ap_ids_by_nicknames" do
1869 test "it returns a list of AP ids for a given set of nicknames" do
1870 user = insert(:user)
1871 user_two = insert(:user)
1872
1873 ap_ids = User.get_ap_ids_by_nicknames([user.nickname, user_two.nickname, "nonexistent"])
1874 assert length(ap_ids) == 2
1875 assert user.ap_id in ap_ids
1876 assert user_two.ap_id in ap_ids
1877 end
1878 end
1879
1880 describe "sync followers count" do
1881 setup do
1882 user1 = insert(:user, local: false, ap_id: "http://localhost:4001/users/masto_closed")
1883 user2 = insert(:user, local: false, ap_id: "http://localhost:4001/users/fuser2")
1884 insert(:user, local: true)
1885 insert(:user, local: false, deactivated: true)
1886 {:ok, user1: user1, user2: user2}
1887 end
1888
1889 test "external_users/1 external active users with limit", %{user1: user1, user2: user2} do
1890 [fdb_user1] = User.external_users(limit: 1)
1891
1892 assert fdb_user1.ap_id
1893 assert fdb_user1.ap_id == user1.ap_id
1894 assert fdb_user1.id == user1.id
1895
1896 [fdb_user2] = User.external_users(max_id: fdb_user1.id, limit: 1)
1897
1898 assert fdb_user2.ap_id
1899 assert fdb_user2.ap_id == user2.ap_id
1900 assert fdb_user2.id == user2.id
1901
1902 assert User.external_users(max_id: fdb_user2.id, limit: 1) == []
1903 end
1904 end
1905
1906 describe "is_internal_user?/1" do
1907 test "non-internal user returns false" do
1908 user = insert(:user)
1909 refute User.is_internal_user?(user)
1910 end
1911
1912 test "user with no nickname returns true" do
1913 user = insert(:user, %{nickname: nil})
1914 assert User.is_internal_user?(user)
1915 end
1916
1917 test "user with internal-prefixed nickname returns true" do
1918 user = insert(:user, %{nickname: "internal.test"})
1919 assert User.is_internal_user?(user)
1920 end
1921 end
1922
1923 describe "update_and_set_cache/1" do
1924 test "returns error when user is stale instead Ecto.StaleEntryError" do
1925 user = insert(:user)
1926
1927 changeset = Ecto.Changeset.change(user, bio: "test")
1928
1929 Repo.delete(user)
1930
1931 assert {:error, %Ecto.Changeset{errors: [id: {"is stale", [stale: true]}], valid?: false}} =
1932 User.update_and_set_cache(changeset)
1933 end
1934
1935 test "performs update cache if user updated" do
1936 user = insert(:user)
1937 assert {:ok, nil} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1938
1939 changeset = Ecto.Changeset.change(user, bio: "test-bio")
1940
1941 assert {:ok, %User{bio: "test-bio"} = user} = User.update_and_set_cache(changeset)
1942 assert {:ok, user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1943 assert %User{bio: "test-bio"} = User.get_cached_by_ap_id(user.ap_id)
1944 end
1945 end
1946
1947 describe "following/followers synchronization" do
1948 setup do: clear_config([:instance, :external_user_synchronization])
1949
1950 test "updates the counters normally on following/getting a follow when disabled" do
1951 Pleroma.Config.put([:instance, :external_user_synchronization], false)
1952 user = insert(:user)
1953
1954 other_user =
1955 insert(:user,
1956 local: false,
1957 follower_address: "http://localhost:4001/users/masto_closed/followers",
1958 following_address: "http://localhost:4001/users/masto_closed/following",
1959 ap_enabled: true
1960 )
1961
1962 assert other_user.following_count == 0
1963 assert other_user.follower_count == 0
1964
1965 {:ok, user} = Pleroma.User.follow(user, other_user)
1966 other_user = Pleroma.User.get_by_id(other_user.id)
1967
1968 assert user.following_count == 1
1969 assert other_user.follower_count == 1
1970 end
1971
1972 test "syncronizes the counters with the remote instance for the followed when enabled" do
1973 Pleroma.Config.put([:instance, :external_user_synchronization], false)
1974
1975 user = insert(:user)
1976
1977 other_user =
1978 insert(:user,
1979 local: false,
1980 follower_address: "http://localhost:4001/users/masto_closed/followers",
1981 following_address: "http://localhost:4001/users/masto_closed/following",
1982 ap_enabled: true
1983 )
1984
1985 assert other_user.following_count == 0
1986 assert other_user.follower_count == 0
1987
1988 Pleroma.Config.put([:instance, :external_user_synchronization], true)
1989 {:ok, _user} = User.follow(user, other_user)
1990 other_user = User.get_by_id(other_user.id)
1991
1992 assert other_user.follower_count == 437
1993 end
1994
1995 test "syncronizes the counters with the remote instance for the follower when enabled" do
1996 Pleroma.Config.put([:instance, :external_user_synchronization], false)
1997
1998 user = insert(:user)
1999
2000 other_user =
2001 insert(:user,
2002 local: false,
2003 follower_address: "http://localhost:4001/users/masto_closed/followers",
2004 following_address: "http://localhost:4001/users/masto_closed/following",
2005 ap_enabled: true
2006 )
2007
2008 assert other_user.following_count == 0
2009 assert other_user.follower_count == 0
2010
2011 Pleroma.Config.put([:instance, :external_user_synchronization], true)
2012 {:ok, other_user} = User.follow(other_user, user)
2013
2014 assert other_user.following_count == 152
2015 end
2016 end
2017
2018 describe "change_email/2" do
2019 setup do
2020 [user: insert(:user)]
2021 end
2022
2023 test "blank email returns error", %{user: user} do
2024 assert {:error, %{errors: [email: {"can't be blank", _}]}} = User.change_email(user, "")
2025 assert {:error, %{errors: [email: {"can't be blank", _}]}} = User.change_email(user, nil)
2026 end
2027
2028 test "non unique email returns error", %{user: user} do
2029 %{email: email} = insert(:user)
2030
2031 assert {:error, %{errors: [email: {"has already been taken", _}]}} =
2032 User.change_email(user, email)
2033 end
2034
2035 test "invalid email returns error", %{user: user} do
2036 assert {:error, %{errors: [email: {"has invalid format", _}]}} =
2037 User.change_email(user, "cofe")
2038 end
2039
2040 test "changes email", %{user: user} do
2041 assert {:ok, %User{email: "cofe@cofe.party"}} = User.change_email(user, "cofe@cofe.party")
2042 end
2043 end
2044
2045 describe "get_cached_by_nickname_or_id" do
2046 setup do
2047 local_user = insert(:user)
2048 remote_user = insert(:user, nickname: "nickname@example.com", local: false)
2049
2050 [local_user: local_user, remote_user: remote_user]
2051 end
2052
2053 setup do: clear_config([:instance, :limit_to_local_content])
2054
2055 test "allows getting remote users by id no matter what :limit_to_local_content is set to", %{
2056 remote_user: remote_user
2057 } do
2058 Pleroma.Config.put([:instance, :limit_to_local_content], false)
2059 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2060
2061 Pleroma.Config.put([:instance, :limit_to_local_content], true)
2062 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2063
2064 Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
2065 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2066 end
2067
2068 test "disallows getting remote users by nickname without authentication when :limit_to_local_content is set to :unauthenticated",
2069 %{remote_user: remote_user} do
2070 Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
2071 assert nil == User.get_cached_by_nickname_or_id(remote_user.nickname)
2072 end
2073
2074 test "allows getting remote users by nickname with authentication when :limit_to_local_content is set to :unauthenticated",
2075 %{remote_user: remote_user, local_user: local_user} do
2076 Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
2077 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.nickname, for: local_user)
2078 end
2079
2080 test "disallows getting remote users by nickname when :limit_to_local_content is set to true",
2081 %{remote_user: remote_user} do
2082 Pleroma.Config.put([:instance, :limit_to_local_content], true)
2083 assert nil == User.get_cached_by_nickname_or_id(remote_user.nickname)
2084 end
2085
2086 test "allows getting local users by nickname no matter what :limit_to_local_content is set to",
2087 %{local_user: local_user} do
2088 Pleroma.Config.put([:instance, :limit_to_local_content], false)
2089 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2090
2091 Pleroma.Config.put([:instance, :limit_to_local_content], true)
2092 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2093
2094 Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
2095 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2096 end
2097 end
2098
2099 describe "update_email_notifications/2" do
2100 setup do
2101 user = insert(:user, email_notifications: %{"digest" => true})
2102
2103 {:ok, user: user}
2104 end
2105
2106 test "Notifications are updated", %{user: user} do
2107 true = user.email_notifications["digest"]
2108 assert {:ok, result} = User.update_email_notifications(user, %{"digest" => false})
2109 assert result.email_notifications["digest"] == false
2110 end
2111 end
2112
2113 test "avatar fallback" do
2114 user = insert(:user)
2115 assert User.avatar_url(user) =~ "/images/avi.png"
2116
2117 clear_config([:assets, :default_user_avatar], "avatar.png")
2118
2119 user = User.get_cached_by_nickname_or_id(user.nickname)
2120 assert User.avatar_url(user) =~ "avatar.png"
2121
2122 assert User.avatar_url(user, no_default: true) == nil
2123 end
2124 end