User: Don't allow local users in remote changesets
[akkoma] / test / pleroma / 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, is_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, is_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, is_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, is_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, is_locked: true)
303 followed = insert(:user, is_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
881 test "it is invalid given a local user" do
882 user = insert(:user)
883 cs = User.remote_user_changeset(user, %{name: "tom from myspace"})
884
885 refute cs.valid?
886 end
887 end
888
889 describe "followers and friends" do
890 test "gets all followers for a given user" do
891 user = insert(:user)
892 follower_one = insert(:user)
893 follower_two = insert(:user)
894 not_follower = insert(:user)
895
896 {:ok, follower_one} = User.follow(follower_one, user)
897 {:ok, follower_two} = User.follow(follower_two, user)
898
899 res = User.get_followers(user)
900
901 assert Enum.member?(res, follower_one)
902 assert Enum.member?(res, follower_two)
903 refute Enum.member?(res, not_follower)
904 end
905
906 test "gets all friends (followed users) for a given user" do
907 user = insert(:user)
908 followed_one = insert(:user)
909 followed_two = insert(:user)
910 not_followed = insert(:user)
911
912 {:ok, user} = User.follow(user, followed_one)
913 {:ok, user} = User.follow(user, followed_two)
914
915 res = User.get_friends(user)
916
917 followed_one = User.get_cached_by_ap_id(followed_one.ap_id)
918 followed_two = User.get_cached_by_ap_id(followed_two.ap_id)
919 assert Enum.member?(res, followed_one)
920 assert Enum.member?(res, followed_two)
921 refute Enum.member?(res, not_followed)
922 end
923 end
924
925 describe "updating note and follower count" do
926 test "it sets the note_count property" do
927 note = insert(:note)
928
929 user = User.get_cached_by_ap_id(note.data["actor"])
930
931 assert user.note_count == 0
932
933 {:ok, user} = User.update_note_count(user)
934
935 assert user.note_count == 1
936 end
937
938 test "it increases the note_count property" do
939 note = insert(:note)
940 user = User.get_cached_by_ap_id(note.data["actor"])
941
942 assert user.note_count == 0
943
944 {:ok, user} = User.increase_note_count(user)
945
946 assert user.note_count == 1
947
948 {:ok, user} = User.increase_note_count(user)
949
950 assert user.note_count == 2
951 end
952
953 test "it decreases the note_count property" do
954 note = insert(:note)
955 user = User.get_cached_by_ap_id(note.data["actor"])
956
957 assert user.note_count == 0
958
959 {:ok, user} = User.increase_note_count(user)
960
961 assert user.note_count == 1
962
963 {:ok, user} = User.decrease_note_count(user)
964
965 assert user.note_count == 0
966
967 {:ok, user} = User.decrease_note_count(user)
968
969 assert user.note_count == 0
970 end
971
972 test "it sets the follower_count property" do
973 user = insert(:user)
974 follower = insert(:user)
975
976 User.follow(follower, user)
977
978 assert user.follower_count == 0
979
980 {:ok, user} = User.update_follower_count(user)
981
982 assert user.follower_count == 1
983 end
984 end
985
986 describe "mutes" do
987 test "it mutes people" do
988 user = insert(:user)
989 muted_user = insert(:user)
990
991 refute User.mutes?(user, muted_user)
992 refute User.muted_notifications?(user, muted_user)
993
994 {:ok, _user_relationships} = User.mute(user, muted_user)
995
996 assert User.mutes?(user, muted_user)
997 assert User.muted_notifications?(user, muted_user)
998 end
999
1000 test "it unmutes users" do
1001 user = insert(:user)
1002 muted_user = insert(:user)
1003
1004 {:ok, _user_relationships} = User.mute(user, muted_user)
1005 {:ok, _user_mute} = User.unmute(user, muted_user)
1006
1007 refute User.mutes?(user, muted_user)
1008 refute User.muted_notifications?(user, muted_user)
1009 end
1010
1011 test "it mutes user without notifications" do
1012 user = insert(:user)
1013 muted_user = insert(:user)
1014
1015 refute User.mutes?(user, muted_user)
1016 refute User.muted_notifications?(user, muted_user)
1017
1018 {:ok, _user_relationships} = User.mute(user, muted_user, false)
1019
1020 assert User.mutes?(user, muted_user)
1021 refute User.muted_notifications?(user, muted_user)
1022 end
1023 end
1024
1025 describe "blocks" do
1026 test "it blocks people" do
1027 user = insert(:user)
1028 blocked_user = insert(:user)
1029
1030 refute User.blocks?(user, blocked_user)
1031
1032 {:ok, _user_relationship} = User.block(user, blocked_user)
1033
1034 assert User.blocks?(user, blocked_user)
1035 end
1036
1037 test "it unblocks users" do
1038 user = insert(:user)
1039 blocked_user = insert(:user)
1040
1041 {:ok, _user_relationship} = User.block(user, blocked_user)
1042 {:ok, _user_block} = User.unblock(user, blocked_user)
1043
1044 refute User.blocks?(user, blocked_user)
1045 end
1046
1047 test "blocks tear down cyclical follow relationships" do
1048 blocker = insert(:user)
1049 blocked = insert(:user)
1050
1051 {:ok, blocker} = User.follow(blocker, blocked)
1052 {:ok, blocked} = User.follow(blocked, blocker)
1053
1054 assert User.following?(blocker, blocked)
1055 assert User.following?(blocked, blocker)
1056
1057 {:ok, _user_relationship} = User.block(blocker, blocked)
1058 blocked = User.get_cached_by_id(blocked.id)
1059
1060 assert User.blocks?(blocker, blocked)
1061
1062 refute User.following?(blocker, blocked)
1063 refute User.following?(blocked, blocker)
1064 end
1065
1066 test "blocks tear down blocker->blocked follow relationships" do
1067 blocker = insert(:user)
1068 blocked = insert(:user)
1069
1070 {:ok, blocker} = User.follow(blocker, blocked)
1071
1072 assert User.following?(blocker, blocked)
1073 refute User.following?(blocked, blocker)
1074
1075 {:ok, _user_relationship} = User.block(blocker, blocked)
1076 blocked = User.get_cached_by_id(blocked.id)
1077
1078 assert User.blocks?(blocker, blocked)
1079
1080 refute User.following?(blocker, blocked)
1081 refute User.following?(blocked, blocker)
1082 end
1083
1084 test "blocks tear down blocked->blocker follow relationships" do
1085 blocker = insert(:user)
1086 blocked = insert(:user)
1087
1088 {:ok, blocked} = User.follow(blocked, blocker)
1089
1090 refute User.following?(blocker, blocked)
1091 assert User.following?(blocked, blocker)
1092
1093 {:ok, _user_relationship} = User.block(blocker, blocked)
1094 blocked = User.get_cached_by_id(blocked.id)
1095
1096 assert User.blocks?(blocker, blocked)
1097
1098 refute User.following?(blocker, blocked)
1099 refute User.following?(blocked, blocker)
1100 end
1101
1102 test "blocks tear down blocked->blocker subscription relationships" do
1103 blocker = insert(:user)
1104 blocked = insert(:user)
1105
1106 {:ok, _subscription} = User.subscribe(blocked, blocker)
1107
1108 assert User.subscribed_to?(blocked, blocker)
1109 refute User.subscribed_to?(blocker, blocked)
1110
1111 {:ok, _user_relationship} = User.block(blocker, blocked)
1112
1113 assert User.blocks?(blocker, blocked)
1114 refute User.subscribed_to?(blocker, blocked)
1115 refute User.subscribed_to?(blocked, blocker)
1116 end
1117 end
1118
1119 describe "domain blocking" do
1120 test "blocks domains" do
1121 user = insert(:user)
1122 collateral_user = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1123
1124 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1125
1126 assert User.blocks?(user, collateral_user)
1127 end
1128
1129 test "does not block domain with same end" do
1130 user = insert(:user)
1131
1132 collateral_user =
1133 insert(:user, %{ap_id: "https://another-awful-and-rude-instance.com/user/bully"})
1134
1135 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1136
1137 refute User.blocks?(user, collateral_user)
1138 end
1139
1140 test "does not block domain with same end if wildcard added" do
1141 user = insert(:user)
1142
1143 collateral_user =
1144 insert(:user, %{ap_id: "https://another-awful-and-rude-instance.com/user/bully"})
1145
1146 {:ok, user} = User.block_domain(user, "*.awful-and-rude-instance.com")
1147
1148 refute User.blocks?(user, collateral_user)
1149 end
1150
1151 test "blocks domain with wildcard for subdomain" do
1152 user = insert(:user)
1153
1154 user_from_subdomain =
1155 insert(:user, %{ap_id: "https://subdomain.awful-and-rude-instance.com/user/bully"})
1156
1157 user_with_two_subdomains =
1158 insert(:user, %{
1159 ap_id: "https://subdomain.second_subdomain.awful-and-rude-instance.com/user/bully"
1160 })
1161
1162 user_domain = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1163
1164 {:ok, user} = User.block_domain(user, "*.awful-and-rude-instance.com")
1165
1166 assert User.blocks?(user, user_from_subdomain)
1167 assert User.blocks?(user, user_with_two_subdomains)
1168 assert User.blocks?(user, user_domain)
1169 end
1170
1171 test "unblocks domains" do
1172 user = insert(:user)
1173 collateral_user = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1174
1175 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1176 {:ok, user} = User.unblock_domain(user, "awful-and-rude-instance.com")
1177
1178 refute User.blocks?(user, collateral_user)
1179 end
1180
1181 test "follows take precedence over domain blocks" do
1182 user = insert(:user)
1183 good_eggo = insert(:user, %{ap_id: "https://meanies.social/user/cuteposter"})
1184
1185 {:ok, user} = User.block_domain(user, "meanies.social")
1186 {:ok, user} = User.follow(user, good_eggo)
1187
1188 refute User.blocks?(user, good_eggo)
1189 end
1190 end
1191
1192 describe "get_recipients_from_activity" do
1193 test "works for announces" do
1194 actor = insert(:user)
1195 user = insert(:user, local: true)
1196
1197 {:ok, activity} = CommonAPI.post(actor, %{status: "hello"})
1198 {:ok, announce} = CommonAPI.repeat(activity.id, user)
1199
1200 recipients = User.get_recipients_from_activity(announce)
1201
1202 assert user in recipients
1203 end
1204
1205 test "get recipients" do
1206 actor = insert(:user)
1207 user = insert(:user, local: true)
1208 user_two = insert(:user, local: false)
1209 addressed = insert(:user, local: true)
1210 addressed_remote = insert(:user, local: false)
1211
1212 {:ok, activity} =
1213 CommonAPI.post(actor, %{
1214 status: "hey @#{addressed.nickname} @#{addressed_remote.nickname}"
1215 })
1216
1217 assert Enum.map([actor, addressed], & &1.ap_id) --
1218 Enum.map(User.get_recipients_from_activity(activity), & &1.ap_id) == []
1219
1220 {:ok, user} = User.follow(user, actor)
1221 {:ok, _user_two} = User.follow(user_two, actor)
1222 recipients = User.get_recipients_from_activity(activity)
1223 assert length(recipients) == 3
1224 assert user in recipients
1225 assert addressed in recipients
1226 end
1227
1228 test "has following" do
1229 actor = insert(:user)
1230 user = insert(:user)
1231 user_two = insert(:user)
1232 addressed = insert(:user, local: true)
1233
1234 {:ok, activity} =
1235 CommonAPI.post(actor, %{
1236 status: "hey @#{addressed.nickname}"
1237 })
1238
1239 assert Enum.map([actor, addressed], & &1.ap_id) --
1240 Enum.map(User.get_recipients_from_activity(activity), & &1.ap_id) == []
1241
1242 {:ok, _actor} = User.follow(actor, user)
1243 {:ok, _actor} = User.follow(actor, user_two)
1244 recipients = User.get_recipients_from_activity(activity)
1245 assert length(recipients) == 2
1246 assert addressed in recipients
1247 end
1248 end
1249
1250 describe ".deactivate" do
1251 test "can de-activate then re-activate a user" do
1252 user = insert(:user)
1253 assert false == user.deactivated
1254 {:ok, user} = User.deactivate(user)
1255 assert true == user.deactivated
1256 {:ok, user} = User.deactivate(user, false)
1257 assert false == user.deactivated
1258 end
1259
1260 test "hide a user from followers" do
1261 user = insert(:user)
1262 user2 = insert(:user)
1263
1264 {:ok, user} = User.follow(user, user2)
1265 {:ok, _user} = User.deactivate(user)
1266
1267 user2 = User.get_cached_by_id(user2.id)
1268
1269 assert user2.follower_count == 0
1270 assert [] = User.get_followers(user2)
1271 end
1272
1273 test "hide a user from friends" do
1274 user = insert(:user)
1275 user2 = insert(:user)
1276
1277 {:ok, user2} = User.follow(user2, user)
1278 assert user2.following_count == 1
1279 assert User.following_count(user2) == 1
1280
1281 {:ok, _user} = User.deactivate(user)
1282
1283 user2 = User.get_cached_by_id(user2.id)
1284
1285 assert refresh_record(user2).following_count == 0
1286 assert user2.following_count == 0
1287 assert User.following_count(user2) == 0
1288 assert [] = User.get_friends(user2)
1289 end
1290
1291 test "hide a user's statuses from timelines and notifications" do
1292 user = insert(:user)
1293 user2 = insert(:user)
1294
1295 {:ok, user2} = User.follow(user2, user)
1296
1297 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{user2.nickname}"})
1298
1299 activity = Repo.preload(activity, :bookmark)
1300
1301 [notification] = Pleroma.Notification.for_user(user2)
1302 assert notification.activity.id == activity.id
1303
1304 assert [activity] == ActivityPub.fetch_public_activities(%{}) |> Repo.preload(:bookmark)
1305
1306 assert [%{activity | thread_muted?: CommonAPI.thread_muted?(user2, activity)}] ==
1307 ActivityPub.fetch_activities([user2.ap_id | User.following(user2)], %{
1308 user: user2
1309 })
1310
1311 {:ok, _user} = User.deactivate(user)
1312
1313 assert [] == ActivityPub.fetch_public_activities(%{})
1314 assert [] == Pleroma.Notification.for_user(user2)
1315
1316 assert [] ==
1317 ActivityPub.fetch_activities([user2.ap_id | User.following(user2)], %{
1318 user: user2
1319 })
1320 end
1321 end
1322
1323 describe "approve" do
1324 test "approves a user" do
1325 user = insert(:user, approval_pending: true)
1326 assert true == user.approval_pending
1327 {:ok, user} = User.approve(user)
1328 assert false == user.approval_pending
1329 end
1330
1331 test "approves a list of users" do
1332 unapproved_users = [
1333 insert(:user, approval_pending: true),
1334 insert(:user, approval_pending: true),
1335 insert(:user, approval_pending: true)
1336 ]
1337
1338 {:ok, users} = User.approve(unapproved_users)
1339
1340 assert Enum.count(users) == 3
1341
1342 Enum.each(users, fn user ->
1343 assert false == user.approval_pending
1344 end)
1345 end
1346 end
1347
1348 describe "delete" do
1349 setup do
1350 {:ok, user} = insert(:user) |> User.set_cache()
1351
1352 [user: user]
1353 end
1354
1355 setup do: clear_config([:instance, :federating])
1356
1357 test ".delete_user_activities deletes all create activities", %{user: user} do
1358 {:ok, activity} = CommonAPI.post(user, %{status: "2hu"})
1359
1360 User.delete_user_activities(user)
1361
1362 # TODO: Test removal favorites, repeats, delete activities.
1363 refute Activity.get_by_id(activity.id)
1364 end
1365
1366 test "it deactivates a user, all follow relationships and all activities", %{user: user} do
1367 follower = insert(:user)
1368 {:ok, follower} = User.follow(follower, user)
1369
1370 locked_user = insert(:user, name: "locked", is_locked: true)
1371 {:ok, _} = User.follow(user, locked_user, :follow_pending)
1372
1373 object = insert(:note, user: user)
1374 activity = insert(:note_activity, user: user, note: object)
1375
1376 object_two = insert(:note, user: follower)
1377 activity_two = insert(:note_activity, user: follower, note: object_two)
1378
1379 {:ok, like} = CommonAPI.favorite(user, activity_two.id)
1380 {:ok, like_two} = CommonAPI.favorite(follower, activity.id)
1381 {:ok, repeat} = CommonAPI.repeat(activity_two.id, user)
1382
1383 {:ok, job} = User.delete(user)
1384 {:ok, _user} = ObanHelpers.perform(job)
1385
1386 follower = User.get_cached_by_id(follower.id)
1387
1388 refute User.following?(follower, user)
1389 assert %{deactivated: true} = User.get_by_id(user.id)
1390
1391 assert [] == User.get_follow_requests(locked_user)
1392
1393 user_activities =
1394 user.ap_id
1395 |> Activity.Queries.by_actor()
1396 |> Repo.all()
1397 |> Enum.map(fn act -> act.data["type"] end)
1398
1399 assert Enum.all?(user_activities, fn act -> act in ~w(Delete Undo) end)
1400
1401 refute Activity.get_by_id(activity.id)
1402 refute Activity.get_by_id(like.id)
1403 refute Activity.get_by_id(like_two.id)
1404 refute Activity.get_by_id(repeat.id)
1405 end
1406 end
1407
1408 describe "delete/1 when confirmation is pending" do
1409 setup do
1410 user = insert(:user, confirmation_pending: true)
1411 {:ok, user: user}
1412 end
1413
1414 test "deletes user from database when activation required", %{user: user} do
1415 clear_config([:instance, :account_activation_required], true)
1416
1417 {:ok, job} = User.delete(user)
1418 {:ok, _} = ObanHelpers.perform(job)
1419
1420 refute User.get_cached_by_id(user.id)
1421 refute User.get_by_id(user.id)
1422 end
1423
1424 test "deactivates user when activation is not required", %{user: user} do
1425 clear_config([:instance, :account_activation_required], false)
1426
1427 {:ok, job} = User.delete(user)
1428 {:ok, _} = ObanHelpers.perform(job)
1429
1430 assert %{deactivated: true} = User.get_cached_by_id(user.id)
1431 assert %{deactivated: true} = User.get_by_id(user.id)
1432 end
1433 end
1434
1435 test "delete/1 when approval is pending deletes the user" do
1436 user = insert(:user, approval_pending: true)
1437
1438 {:ok, job} = User.delete(user)
1439 {:ok, _} = ObanHelpers.perform(job)
1440
1441 refute User.get_cached_by_id(user.id)
1442 refute User.get_by_id(user.id)
1443 end
1444
1445 test "delete/1 purges a user when they wouldn't be fully deleted" do
1446 user =
1447 insert(:user, %{
1448 bio: "eyy lmao",
1449 name: "qqqqqqq",
1450 password_hash: "pdfk2$1b3n159001",
1451 keys: "RSA begin buplic key",
1452 public_key: "--PRIVATE KEYE--",
1453 avatar: %{"a" => "b"},
1454 tags: ["qqqqq"],
1455 banner: %{"a" => "b"},
1456 background: %{"a" => "b"},
1457 note_count: 9,
1458 follower_count: 9,
1459 following_count: 9001,
1460 is_locked: true,
1461 confirmation_pending: true,
1462 password_reset_pending: true,
1463 approval_pending: true,
1464 registration_reason: "ahhhhh",
1465 confirmation_token: "qqqq",
1466 domain_blocks: ["lain.com"],
1467 deactivated: true,
1468 ap_enabled: true,
1469 is_moderator: true,
1470 is_admin: true,
1471 mastofe_settings: %{"a" => "b"},
1472 mascot: %{"a" => "b"},
1473 emoji: %{"a" => "b"},
1474 pleroma_settings_store: %{"q" => "x"},
1475 fields: [%{"gg" => "qq"}],
1476 raw_fields: [%{"gg" => "qq"}],
1477 discoverable: true,
1478 also_known_as: ["https://lol.olo/users/loll"]
1479 })
1480
1481 {:ok, job} = User.delete(user)
1482 {:ok, _} = ObanHelpers.perform(job)
1483 user = User.get_by_id(user.id)
1484
1485 assert %User{
1486 bio: "",
1487 raw_bio: nil,
1488 email: nil,
1489 name: nil,
1490 password_hash: nil,
1491 keys: nil,
1492 public_key: nil,
1493 avatar: %{},
1494 tags: [],
1495 last_refreshed_at: nil,
1496 last_digest_emailed_at: nil,
1497 banner: %{},
1498 background: %{},
1499 note_count: 0,
1500 follower_count: 0,
1501 following_count: 0,
1502 is_locked: false,
1503 confirmation_pending: false,
1504 password_reset_pending: false,
1505 approval_pending: false,
1506 registration_reason: nil,
1507 confirmation_token: nil,
1508 domain_blocks: [],
1509 deactivated: true,
1510 ap_enabled: false,
1511 is_moderator: false,
1512 is_admin: false,
1513 mastofe_settings: nil,
1514 mascot: nil,
1515 emoji: %{},
1516 pleroma_settings_store: %{},
1517 fields: [],
1518 raw_fields: [],
1519 discoverable: false,
1520 also_known_as: []
1521 } = user
1522 end
1523
1524 test "get_public_key_for_ap_id fetches a user that's not in the db" do
1525 assert {:ok, _key} = User.get_public_key_for_ap_id("http://mastodon.example.org/users/admin")
1526 end
1527
1528 describe "per-user rich-text filtering" do
1529 test "html_filter_policy returns default policies, when rich-text is enabled" do
1530 user = insert(:user)
1531
1532 assert Pleroma.Config.get([:markup, :scrub_policy]) == User.html_filter_policy(user)
1533 end
1534
1535 test "html_filter_policy returns TwitterText scrubber when rich-text is disabled" do
1536 user = insert(:user, no_rich_text: true)
1537
1538 assert Pleroma.HTML.Scrubber.TwitterText == User.html_filter_policy(user)
1539 end
1540 end
1541
1542 describe "caching" do
1543 test "invalidate_cache works" do
1544 user = insert(:user)
1545
1546 User.set_cache(user)
1547 User.invalidate_cache(user)
1548
1549 {:ok, nil} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1550 {:ok, nil} = Cachex.get(:user_cache, "nickname:#{user.nickname}")
1551 end
1552
1553 test "User.delete() plugs any possible zombie objects" do
1554 user = insert(:user)
1555
1556 {:ok, job} = User.delete(user)
1557 {:ok, _} = ObanHelpers.perform(job)
1558
1559 {:ok, cached_user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1560
1561 assert cached_user != user
1562
1563 {:ok, cached_user} = Cachex.get(:user_cache, "nickname:#{user.ap_id}")
1564
1565 assert cached_user != user
1566 end
1567 end
1568
1569 describe "account_status/1" do
1570 setup do: clear_config([:instance, :account_activation_required])
1571
1572 test "return confirmation_pending for unconfirm user" do
1573 Pleroma.Config.put([:instance, :account_activation_required], true)
1574 user = insert(:user, confirmation_pending: true)
1575 assert User.account_status(user) == :confirmation_pending
1576 end
1577
1578 test "return active for confirmed user" do
1579 Pleroma.Config.put([:instance, :account_activation_required], true)
1580 user = insert(:user, confirmation_pending: false)
1581 assert User.account_status(user) == :active
1582 end
1583
1584 test "return active for remote user" do
1585 user = insert(:user, local: false)
1586 assert User.account_status(user) == :active
1587 end
1588
1589 test "returns :password_reset_pending for user with reset password" do
1590 user = insert(:user, password_reset_pending: true)
1591 assert User.account_status(user) == :password_reset_pending
1592 end
1593
1594 test "returns :deactivated for deactivated user" do
1595 user = insert(:user, local: true, confirmation_pending: false, deactivated: true)
1596 assert User.account_status(user) == :deactivated
1597 end
1598
1599 test "returns :approval_pending for unapproved user" do
1600 user = insert(:user, local: true, approval_pending: true)
1601 assert User.account_status(user) == :approval_pending
1602
1603 user = insert(:user, local: true, confirmation_pending: true, approval_pending: true)
1604 assert User.account_status(user) == :approval_pending
1605 end
1606 end
1607
1608 describe "superuser?/1" do
1609 test "returns false for unprivileged users" do
1610 user = insert(:user, local: true)
1611
1612 refute User.superuser?(user)
1613 end
1614
1615 test "returns false for remote users" do
1616 user = insert(:user, local: false)
1617 remote_admin_user = insert(:user, local: false, is_admin: true)
1618
1619 refute User.superuser?(user)
1620 refute User.superuser?(remote_admin_user)
1621 end
1622
1623 test "returns true for local moderators" do
1624 user = insert(:user, local: true, is_moderator: true)
1625
1626 assert User.superuser?(user)
1627 end
1628
1629 test "returns true for local admins" do
1630 user = insert(:user, local: true, is_admin: true)
1631
1632 assert User.superuser?(user)
1633 end
1634 end
1635
1636 describe "invisible?/1" do
1637 test "returns true for an invisible user" do
1638 user = insert(:user, local: true, invisible: true)
1639
1640 assert User.invisible?(user)
1641 end
1642
1643 test "returns false for a non-invisible user" do
1644 user = insert(:user, local: true)
1645
1646 refute User.invisible?(user)
1647 end
1648 end
1649
1650 describe "visible_for/2" do
1651 test "returns true when the account is itself" do
1652 user = insert(:user, local: true)
1653
1654 assert User.visible_for(user, user) == :visible
1655 end
1656
1657 test "returns false when the account is unconfirmed and confirmation is required" do
1658 Pleroma.Config.put([:instance, :account_activation_required], true)
1659
1660 user = insert(:user, local: true, confirmation_pending: true)
1661 other_user = insert(:user, local: true)
1662
1663 refute User.visible_for(user, other_user) == :visible
1664 end
1665
1666 test "returns true when the account is unconfirmed and confirmation is required but the account is remote" do
1667 Pleroma.Config.put([:instance, :account_activation_required], true)
1668
1669 user = insert(:user, local: false, 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 confirmation is not required" do
1676 user = insert(:user, local: true, confirmation_pending: true)
1677 other_user = insert(:user, local: true)
1678
1679 assert User.visible_for(user, other_user) == :visible
1680 end
1681
1682 test "returns true when the account is unconfirmed and being viewed by a privileged account (confirmation required)" do
1683 Pleroma.Config.put([:instance, :account_activation_required], true)
1684
1685 user = insert(:user, local: true, confirmation_pending: true)
1686 other_user = insert(:user, local: true, is_admin: true)
1687
1688 assert User.visible_for(user, other_user) == :visible
1689 end
1690 end
1691
1692 describe "parse_bio/2" do
1693 test "preserves hosts in user links text" do
1694 remote_user = insert(:user, local: false, nickname: "nick@domain.com")
1695 user = insert(:user)
1696 bio = "A.k.a. @nick@domain.com"
1697
1698 expected_text =
1699 ~s(A.k.a. <span class="h-card"><a class="u-url mention" data-user="#{remote_user.id}" href="#{
1700 remote_user.ap_id
1701 }" rel="ugc">@<span>nick@domain.com</span></a></span>)
1702
1703 assert expected_text == User.parse_bio(bio, user)
1704 end
1705
1706 test "Adds rel=me on linkbacked urls" do
1707 user = insert(:user, ap_id: "https://social.example.org/users/lain")
1708
1709 bio = "http://example.com/rel_me/null"
1710 expected_text = "<a href=\"#{bio}\">#{bio}</a>"
1711 assert expected_text == User.parse_bio(bio, user)
1712
1713 bio = "http://example.com/rel_me/link"
1714 expected_text = "<a href=\"#{bio}\" rel=\"me\">#{bio}</a>"
1715 assert expected_text == User.parse_bio(bio, user)
1716
1717 bio = "http://example.com/rel_me/anchor"
1718 expected_text = "<a href=\"#{bio}\" rel=\"me\">#{bio}</a>"
1719 assert expected_text == User.parse_bio(bio, user)
1720 end
1721 end
1722
1723 test "follower count is updated when a follower is blocked" do
1724 user = insert(:user)
1725 follower = insert(:user)
1726 follower2 = insert(:user)
1727 follower3 = insert(:user)
1728
1729 {:ok, follower} = User.follow(follower, user)
1730 {:ok, _follower2} = User.follow(follower2, user)
1731 {:ok, _follower3} = User.follow(follower3, user)
1732
1733 {:ok, _user_relationship} = User.block(user, follower)
1734 user = refresh_record(user)
1735
1736 assert user.follower_count == 2
1737 end
1738
1739 describe "list_inactive_users_query/1" do
1740 defp days_ago(days) do
1741 NaiveDateTime.add(
1742 NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second),
1743 -days * 60 * 60 * 24,
1744 :second
1745 )
1746 end
1747
1748 test "Users are inactive by default" do
1749 total = 10
1750
1751 users =
1752 Enum.map(1..total, fn _ ->
1753 insert(:user, last_digest_emailed_at: days_ago(20), deactivated: false)
1754 end)
1755
1756 inactive_users_ids =
1757 Pleroma.User.list_inactive_users_query()
1758 |> Pleroma.Repo.all()
1759 |> Enum.map(& &1.id)
1760
1761 Enum.each(users, fn user ->
1762 assert user.id in inactive_users_ids
1763 end)
1764 end
1765
1766 test "Only includes users who has no recent activity" do
1767 total = 10
1768
1769 users =
1770 Enum.map(1..total, fn _ ->
1771 insert(:user, last_digest_emailed_at: days_ago(20), deactivated: false)
1772 end)
1773
1774 {inactive, active} = Enum.split(users, trunc(total / 2))
1775
1776 Enum.map(active, fn user ->
1777 to = Enum.random(users -- [user])
1778
1779 {:ok, _} =
1780 CommonAPI.post(user, %{
1781 status: "hey @#{to.nickname}"
1782 })
1783 end)
1784
1785 inactive_users_ids =
1786 Pleroma.User.list_inactive_users_query()
1787 |> Pleroma.Repo.all()
1788 |> Enum.map(& &1.id)
1789
1790 Enum.each(active, fn user ->
1791 refute user.id in inactive_users_ids
1792 end)
1793
1794 Enum.each(inactive, fn user ->
1795 assert user.id in inactive_users_ids
1796 end)
1797 end
1798
1799 test "Only includes users with no read notifications" do
1800 total = 10
1801
1802 users =
1803 Enum.map(1..total, fn _ ->
1804 insert(:user, last_digest_emailed_at: days_ago(20), deactivated: false)
1805 end)
1806
1807 [sender | recipients] = users
1808 {inactive, active} = Enum.split(recipients, trunc(total / 2))
1809
1810 Enum.each(recipients, fn to ->
1811 {:ok, _} =
1812 CommonAPI.post(sender, %{
1813 status: "hey @#{to.nickname}"
1814 })
1815
1816 {:ok, _} =
1817 CommonAPI.post(sender, %{
1818 status: "hey again @#{to.nickname}"
1819 })
1820 end)
1821
1822 Enum.each(active, fn user ->
1823 [n1, _n2] = Pleroma.Notification.for_user(user)
1824 {:ok, _} = Pleroma.Notification.read_one(user, n1.id)
1825 end)
1826
1827 inactive_users_ids =
1828 Pleroma.User.list_inactive_users_query()
1829 |> Pleroma.Repo.all()
1830 |> Enum.map(& &1.id)
1831
1832 Enum.each(active, fn user ->
1833 refute user.id in inactive_users_ids
1834 end)
1835
1836 Enum.each(inactive, fn user ->
1837 assert user.id in inactive_users_ids
1838 end)
1839 end
1840 end
1841
1842 describe "toggle_confirmation/1" do
1843 test "if user is confirmed" do
1844 user = insert(:user, confirmation_pending: false)
1845 {:ok, user} = User.toggle_confirmation(user)
1846
1847 assert user.confirmation_pending
1848 assert user.confirmation_token
1849 end
1850
1851 test "if user is unconfirmed" do
1852 user = insert(:user, confirmation_pending: true, confirmation_token: "some token")
1853 {:ok, user} = User.toggle_confirmation(user)
1854
1855 refute user.confirmation_pending
1856 refute user.confirmation_token
1857 end
1858 end
1859
1860 describe "ensure_keys_present" do
1861 test "it creates keys for a user and stores them in info" do
1862 user = insert(:user)
1863 refute is_binary(user.keys)
1864 {:ok, user} = User.ensure_keys_present(user)
1865 assert is_binary(user.keys)
1866 end
1867
1868 test "it doesn't create keys if there already are some" do
1869 user = insert(:user, keys: "xxx")
1870 {:ok, user} = User.ensure_keys_present(user)
1871 assert user.keys == "xxx"
1872 end
1873 end
1874
1875 describe "get_ap_ids_by_nicknames" do
1876 test "it returns a list of AP ids for a given set of nicknames" do
1877 user = insert(:user)
1878 user_two = insert(:user)
1879
1880 ap_ids = User.get_ap_ids_by_nicknames([user.nickname, user_two.nickname, "nonexistent"])
1881 assert length(ap_ids) == 2
1882 assert user.ap_id in ap_ids
1883 assert user_two.ap_id in ap_ids
1884 end
1885 end
1886
1887 describe "sync followers count" do
1888 setup do
1889 user1 = insert(:user, local: false, ap_id: "http://localhost:4001/users/masto_closed")
1890 user2 = insert(:user, local: false, ap_id: "http://localhost:4001/users/fuser2")
1891 insert(:user, local: true)
1892 insert(:user, local: false, deactivated: true)
1893 {:ok, user1: user1, user2: user2}
1894 end
1895
1896 test "external_users/1 external active users with limit", %{user1: user1, user2: user2} do
1897 [fdb_user1] = User.external_users(limit: 1)
1898
1899 assert fdb_user1.ap_id
1900 assert fdb_user1.ap_id == user1.ap_id
1901 assert fdb_user1.id == user1.id
1902
1903 [fdb_user2] = User.external_users(max_id: fdb_user1.id, limit: 1)
1904
1905 assert fdb_user2.ap_id
1906 assert fdb_user2.ap_id == user2.ap_id
1907 assert fdb_user2.id == user2.id
1908
1909 assert User.external_users(max_id: fdb_user2.id, limit: 1) == []
1910 end
1911 end
1912
1913 describe "is_internal_user?/1" do
1914 test "non-internal user returns false" do
1915 user = insert(:user)
1916 refute User.is_internal_user?(user)
1917 end
1918
1919 test "user with no nickname returns true" do
1920 user = insert(:user, %{nickname: nil})
1921 assert User.is_internal_user?(user)
1922 end
1923
1924 test "user with internal-prefixed nickname returns true" do
1925 user = insert(:user, %{nickname: "internal.test"})
1926 assert User.is_internal_user?(user)
1927 end
1928 end
1929
1930 describe "update_and_set_cache/1" do
1931 test "returns error when user is stale instead Ecto.StaleEntryError" do
1932 user = insert(:user)
1933
1934 changeset = Ecto.Changeset.change(user, bio: "test")
1935
1936 Repo.delete(user)
1937
1938 assert {:error, %Ecto.Changeset{errors: [id: {"is stale", [stale: true]}], valid?: false}} =
1939 User.update_and_set_cache(changeset)
1940 end
1941
1942 test "performs update cache if user updated" do
1943 user = insert(:user)
1944 assert {:ok, nil} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1945
1946 changeset = Ecto.Changeset.change(user, bio: "test-bio")
1947
1948 assert {:ok, %User{bio: "test-bio"} = user} = User.update_and_set_cache(changeset)
1949 assert {:ok, user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1950 assert %User{bio: "test-bio"} = User.get_cached_by_ap_id(user.ap_id)
1951 end
1952 end
1953
1954 describe "following/followers synchronization" do
1955 setup do: clear_config([:instance, :external_user_synchronization])
1956
1957 test "updates the counters normally on following/getting a follow when disabled" do
1958 Pleroma.Config.put([:instance, :external_user_synchronization], false)
1959 user = insert(:user)
1960
1961 other_user =
1962 insert(:user,
1963 local: false,
1964 follower_address: "http://localhost:4001/users/masto_closed/followers",
1965 following_address: "http://localhost:4001/users/masto_closed/following",
1966 ap_enabled: true
1967 )
1968
1969 assert other_user.following_count == 0
1970 assert other_user.follower_count == 0
1971
1972 {:ok, user} = Pleroma.User.follow(user, other_user)
1973 other_user = Pleroma.User.get_by_id(other_user.id)
1974
1975 assert user.following_count == 1
1976 assert other_user.follower_count == 1
1977 end
1978
1979 test "syncronizes the counters with the remote instance for the followed when enabled" do
1980 Pleroma.Config.put([:instance, :external_user_synchronization], false)
1981
1982 user = insert(:user)
1983
1984 other_user =
1985 insert(:user,
1986 local: false,
1987 follower_address: "http://localhost:4001/users/masto_closed/followers",
1988 following_address: "http://localhost:4001/users/masto_closed/following",
1989 ap_enabled: true
1990 )
1991
1992 assert other_user.following_count == 0
1993 assert other_user.follower_count == 0
1994
1995 Pleroma.Config.put([:instance, :external_user_synchronization], true)
1996 {:ok, _user} = User.follow(user, other_user)
1997 other_user = User.get_by_id(other_user.id)
1998
1999 assert other_user.follower_count == 437
2000 end
2001
2002 test "syncronizes the counters with the remote instance for the follower when enabled" do
2003 Pleroma.Config.put([:instance, :external_user_synchronization], false)
2004
2005 user = insert(:user)
2006
2007 other_user =
2008 insert(:user,
2009 local: false,
2010 follower_address: "http://localhost:4001/users/masto_closed/followers",
2011 following_address: "http://localhost:4001/users/masto_closed/following",
2012 ap_enabled: true
2013 )
2014
2015 assert other_user.following_count == 0
2016 assert other_user.follower_count == 0
2017
2018 Pleroma.Config.put([:instance, :external_user_synchronization], true)
2019 {:ok, other_user} = User.follow(other_user, user)
2020
2021 assert other_user.following_count == 152
2022 end
2023 end
2024
2025 describe "change_email/2" do
2026 setup do
2027 [user: insert(:user)]
2028 end
2029
2030 test "blank email returns error", %{user: user} do
2031 assert {:error, %{errors: [email: {"can't be blank", _}]}} = User.change_email(user, "")
2032 assert {:error, %{errors: [email: {"can't be blank", _}]}} = User.change_email(user, nil)
2033 end
2034
2035 test "non unique email returns error", %{user: user} do
2036 %{email: email} = insert(:user)
2037
2038 assert {:error, %{errors: [email: {"has already been taken", _}]}} =
2039 User.change_email(user, email)
2040 end
2041
2042 test "invalid email returns error", %{user: user} do
2043 assert {:error, %{errors: [email: {"has invalid format", _}]}} =
2044 User.change_email(user, "cofe")
2045 end
2046
2047 test "changes email", %{user: user} do
2048 assert {:ok, %User{email: "cofe@cofe.party"}} = User.change_email(user, "cofe@cofe.party")
2049 end
2050 end
2051
2052 describe "get_cached_by_nickname_or_id" do
2053 setup do
2054 local_user = insert(:user)
2055 remote_user = insert(:user, nickname: "nickname@example.com", local: false)
2056
2057 [local_user: local_user, remote_user: remote_user]
2058 end
2059
2060 setup do: clear_config([:instance, :limit_to_local_content])
2061
2062 test "allows getting remote users by id no matter what :limit_to_local_content is set to", %{
2063 remote_user: remote_user
2064 } do
2065 Pleroma.Config.put([:instance, :limit_to_local_content], false)
2066 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2067
2068 Pleroma.Config.put([:instance, :limit_to_local_content], true)
2069 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2070
2071 Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
2072 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2073 end
2074
2075 test "disallows getting remote users by nickname without authentication when :limit_to_local_content is set to :unauthenticated",
2076 %{remote_user: remote_user} do
2077 Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
2078 assert nil == User.get_cached_by_nickname_or_id(remote_user.nickname)
2079 end
2080
2081 test "allows getting remote users by nickname with authentication when :limit_to_local_content is set to :unauthenticated",
2082 %{remote_user: remote_user, local_user: local_user} do
2083 Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
2084 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.nickname, for: local_user)
2085 end
2086
2087 test "disallows getting remote users by nickname when :limit_to_local_content is set to true",
2088 %{remote_user: remote_user} do
2089 Pleroma.Config.put([:instance, :limit_to_local_content], true)
2090 assert nil == User.get_cached_by_nickname_or_id(remote_user.nickname)
2091 end
2092
2093 test "allows getting local users by nickname no matter what :limit_to_local_content is set to",
2094 %{local_user: local_user} do
2095 Pleroma.Config.put([:instance, :limit_to_local_content], false)
2096 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2097
2098 Pleroma.Config.put([:instance, :limit_to_local_content], true)
2099 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2100
2101 Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
2102 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2103 end
2104 end
2105
2106 describe "update_email_notifications/2" do
2107 setup do
2108 user = insert(:user, email_notifications: %{"digest" => true})
2109
2110 {:ok, user: user}
2111 end
2112
2113 test "Notifications are updated", %{user: user} do
2114 true = user.email_notifications["digest"]
2115 assert {:ok, result} = User.update_email_notifications(user, %{"digest" => false})
2116 assert result.email_notifications["digest"] == false
2117 end
2118 end
2119
2120 test "avatar fallback" do
2121 user = insert(:user)
2122 assert User.avatar_url(user) =~ "/images/avi.png"
2123
2124 clear_config([:assets, :default_user_avatar], "avatar.png")
2125
2126 user = User.get_cached_by_nickname_or_id(user.nickname)
2127 assert User.avatar_url(user) =~ "avatar.png"
2128
2129 assert User.avatar_url(user, no_default: true) == nil
2130 end
2131 end