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