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