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