Fork of Pleroma with site-specific changes and feature branches https://git.pleroma.social/pleroma/pleroma
No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.

464 líneas
12KB

  1. # Pleroma: A lightweight social networking server
  2. # Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
  3. # SPDX-License-Identifier: AGPL-3.0-only
  4. defmodule Mix.Tasks.Pleroma.User do
  5. use Mix.Task
  6. import Mix.Pleroma
  7. alias Ecto.Changeset
  8. alias Pleroma.User
  9. alias Pleroma.UserInviteToken
  10. alias Pleroma.Web.ActivityPub.Builder
  11. alias Pleroma.Web.ActivityPub.Pipeline
  12. @shortdoc "Manages Pleroma users"
  13. @moduledoc File.read!("docs/administration/CLI_tasks/user.md")
  14. def run(["new", nickname, email | rest]) do
  15. {options, [], []} =
  16. OptionParser.parse(
  17. rest,
  18. strict: [
  19. name: :string,
  20. bio: :string,
  21. password: :string,
  22. moderator: :boolean,
  23. admin: :boolean,
  24. assume_yes: :boolean
  25. ],
  26. aliases: [
  27. y: :assume_yes
  28. ]
  29. )
  30. name = Keyword.get(options, :name, nickname)
  31. bio = Keyword.get(options, :bio, "")
  32. {password, generated_password?} =
  33. case Keyword.get(options, :password) do
  34. nil ->
  35. {:crypto.strong_rand_bytes(16) |> Base.encode64(), true}
  36. password ->
  37. {password, false}
  38. end
  39. moderator? = Keyword.get(options, :moderator, false)
  40. admin? = Keyword.get(options, :admin, false)
  41. assume_yes? = Keyword.get(options, :assume_yes, false)
  42. shell_info("""
  43. A user will be created with the following information:
  44. - nickname: #{nickname}
  45. - email: #{email}
  46. - password: #{
  47. if(generated_password?, do: "[generated; a reset link will be created]", else: password)
  48. }
  49. - name: #{name}
  50. - bio: #{bio}
  51. - moderator: #{if(moderator?, do: "true", else: "false")}
  52. - admin: #{if(admin?, do: "true", else: "false")}
  53. """)
  54. proceed? = assume_yes? or shell_prompt("Continue?", "n") in ~w(Yn Y y)
  55. if proceed? do
  56. start_pleroma()
  57. params = %{
  58. nickname: nickname,
  59. email: email,
  60. password: password,
  61. password_confirmation: password,
  62. name: name,
  63. bio: bio
  64. }
  65. changeset = User.register_changeset(%User{}, params, need_confirmation: false)
  66. {:ok, _user} = User.register(changeset)
  67. shell_info("User #{nickname} created")
  68. if moderator? do
  69. run(["set", nickname, "--moderator"])
  70. end
  71. if admin? do
  72. run(["set", nickname, "--admin"])
  73. end
  74. if generated_password? do
  75. run(["reset_password", nickname])
  76. end
  77. else
  78. shell_info("User will not be created.")
  79. end
  80. end
  81. def run(["rm", nickname]) do
  82. start_pleroma()
  83. with %User{local: true} = user <- User.get_cached_by_nickname(nickname),
  84. {:ok, delete_data, _} <- Builder.delete(user, user.ap_id),
  85. {:ok, _delete, _} <- Pipeline.common_pipeline(delete_data, local: true) do
  86. shell_info("User #{nickname} deleted.")
  87. else
  88. _ -> shell_error("No local user #{nickname}")
  89. end
  90. end
  91. def run(["toggle_activated", nickname]) do
  92. start_pleroma()
  93. with %User{} = user <- User.get_cached_by_nickname(nickname) do
  94. {:ok, user} = User.deactivate(user, !user.deactivated)
  95. shell_info(
  96. "Activation status of #{nickname}: #{if(user.deactivated, do: "de", else: "")}activated"
  97. )
  98. else
  99. _ ->
  100. shell_error("No user #{nickname}")
  101. end
  102. end
  103. def run(["reset_password", nickname]) do
  104. start_pleroma()
  105. with %User{local: true} = user <- User.get_cached_by_nickname(nickname),
  106. {:ok, token} <- Pleroma.PasswordResetToken.create_token(user) do
  107. shell_info("Generated password reset token for #{user.nickname}")
  108. IO.puts(
  109. "URL: #{
  110. Pleroma.Web.Router.Helpers.reset_password_url(
  111. Pleroma.Web.Endpoint,
  112. :reset,
  113. token.token
  114. )
  115. }"
  116. )
  117. else
  118. _ ->
  119. shell_error("No local user #{nickname}")
  120. end
  121. end
  122. def run(["reset_mfa", nickname]) do
  123. start_pleroma()
  124. with %User{local: true} = user <- User.get_cached_by_nickname(nickname),
  125. {:ok, _token} <- Pleroma.MFA.disable(user) do
  126. shell_info("Multi-Factor Authentication disabled for #{user.nickname}")
  127. else
  128. _ ->
  129. shell_error("No local user #{nickname}")
  130. end
  131. end
  132. def run(["deactivate", nickname]) do
  133. start_pleroma()
  134. with %User{} = user <- User.get_cached_by_nickname(nickname) do
  135. shell_info("Deactivating #{user.nickname}")
  136. User.deactivate(user)
  137. :timer.sleep(500)
  138. user = User.get_cached_by_id(user.id)
  139. if Enum.empty?(Enum.filter(User.get_friends(user), & &1.local)) do
  140. shell_info("Successfully unsubscribed all local followers from #{user.nickname}")
  141. end
  142. else
  143. _ ->
  144. shell_error("No user #{nickname}")
  145. end
  146. end
  147. def run(["deactivate_all_from_instance", instance]) do
  148. start_pleroma()
  149. Pleroma.User.Query.build(%{nickname: "@#{instance}"})
  150. |> Pleroma.Repo.chunk_stream(500, :batches)
  151. |> Stream.each(fn users ->
  152. users
  153. |> Enum.each(fn user ->
  154. run(["deactivate", user.nickname])
  155. end)
  156. end)
  157. |> Stream.run()
  158. end
  159. def run(["set", nickname | rest]) do
  160. start_pleroma()
  161. {options, [], []} =
  162. OptionParser.parse(
  163. rest,
  164. strict: [
  165. admin: :boolean,
  166. confirmed: :boolean,
  167. locked: :boolean,
  168. moderator: :boolean
  169. ]
  170. )
  171. with %User{local: true} = user <- User.get_cached_by_nickname(nickname) do
  172. user =
  173. case Keyword.get(options, :admin) do
  174. nil -> user
  175. value -> set_admin(user, value)
  176. end
  177. user =
  178. case Keyword.get(options, :confirmed) do
  179. nil -> user
  180. value -> set_confirmed(user, value)
  181. end
  182. user =
  183. case Keyword.get(options, :locked) do
  184. nil -> user
  185. value -> set_locked(user, value)
  186. end
  187. _user =
  188. case Keyword.get(options, :moderator) do
  189. nil -> user
  190. value -> set_moderator(user, value)
  191. end
  192. else
  193. _ ->
  194. shell_error("No local user #{nickname}")
  195. end
  196. end
  197. def run(["tag", nickname | tags]) do
  198. start_pleroma()
  199. with %User{} = user <- User.get_cached_by_nickname(nickname) do
  200. user = user |> User.tag(tags)
  201. shell_info("Tags of #{user.nickname}: #{inspect(user.tags)}")
  202. else
  203. _ ->
  204. shell_error("Could not change user tags for #{nickname}")
  205. end
  206. end
  207. def run(["untag", nickname | tags]) do
  208. start_pleroma()
  209. with %User{} = user <- User.get_cached_by_nickname(nickname) do
  210. user = user |> User.untag(tags)
  211. shell_info("Tags of #{user.nickname}: #{inspect(user.tags)}")
  212. else
  213. _ ->
  214. shell_error("Could not change user tags for #{nickname}")
  215. end
  216. end
  217. def run(["invite" | rest]) do
  218. {options, [], []} =
  219. OptionParser.parse(rest,
  220. strict: [
  221. expires_at: :string,
  222. max_use: :integer
  223. ]
  224. )
  225. options =
  226. options
  227. |> Keyword.update(:expires_at, {:ok, nil}, fn
  228. nil -> {:ok, nil}
  229. val -> Date.from_iso8601(val)
  230. end)
  231. |> Enum.into(%{})
  232. start_pleroma()
  233. with {:ok, val} <- options[:expires_at],
  234. options = Map.put(options, :expires_at, val),
  235. {:ok, invite} <- UserInviteToken.create_invite(options) do
  236. shell_info("Generated user invite token " <> String.replace(invite.invite_type, "_", " "))
  237. url =
  238. Pleroma.Web.Router.Helpers.redirect_url(
  239. Pleroma.Web.Endpoint,
  240. :registration_page,
  241. invite.token
  242. )
  243. IO.puts(url)
  244. else
  245. error ->
  246. shell_error("Could not create invite token: #{inspect(error)}")
  247. end
  248. end
  249. def run(["invites"]) do
  250. start_pleroma()
  251. shell_info("Invites list:")
  252. UserInviteToken.list_invites()
  253. |> Enum.each(fn invite ->
  254. expire_info =
  255. with expires_at when not is_nil(expires_at) <- invite.expires_at do
  256. " | Expires at: #{Date.to_string(expires_at)}"
  257. end
  258. using_info =
  259. with max_use when not is_nil(max_use) <- invite.max_use do
  260. " | Max use: #{max_use} Left use: #{max_use - invite.uses}"
  261. end
  262. shell_info(
  263. "ID: #{invite.id} | Token: #{invite.token} | Token type: #{invite.invite_type} | Used: #{
  264. invite.used
  265. }#{expire_info}#{using_info}"
  266. )
  267. end)
  268. end
  269. def run(["revoke_invite", token]) do
  270. start_pleroma()
  271. with {:ok, invite} <- UserInviteToken.find_by_token(token),
  272. {:ok, _} <- UserInviteToken.update_invite(invite, %{used: true}) do
  273. shell_info("Invite for token #{token} was revoked.")
  274. else
  275. _ -> shell_error("No invite found with token #{token}")
  276. end
  277. end
  278. def run(["delete_activities", nickname]) do
  279. start_pleroma()
  280. with %User{local: true} = user <- User.get_cached_by_nickname(nickname) do
  281. User.delete_user_activities(user)
  282. shell_info("User #{nickname} statuses deleted.")
  283. else
  284. _ ->
  285. shell_error("No local user #{nickname}")
  286. end
  287. end
  288. def run(["confirm", nickname]) do
  289. start_pleroma()
  290. with %User{} = user <- User.get_cached_by_nickname(nickname) do
  291. {:ok, user} = User.confirm(user)
  292. message = if user.confirmation_pending, do: "needs", else: "doesn't need"
  293. shell_info("#{nickname} #{message} confirmation.")
  294. else
  295. _ ->
  296. shell_error("No local user #{nickname}")
  297. end
  298. end
  299. def run(["confirm_all"]) do
  300. start_pleroma()
  301. Pleroma.User.Query.build(%{
  302. local: true,
  303. deactivated: false,
  304. is_moderator: false,
  305. is_admin: false,
  306. invisible: false
  307. })
  308. |> Pleroma.Repo.chunk_stream(500, :batches)
  309. |> Stream.each(fn users ->
  310. users
  311. |> Enum.each(fn user -> User.need_confirmation(user, false) end)
  312. end)
  313. |> Stream.run()
  314. end
  315. def run(["unconfirm_all"]) do
  316. start_pleroma()
  317. Pleroma.User.Query.build(%{
  318. local: true,
  319. deactivated: false,
  320. is_moderator: false,
  321. is_admin: false,
  322. invisible: false
  323. })
  324. |> Pleroma.Repo.chunk_stream(500, :batches)
  325. |> Stream.each(fn users ->
  326. users
  327. |> Enum.each(fn user -> User.need_confirmation(user, true) end)
  328. end)
  329. |> Stream.run()
  330. end
  331. def run(["sign_out", nickname]) do
  332. start_pleroma()
  333. with %User{local: true} = user <- User.get_cached_by_nickname(nickname) do
  334. User.global_sign_out(user)
  335. shell_info("#{nickname} signed out from all apps.")
  336. else
  337. _ ->
  338. shell_error("No local user #{nickname}")
  339. end
  340. end
  341. def run(["list"]) do
  342. start_pleroma()
  343. Pleroma.User.Query.build(%{local: true})
  344. |> Pleroma.Repo.chunk_stream(500, :batches)
  345. |> Stream.each(fn users ->
  346. users
  347. |> Enum.each(fn user ->
  348. shell_info(
  349. "#{user.nickname} moderator: #{user.is_moderator}, admin: #{user.is_admin}, locked: #{
  350. user.is_locked
  351. }, deactivated: #{user.deactivated}"
  352. )
  353. end)
  354. end)
  355. |> Stream.run()
  356. end
  357. defp set_moderator(user, value) do
  358. {:ok, user} =
  359. user
  360. |> Changeset.change(%{is_moderator: value})
  361. |> User.update_and_set_cache()
  362. shell_info("Moderator status of #{user.nickname}: #{user.is_moderator}")
  363. user
  364. end
  365. defp set_admin(user, value) do
  366. {:ok, user} = User.admin_api_update(user, %{is_admin: value})
  367. shell_info("Admin status of #{user.nickname}: #{user.is_admin}")
  368. user
  369. end
  370. defp set_locked(user, value) do
  371. {:ok, user} =
  372. user
  373. |> Changeset.change(%{is_locked: value})
  374. |> User.update_and_set_cache()
  375. shell_info("Locked status of #{user.nickname}: #{user.is_locked}")
  376. user
  377. end
  378. defp set_confirmed(user, value) do
  379. {:ok, user} = User.need_confirmation(user, !value)
  380. shell_info("Confirmation pending status of #{user.nickname}: #{user.confirmation_pending}")
  381. user
  382. end
  383. end