total rebase
[anni] / test / mix / tasks / pleroma / user_test.exs
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
5 defmodule Mix.Tasks.Pleroma.UserTest do
6   alias Pleroma.Activity
7   alias Pleroma.MFA
8   alias Pleroma.Object
9   alias Pleroma.Repo
10   alias Pleroma.Tests.ObanHelpers
11   alias Pleroma.User
12   alias Pleroma.Web.CommonAPI
13   alias Pleroma.Web.OAuth.Authorization
14   alias Pleroma.Web.OAuth.Token
15
16   use Pleroma.DataCase
17   use Oban.Testing, repo: Pleroma.Repo
18
19   import ExUnit.CaptureIO
20   import Mock
21   import Pleroma.Factory
22
23   setup do
24     Mox.stub_with(Pleroma.UnstubbedConfigMock, Pleroma.Config)
25     :ok
26   end
27
28   setup_all do
29     Mix.shell(Mix.Shell.Process)
30
31     on_exit(fn ->
32       Mix.shell(Mix.Shell.IO)
33     end)
34
35     :ok
36   end
37
38   describe "running new" do
39     test "user is created" do
40       # just get random data
41       unsaved = build(:user)
42
43       # prepare to answer yes
44       send(self(), {:mix_shell_input, :prompt, "Y"})
45
46       Mix.Tasks.Pleroma.User.run([
47         "new",
48         unsaved.nickname,
49         unsaved.email,
50         "--name",
51         unsaved.name,
52         "--bio",
53         unsaved.bio,
54         "--password",
55         "test",
56         "--moderator",
57         "--admin"
58       ])
59
60       assert_received {:mix_shell, :info, [message]}
61       assert message =~ "user will be created"
62
63       assert_received {:mix_shell, :prompt, [message]}
64       assert message =~ "Continue"
65
66       assert_received {:mix_shell, :info, [message]}
67       assert message =~ "created"
68
69       user = User.get_cached_by_nickname(unsaved.nickname)
70       assert user.name == unsaved.name
71       assert user.email == unsaved.email
72       assert user.bio == unsaved.bio
73       assert user.is_moderator
74       assert user.is_admin
75     end
76
77     test "user is not created" do
78       unsaved = build(:user)
79
80       # prepare to answer no
81       send(self(), {:mix_shell_input, :prompt, "N"})
82
83       Mix.Tasks.Pleroma.User.run(["new", unsaved.nickname, unsaved.email])
84
85       assert_received {:mix_shell, :info, [message]}
86       assert message =~ "user will be created"
87
88       assert_received {:mix_shell, :prompt, [message]}
89       assert message =~ "Continue"
90
91       assert_received {:mix_shell, :info, [message]}
92       assert message =~ "will not be created"
93
94       refute User.get_cached_by_nickname(unsaved.nickname)
95     end
96   end
97
98   describe "running rm" do
99     test "user is deleted" do
100       clear_config([:instance, :federating], true)
101       user = insert(:user)
102
103       with_mock Pleroma.Web.Federator,
104         publish: fn _ -> nil end do
105         Mix.Tasks.Pleroma.User.run(["rm", user.nickname])
106         ObanHelpers.perform_all()
107
108         assert_received {:mix_shell, :info, [message]}
109         assert message =~ " deleted"
110         assert %{is_active: false} = User.get_by_nickname(user.nickname)
111
112         assert called(Pleroma.Web.Federator.publish(:_))
113       end
114     end
115
116     test "a remote user's create activity is deleted when the object has been pruned" do
117       user = insert(:user)
118       user2 = insert(:user)
119
120       {:ok, post} = CommonAPI.post(user, %{status: "uguu"})
121       {:ok, post2} = CommonAPI.post(user2, %{status: "test"})
122       obj = Object.normalize(post2, fetch: false)
123
124       {:ok, like_object, meta} = Pleroma.Web.ActivityPub.Builder.like(user, obj)
125
126       {:ok, like_activity, _meta} =
127         Pleroma.Web.ActivityPub.Pipeline.common_pipeline(
128           like_object,
129           Keyword.put(meta, :local, true)
130         )
131
132       like_activity.data["object"]
133       |> Pleroma.Object.get_by_ap_id()
134       |> Repo.delete()
135
136       clear_config([:instance, :federating], true)
137
138       object = Object.normalize(post, fetch: false)
139       Object.prune(object)
140
141       with_mock Pleroma.Web.Federator,
142         publish: fn _ -> nil end do
143         Mix.Tasks.Pleroma.User.run(["rm", user.nickname])
144         ObanHelpers.perform_all()
145
146         assert_received {:mix_shell, :info, [message]}
147         assert message =~ " deleted"
148         assert %{is_active: false} = User.get_by_nickname(user.nickname)
149
150         assert called(Pleroma.Web.Federator.publish(:_))
151         refute Pleroma.Repo.get(Pleroma.Activity, like_activity.id)
152       end
153
154       refute Activity.get_by_id(post.id)
155     end
156
157     test "no user to delete" do
158       Mix.Tasks.Pleroma.User.run(["rm", "nonexistent"])
159
160       assert_received {:mix_shell, :error, [message]}
161       assert message =~ "No local user"
162     end
163   end
164
165   describe "running deactivate" do
166     test "active user is deactivated and unsubscribed" do
167       followed = insert(:user)
168       remote_followed = insert(:user, local: false)
169       user = insert(:user)
170
171       User.follow(user, followed, :follow_accept)
172       User.follow(user, remote_followed, :follow_accept)
173
174       Mix.Tasks.Pleroma.User.run(["deactivate", user.nickname])
175
176       # Note that the task has delay :timer.sleep(500)
177       assert_received {:mix_shell, :info, [message]}
178
179       assert message ==
180                "Successfully deactivated #{user.nickname} and unsubscribed all local followers"
181
182       user = User.get_cached_by_nickname(user.nickname)
183       assert Enum.empty?(Enum.filter(User.get_friends(user), & &1.local))
184       refute user.is_active
185     end
186
187     test "user is deactivated" do
188       %{id: id, nickname: nickname} = insert(:user, is_active: false)
189
190       assert :ok = Mix.Tasks.Pleroma.User.run(["deactivate", nickname])
191       assert_received {:mix_shell, :info, [message]}
192       assert message == "User #{nickname} already deactivated"
193
194       user = Repo.get(User, id)
195       refute user.is_active
196     end
197
198     test "no user to deactivate" do
199       Mix.Tasks.Pleroma.User.run(["deactivate", "nonexistent"])
200
201       assert_received {:mix_shell, :error, [message]}
202       assert message =~ "No user"
203     end
204   end
205
206   describe "running set" do
207     test "All statuses set" do
208       user = insert(:user)
209
210       Mix.Tasks.Pleroma.User.run([
211         "set",
212         user.nickname,
213         "--admin",
214         "--confirmed",
215         "--locked",
216         "--moderator"
217       ])
218
219       assert_received {:mix_shell, :info, [message]}
220       assert message =~ ~r/Admin status .* true/
221
222       assert_received {:mix_shell, :info, [message]}
223       assert message =~ ~r/Confirmation status.* true/
224
225       assert_received {:mix_shell, :info, [message]}
226       assert message =~ ~r/Locked status .* true/
227
228       assert_received {:mix_shell, :info, [message]}
229       assert message =~ ~r/Moderator status .* true/
230
231       user = User.get_cached_by_nickname(user.nickname)
232       assert user.is_moderator
233       assert user.is_locked
234       assert user.is_admin
235       assert user.is_confirmed
236     end
237
238     test "All statuses unset" do
239       user =
240         insert(:user,
241           is_locked: true,
242           is_moderator: true,
243           is_admin: true,
244           is_confirmed: false
245         )
246
247       Mix.Tasks.Pleroma.User.run([
248         "set",
249         user.nickname,
250         "--no-admin",
251         "--no-confirmed",
252         "--no-locked",
253         "--no-moderator"
254       ])
255
256       assert_received {:mix_shell, :info, [message]}
257       assert message =~ ~r/Admin status .* false/
258
259       assert_received {:mix_shell, :info, [message]}
260       assert message =~ ~r/Confirmation status.* false/
261
262       assert_received {:mix_shell, :info, [message]}
263       assert message =~ ~r/Locked status .* false/
264
265       assert_received {:mix_shell, :info, [message]}
266       assert message =~ ~r/Moderator status .* false/
267
268       user = User.get_cached_by_nickname(user.nickname)
269       refute user.is_moderator
270       refute user.is_locked
271       refute user.is_admin
272       refute user.is_confirmed
273     end
274
275     test "no user to set status" do
276       Mix.Tasks.Pleroma.User.run(["set", "nonexistent", "--moderator"])
277
278       assert_received {:mix_shell, :error, [message]}
279       assert message =~ "No local user"
280     end
281   end
282
283   describe "running reset_password" do
284     test "password reset token is generated" do
285       user = insert(:user)
286
287       assert capture_io(fn ->
288                Mix.Tasks.Pleroma.User.run(["reset_password", user.nickname])
289              end) =~ "URL:"
290
291       assert_received {:mix_shell, :info, [message]}
292       assert message =~ "Generated"
293     end
294
295     test "no user to reset password" do
296       Mix.Tasks.Pleroma.User.run(["reset_password", "nonexistent"])
297
298       assert_received {:mix_shell, :error, [message]}
299       assert message =~ "No local user"
300     end
301   end
302
303   describe "running reset_mfa" do
304     test "disables MFA" do
305       user =
306         insert(:user,
307           multi_factor_authentication_settings: %MFA.Settings{
308             enabled: true,
309             totp: %MFA.Settings.TOTP{secret: "xx", confirmed: true}
310           }
311         )
312
313       Mix.Tasks.Pleroma.User.run(["reset_mfa", user.nickname])
314
315       assert_received {:mix_shell, :info, [message]}
316       assert message == "Multi-Factor Authentication disabled for #{user.nickname}"
317
318       assert %{enabled: false, totp: false} ==
319                user.nickname
320                |> User.get_cached_by_nickname()
321                |> MFA.mfa_settings()
322     end
323
324     test "no user to reset MFA" do
325       Mix.Tasks.Pleroma.User.run(["reset_password", "nonexistent"])
326
327       assert_received {:mix_shell, :error, [message]}
328       assert message =~ "No local user"
329     end
330   end
331
332   describe "running invite" do
333     test "invite token is generated" do
334       assert capture_io(fn ->
335                Mix.Tasks.Pleroma.User.run(["invite"])
336              end) =~ "http"
337
338       assert_received {:mix_shell, :info, [message]}
339       assert message =~ "Generated user invite token one time"
340     end
341
342     test "token is generated with expires_at" do
343       assert capture_io(fn ->
344                Mix.Tasks.Pleroma.User.run([
345                  "invite",
346                  "--expires-at",
347                  Date.to_string(Date.utc_today())
348                ])
349              end)
350
351       assert_received {:mix_shell, :info, [message]}
352       assert message =~ "Generated user invite token date limited"
353     end
354
355     test "token is generated with max use" do
356       assert capture_io(fn ->
357                Mix.Tasks.Pleroma.User.run([
358                  "invite",
359                  "--max-use",
360                  "5"
361                ])
362              end)
363
364       assert_received {:mix_shell, :info, [message]}
365       assert message =~ "Generated user invite token reusable"
366     end
367
368     test "token is generated with max use and expires date" do
369       assert capture_io(fn ->
370                Mix.Tasks.Pleroma.User.run([
371                  "invite",
372                  "--max-use",
373                  "5",
374                  "--expires-at",
375                  Date.to_string(Date.utc_today())
376                ])
377              end)
378
379       assert_received {:mix_shell, :info, [message]}
380       assert message =~ "Generated user invite token reusable date limited"
381     end
382   end
383
384   describe "running invites" do
385     test "invites are listed" do
386       {:ok, invite} = Pleroma.UserInviteToken.create_invite()
387
388       {:ok, invite2} =
389         Pleroma.UserInviteToken.create_invite(%{expires_at: Date.utc_today(), max_use: 15})
390
391       # assert capture_io(fn ->
392       Mix.Tasks.Pleroma.User.run([
393         "invites"
394       ])
395
396       #  end)
397
398       assert_received {:mix_shell, :info, [message]}
399       assert_received {:mix_shell, :info, [message2]}
400       assert_received {:mix_shell, :info, [message3]}
401       assert message =~ "Invites list:"
402       assert message2 =~ invite.invite_type
403       assert message3 =~ invite2.invite_type
404     end
405   end
406
407   describe "running revoke_invite" do
408     test "invite is revoked" do
409       {:ok, invite} = Pleroma.UserInviteToken.create_invite(%{expires_at: Date.utc_today()})
410
411       assert capture_io(fn ->
412                Mix.Tasks.Pleroma.User.run([
413                  "revoke_invite",
414                  invite.token
415                ])
416              end)
417
418       assert_received {:mix_shell, :info, [message]}
419       assert message =~ "Invite for token #{invite.token} was revoked."
420     end
421   end
422
423   describe "running delete_activities" do
424     test "activities are deleted" do
425       %{nickname: nickname} = insert(:user)
426
427       assert :ok == Mix.Tasks.Pleroma.User.run(["delete_activities", nickname])
428       assert_received {:mix_shell, :info, [message]}
429       assert message == "User #{nickname} statuses deleted."
430     end
431
432     test "it prints an error message when user is not exist" do
433       Mix.Tasks.Pleroma.User.run(["delete_activities", "foo"])
434
435       assert_received {:mix_shell, :error, [message]}
436       assert message =~ "No local user"
437     end
438   end
439
440   describe "running confirm" do
441     test "user is confirmed" do
442       %{id: id, nickname: nickname} = insert(:user, is_confirmed: true)
443
444       assert :ok = Mix.Tasks.Pleroma.User.run(["confirm", nickname])
445       assert_received {:mix_shell, :info, [message]}
446       assert message == "#{nickname} doesn't need confirmation."
447
448       user = Repo.get(User, id)
449       assert user.is_confirmed
450       refute user.confirmation_token
451     end
452
453     test "user is not confirmed" do
454       %{id: id, nickname: nickname} =
455         insert(:user, is_confirmed: false, confirmation_token: "some token")
456
457       assert :ok = Mix.Tasks.Pleroma.User.run(["confirm", nickname])
458       assert_received {:mix_shell, :info, [message]}
459       assert message == "#{nickname} doesn't need confirmation."
460
461       user = Repo.get(User, id)
462       assert user.is_confirmed
463       refute user.confirmation_token
464     end
465
466     test "it prints an error message when user is not exist" do
467       Mix.Tasks.Pleroma.User.run(["confirm", "foo"])
468
469       assert_received {:mix_shell, :error, [message]}
470       assert message =~ "No local user"
471     end
472   end
473
474   describe "running activate" do
475     test "user is activated" do
476       %{id: id, nickname: nickname} = insert(:user, is_active: true)
477
478       assert :ok = Mix.Tasks.Pleroma.User.run(["activate", nickname])
479       assert_received {:mix_shell, :info, [message]}
480       assert message == "User #{nickname} already activated"
481
482       user = Repo.get(User, id)
483       assert user.is_active
484     end
485
486     test "user is not activated" do
487       %{id: id, nickname: nickname} = insert(:user, is_active: false)
488
489       assert :ok = Mix.Tasks.Pleroma.User.run(["activate", nickname])
490       assert_received {:mix_shell, :info, [message]}
491       assert message == "Successfully activated #{nickname}"
492
493       user = Repo.get(User, id)
494       assert user.is_active
495     end
496
497     test "no user to activate" do
498       Mix.Tasks.Pleroma.User.run(["activate", "foo"])
499
500       assert_received {:mix_shell, :error, [message]}
501       assert message =~ "No user"
502     end
503   end
504
505   describe "search" do
506     test "it returns users matching" do
507       user = insert(:user)
508       moon = insert(:user, nickname: "moon", name: "fediverse expert moon")
509       moot = insert(:user, nickname: "moot")
510       kawen = insert(:user, nickname: "kawen", name: "fediverse expert moon")
511
512       {:ok, user, moon} = User.follow(user, moon)
513
514       assert [moon.id, kawen.id] == User.Search.search("moon") |> Enum.map(& &1.id)
515
516       res = User.search("moo") |> Enum.map(& &1.id)
517       assert Enum.sort([moon.id, moot.id, kawen.id]) == Enum.sort(res)
518
519       assert [kawen.id, moon.id] == User.Search.search("expert fediverse") |> Enum.map(& &1.id)
520
521       assert [moon.id, kawen.id] ==
522                User.Search.search("expert fediverse", for_user: user) |> Enum.map(& &1.id)
523     end
524   end
525
526   describe "signing out" do
527     test "it deletes all user's tokens and authorizations" do
528       user = insert(:user)
529       insert(:oauth_token, user: user)
530       insert(:oauth_authorization, user: user)
531
532       assert Repo.get_by(Token, user_id: user.id)
533       assert Repo.get_by(Authorization, user_id: user.id)
534
535       :ok = Mix.Tasks.Pleroma.User.run(["sign_out", user.nickname])
536
537       refute Repo.get_by(Token, user_id: user.id)
538       refute Repo.get_by(Authorization, user_id: user.id)
539     end
540
541     test "it prints an error message when user is not exist" do
542       Mix.Tasks.Pleroma.User.run(["sign_out", "foo"])
543
544       assert_received {:mix_shell, :error, [message]}
545       assert message =~ "No local user"
546     end
547   end
548
549   describe "tagging" do
550     test "it add tags to a user" do
551       user = insert(:user)
552
553       :ok = Mix.Tasks.Pleroma.User.run(["tag", user.nickname, "pleroma"])
554
555       user = User.get_cached_by_nickname(user.nickname)
556       assert "pleroma" in user.tags
557     end
558
559     test "it prints an error message when user is not exist" do
560       Mix.Tasks.Pleroma.User.run(["tag", "foo"])
561
562       assert_received {:mix_shell, :error, [message]}
563       assert message =~ "Could not change user tags"
564     end
565   end
566
567   describe "untagging" do
568     test "it deletes tags from a user" do
569       user = insert(:user, tags: ["pleroma"])
570       assert "pleroma" in user.tags
571
572       :ok = Mix.Tasks.Pleroma.User.run(["untag", user.nickname, "pleroma"])
573
574       user = User.get_cached_by_nickname(user.nickname)
575       assert Enum.empty?(user.tags)
576     end
577
578     test "it prints an error message when user is not exist" do
579       Mix.Tasks.Pleroma.User.run(["untag", "foo"])
580
581       assert_received {:mix_shell, :error, [message]}
582       assert message =~ "Could not change user tags"
583     end
584   end
585
586   describe "bulk confirm and unconfirm" do
587     test "confirm all" do
588       user1 = insert(:user, is_confirmed: false)
589       user2 = insert(:user, is_confirmed: false)
590
591       refute user1.is_confirmed
592       refute user2.is_confirmed
593
594       Mix.Tasks.Pleroma.User.run(["confirm_all"])
595
596       user1 = User.get_cached_by_nickname(user1.nickname)
597       user2 = User.get_cached_by_nickname(user2.nickname)
598
599       assert user1.is_confirmed
600       assert user2.is_confirmed
601     end
602
603     test "unconfirm all" do
604       user1 = insert(:user, is_confirmed: true)
605       user2 = insert(:user, is_confirmed: true)
606       admin = insert(:user, is_admin: true, is_confirmed: true)
607       mod = insert(:user, is_moderator: true, is_confirmed: true)
608
609       assert user1.is_confirmed
610       assert user2.is_confirmed
611
612       Mix.Tasks.Pleroma.User.run(["unconfirm_all"])
613
614       user1 = User.get_cached_by_nickname(user1.nickname)
615       user2 = User.get_cached_by_nickname(user2.nickname)
616       admin = User.get_cached_by_nickname(admin.nickname)
617       mod = User.get_cached_by_nickname(mod.nickname)
618
619       refute user1.is_confirmed
620       refute user2.is_confirmed
621       assert admin.is_confirmed
622       assert mod.is_confirmed
623     end
624   end
625 end