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