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