user.ex 7.43 KB
Newer Older
Jorty's avatar
Jorty committed
1
2
defmodule Mix.Tasks.Pleroma.User do
  use Mix.Task
3
  import Ecto.Changeset
Jorty's avatar
Jorty committed
4
  alias Pleroma.{Repo, User}
5
  alias Mix.Tasks.Pleroma.Common
Jorty's avatar
Jorty committed
6
7
8
9
10
11
12
13
14
15
16
17
18
19

  @shortdoc "Manages Pleroma users"
  @moduledoc """
  Manages Pleroma users.

  ## Create a new user.

      mix pleroma.user new NICKNAME EMAIL [OPTION...]

  Options:
  - `--name NAME` - the user's name (i.e., "Lain Iwakura")
  - `--bio BIO` - the user's bio
  - `--password PASSWORD` - the user's password
  - `--moderator`/`--no-moderator` - whether the user is a moderator
20
  - `--admin`/`--no-admin` - whether the user is an admin
Rin Toshaka's avatar
Rin Toshaka committed
21

Rin Toshaka's avatar
Rin Toshaka committed
22
  ## Generate an invite link.
Maksim's avatar
Maksim committed
23

24
      mix pleroma.user invite
Jorty's avatar
Jorty committed
25
26
27
28
29
30
31
32

  ## Delete the user's account.

      mix pleroma.user rm NICKNAME

  ## Deactivate or activate the user's account.

      mix pleroma.user toggle_activated NICKNAME
rinpatch's avatar
Oops    
rinpatch committed
33

34
  ## Unsubscribe local users from user's account and deactivate it
Maksim's avatar
Maksim committed
35

36
      mix pleroma.user unsubscribe NICKNAME
Jorty's avatar
Jorty committed
37
38
39
40
41
42
43
44
45
46
47
48

  ## Create a password reset link.

      mix pleroma.user reset_password NICKNAME

  ## Set the value of the given user's settings.

      mix pleroma.user set NICKNAME [OPTION...]

  Options:
  - `--locked`/`--no-locked` - whether the user's account is locked
  - `--moderator`/`--no-moderator` - whether the user is a moderator
49
  - `--admin`/`--no-admin` - whether the user is an admin
Jorty's avatar
Jorty committed
50
51
52
53
54
55
56
57
58
  """
  def run(["new", nickname, email | rest]) do
    {options, [], []} =
      OptionParser.parse(
        rest,
        strict: [
          name: :string,
          bio: :string,
          password: :string,
59
60
          moderator: :boolean,
          admin: :boolean
Jorty's avatar
Jorty committed
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
        ]
      )

    name = Keyword.get(options, :name, nickname)
    bio = Keyword.get(options, :bio, "")

    {password, generated_password?} =
      case Keyword.get(options, :password) do
        nil ->
          {:crypto.strong_rand_bytes(16) |> Base.encode64(), true}

        password ->
          {password, false}
      end

    moderator? = Keyword.get(options, :moderator, false)
77
    admin? = Keyword.get(options, :admin, false)
Jorty's avatar
Jorty committed
78
79
80
81
82
83
84
85
86
87
88

    Mix.shell().info("""
    A user will be created with the following information:
      - nickname: #{nickname}
      - email: #{email}
      - password: #{
      if(generated_password?, do: "[generated; a reset link will be created]", else: password)
    }
      - name: #{name}
      - bio: #{bio}
      - moderator: #{if(moderator?, do: "true", else: "false")}
89
      - admin: #{if(admin?, do: "true", else: "false")}
Jorty's avatar
Jorty committed
90
91
92
93
94
    """)

    proceed? = Mix.shell().yes?("Continue?")

    unless not proceed? do
95
      Common.start_pleroma()
Jorty's avatar
Jorty committed
96

97
98
99
100
101
102
103
104
      params = %{
        nickname: nickname,
        email: email,
        password: password,
        password_confirmation: password,
        name: name,
        bio: bio
      }
Jorty's avatar
Jorty committed
105

106
107
      changeset = User.register_changeset(%User{}, params, confirmed: true)
      {:ok, _user} = User.register(changeset)
Jorty's avatar
Jorty committed
108
109
110
111
112
113
114

      Mix.shell().info("User #{nickname} created")

      if moderator? do
        run(["set", nickname, "--moderator"])
      end

115
116
117
118
      if admin? do
        run(["set", nickname, "--admin"])
      end

Jorty's avatar
Jorty committed
119
120
121
122
123
124
125
126
127
      if generated_password? do
        run(["reset_password", nickname])
      end
    else
      Mix.shell().info("User will not be created.")
    end
  end

  def run(["rm", nickname]) do
128
    Common.start_pleroma()
Jorty's avatar
Jorty committed
129
130
131

    with %User{local: true} = user <- User.get_by_nickname(nickname) do
      User.delete(user)
132
133
134
135
      Mix.shell().info("User #{nickname} deleted.")
    else
      _ ->
        Mix.shell().error("No local user #{nickname}")
Jorty's avatar
Jorty committed
136
137
138
139
    end
  end

  def run(["toggle_activated", nickname]) do
140
    Common.start_pleroma()
Jorty's avatar
Jorty committed
141

142
    with %User{} = user <- User.get_by_nickname(nickname) do
143
144
145
146
147
      {:ok, user} = User.deactivate(user, !user.info.deactivated)

      Mix.shell().info(
        "Activation status of #{nickname}: #{if(user.info.deactivated, do: "de", else: "")}activated"
      )
148
149
    else
      _ ->
150
        Mix.shell().error("No user #{nickname}")
Jorty's avatar
Jorty committed
151
152
153
154
    end
  end

  def run(["reset_password", nickname]) do
155
    Common.start_pleroma()
Jorty's avatar
Jorty committed
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173

    with %User{local: true} = user <- User.get_by_nickname(nickname),
         {:ok, token} <- Pleroma.PasswordResetToken.create_token(user) do
      Mix.shell().info("Generated password reset token for #{user.nickname}")

      IO.puts(
        "URL: #{
          Pleroma.Web.Router.Helpers.util_url(
            Pleroma.Web.Endpoint,
            :show_password_reset,
            token.token
          )
        }"
      )
    else
      _ ->
        Mix.shell().error("No local user #{nickname}")
    end
174
175
176
  end

  def run(["unsubscribe", nickname]) do
177
    Common.start_pleroma()
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202

    with %User{} = user <- User.get_by_nickname(nickname) do
      Mix.shell().info("Deactivating #{user.nickname}")
      User.deactivate(user)

      {:ok, friends} = User.get_friends(user)

      Enum.each(friends, fn friend ->
        user = Repo.get(User, user.id)

        Mix.shell().info("Unsubscribing #{friend.nickname} from #{user.nickname}")
        User.unfollow(user, friend)
      end)

      :timer.sleep(500)

      user = Repo.get(User, user.id)

      if length(user.following) == 0 do
        Mix.shell().info("Successfully unsubscribed all followers from #{user.nickname}")
      end
    else
      _ ->
        Mix.shell().error("No user #{nickname}")
    end
Jorty's avatar
Jorty committed
203
204
205
  end

  def run(["set", nickname | rest]) do
206
    Common.start_pleroma()
207

Jorty's avatar
Jorty committed
208
209
210
211
212
    {options, [], []} =
      OptionParser.parse(
        rest,
        strict: [
          moderator: :boolean,
213
          admin: :boolean,
Jorty's avatar
Jorty committed
214
215
216
217
218
          locked: :boolean
        ]
      )

    with %User{local: true} = user <- User.get_by_nickname(nickname) do
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
      user =
        case Keyword.get(options, :moderator) do
          nil -> user
          value -> set_moderator(user, value)
        end

      user =
        case Keyword.get(options, :locked) do
          nil -> user
          value -> set_locked(user, value)
        end

      _user =
        case Keyword.get(options, :admin) do
          nil -> user
          value -> set_admin(user, value)
        end
Jorty's avatar
Jorty committed
236
237
238
239
240
241
    else
      _ ->
        Mix.shell().error("No local user #{nickname}")
    end
  end

Maksim's avatar
Maksim committed
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
  def run(["invite"]) do
    Common.start_pleroma()

    with {:ok, token} <- Pleroma.UserInviteToken.create_token() do
      Mix.shell().info("Generated user invite token")

      url =
        Pleroma.Web.Router.Helpers.redirect_url(
          Pleroma.Web.Endpoint,
          :registration_page,
          token.token
        )

      IO.puts(url)
    else
      _ ->
        Mix.shell().error("Could not create invite token.")
    end
  end

262
  defp set_moderator(user, value) do
263
    info_cng = User.Info.admin_api_update(user.info, %{is_moderator: value})
Rin Toshaka's avatar
Rin Toshaka committed
264
265
266
267

    user_cng =
      Ecto.Changeset.change(user)
      |> put_embed(:info, info_cng)
268

269
270
271
    {:ok, user} = User.update_and_set_cache(user_cng)

    Mix.shell().info("Moderator status of #{user.nickname}: #{user.info.is_moderator}")
272
    user
273
  end
274

275
  defp set_admin(user, value) do
276
    info_cng = User.Info.admin_api_update(user.info, %{is_admin: value})
Rin Toshaka's avatar
Rin Toshaka committed
277
278
279
280

    user_cng =
      Ecto.Changeset.change(user)
      |> put_embed(:info, info_cng)
281
282

    {:ok, user} = User.update_and_set_cache(user_cng)
283

284
285
    Mix.shell().info("Admin status of #{user.nickname}: #{user.info.is_admin}")
    user
286
287
288
  end

  defp set_locked(user, value) do
289
    info_cng = User.Info.user_upgrade(user.info, %{locked: value})
Rin Toshaka's avatar
Rin Toshaka committed
290
291
292
293

    user_cng =
      Ecto.Changeset.change(user)
      |> put_embed(:info, info_cng)
294
295

    {:ok, user} = User.update_and_set_cache(user_cng)
296

297
    Mix.shell().info("Locked status of #{user.nickname}: #{user.info.locked}")
298
    user
299
  end
Jorty's avatar
Jorty committed
300
end