Fork of Pleroma with site-specific changes and feature branches https://git.pleroma.social/pleroma/pleroma
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

470 lignes
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, is_confirmed: true)
  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(["reset_password", nickname]) do
  92. start_pleroma()
  93. with %User{local: true} = user <- User.get_cached_by_nickname(nickname),
  94. {:ok, token} <- Pleroma.PasswordResetToken.create_token(user) do
  95. shell_info("Generated password reset token for #{user.nickname}")
  96. IO.puts(
  97. "URL: #{
  98. Pleroma.Web.Router.Helpers.reset_password_url(
  99. Pleroma.Web.Endpoint,
  100. :reset,
  101. token.token
  102. )
  103. }"
  104. )
  105. else
  106. _ ->
  107. shell_error("No local user #{nickname}")
  108. end
  109. end
  110. def run(["reset_mfa", nickname]) do
  111. start_pleroma()
  112. with %User{local: true} = user <- User.get_cached_by_nickname(nickname),
  113. {:ok, _token} <- Pleroma.MFA.disable(user) do
  114. shell_info("Multi-Factor Authentication disabled for #{user.nickname}")
  115. else
  116. _ ->
  117. shell_error("No local user #{nickname}")
  118. end
  119. end
  120. def run(["activate", nickname]) do
  121. start_pleroma()
  122. with %User{} = user <- User.get_cached_by_nickname(nickname),
  123. false <- user.is_active do
  124. User.set_activation(user, true)
  125. :timer.sleep(500)
  126. shell_info("Successfully activated #{nickname}")
  127. else
  128. true ->
  129. shell_info("User #{nickname} already activated")
  130. _ ->
  131. shell_error("No user #{nickname}")
  132. end
  133. end
  134. def run(["deactivate", nickname]) do
  135. start_pleroma()
  136. with %User{} = user <- User.get_cached_by_nickname(nickname),
  137. true <- user.is_active do
  138. User.set_activation(user, false)
  139. :timer.sleep(500)
  140. user = User.get_cached_by_id(user.id)
  141. if Enum.empty?(Enum.filter(User.get_friends(user), & &1.local)) do
  142. shell_info("Successfully deactivated #{nickname} and unsubscribed all local followers")
  143. end
  144. else
  145. false ->
  146. shell_info("User #{nickname} already deactivated")
  147. _ ->
  148. shell_error("No user #{nickname}")
  149. end
  150. end
  151. def run(["deactivate_all_from_instance", instance]) do
  152. start_pleroma()
  153. Pleroma.User.Query.build(%{nickname: "@#{instance}"})
  154. |> Pleroma.Repo.chunk_stream(500, :batches)
  155. |> Stream.each(fn users ->
  156. users
  157. |> Enum.each(fn user ->
  158. run(["deactivate", user.nickname])
  159. end)
  160. end)
  161. |> Stream.run()
  162. end
  163. def run(["set", nickname | rest]) do
  164. start_pleroma()
  165. {options, [], []} =
  166. OptionParser.parse(
  167. rest,
  168. strict: [
  169. admin: :boolean,
  170. confirmed: :boolean,
  171. locked: :boolean,
  172. moderator: :boolean
  173. ]
  174. )
  175. with %User{local: true} = user <- User.get_cached_by_nickname(nickname) do
  176. user =
  177. case Keyword.get(options, :admin) do
  178. nil -> user
  179. value -> set_admin(user, value)
  180. end
  181. user =
  182. case Keyword.get(options, :confirmed) do
  183. nil -> user
  184. value -> set_confirmation(user, value)
  185. end
  186. user =
  187. case Keyword.get(options, :locked) do
  188. nil -> user
  189. value -> set_locked(user, value)
  190. end
  191. _user =
  192. case Keyword.get(options, :moderator) do
  193. nil -> user
  194. value -> set_moderator(user, value)
  195. end
  196. else
  197. _ ->
  198. shell_error("No local user #{nickname}")
  199. end
  200. end
  201. def run(["tag", nickname | tags]) do
  202. start_pleroma()
  203. with %User{} = user <- User.get_cached_by_nickname(nickname) do
  204. user = user |> User.tag(tags)
  205. shell_info("Tags of #{user.nickname}: #{inspect(user.tags)}")
  206. else
  207. _ ->
  208. shell_error("Could not change user tags for #{nickname}")
  209. end
  210. end
  211. def run(["untag", nickname | tags]) do
  212. start_pleroma()
  213. with %User{} = user <- User.get_cached_by_nickname(nickname) do
  214. user = user |> User.untag(tags)
  215. shell_info("Tags of #{user.nickname}: #{inspect(user.tags)}")
  216. else
  217. _ ->
  218. shell_error("Could not change user tags for #{nickname}")
  219. end
  220. end
  221. def run(["invite" | rest]) do
  222. {options, [], []} =
  223. OptionParser.parse(rest,
  224. strict: [
  225. expires_at: :string,
  226. max_use: :integer
  227. ]
  228. )
  229. options =
  230. options
  231. |> Keyword.update(:expires_at, {:ok, nil}, fn
  232. nil -> {:ok, nil}
  233. val -> Date.from_iso8601(val)
  234. end)
  235. |> Enum.into(%{})
  236. start_pleroma()
  237. with {:ok, val} <- options[:expires_at],
  238. options = Map.put(options, :expires_at, val),
  239. {:ok, invite} <- UserInviteToken.create_invite(options) do
  240. shell_info("Generated user invite token " <> String.replace(invite.invite_type, "_", " "))
  241. url =
  242. Pleroma.Web.Router.Helpers.redirect_url(
  243. Pleroma.Web.Endpoint,
  244. :registration_page,
  245. invite.token
  246. )
  247. IO.puts(url)
  248. else
  249. error ->
  250. shell_error("Could not create invite token: #{inspect(error)}")
  251. end
  252. end
  253. def run(["invites"]) do
  254. start_pleroma()
  255. shell_info("Invites list:")
  256. UserInviteToken.list_invites()
  257. |> Enum.each(fn invite ->
  258. expire_info =
  259. with expires_at when not is_nil(expires_at) <- invite.expires_at do
  260. " | Expires at: #{Date.to_string(expires_at)}"
  261. end
  262. using_info =
  263. with max_use when not is_nil(max_use) <- invite.max_use do
  264. " | Max use: #{max_use} Left use: #{max_use - invite.uses}"
  265. end
  266. shell_info(
  267. "ID: #{invite.id} | Token: #{invite.token} | Token type: #{invite.invite_type} | Used: #{
  268. invite.used
  269. }#{expire_info}#{using_info}"
  270. )
  271. end)
  272. end
  273. def run(["revoke_invite", token]) do
  274. start_pleroma()
  275. with {:ok, invite} <- UserInviteToken.find_by_token(token),
  276. {:ok, _} <- UserInviteToken.update_invite(invite, %{used: true}) do
  277. shell_info("Invite for token #{token} was revoked.")
  278. else
  279. _ -> shell_error("No invite found with token #{token}")
  280. end
  281. end
  282. def run(["delete_activities", nickname]) do
  283. start_pleroma()
  284. with %User{local: true} = user <- User.get_cached_by_nickname(nickname) do
  285. User.delete_user_activities(user)
  286. shell_info("User #{nickname} statuses deleted.")
  287. else
  288. _ ->
  289. shell_error("No local user #{nickname}")
  290. end
  291. end
  292. def run(["confirm", nickname]) do
  293. start_pleroma()
  294. with %User{} = user <- User.get_cached_by_nickname(nickname) do
  295. {:ok, user} = User.confirm(user)
  296. message = if !user.is_confirmed, do: "needs", else: "doesn't need"
  297. shell_info("#{nickname} #{message} confirmation.")
  298. else
  299. _ ->
  300. shell_error("No local user #{nickname}")
  301. end
  302. end
  303. def run(["confirm_all"]) do
  304. start_pleroma()
  305. Pleroma.User.Query.build(%{
  306. local: true,
  307. is_active: true,
  308. is_moderator: false,
  309. is_admin: false,
  310. invisible: false
  311. })
  312. |> Pleroma.Repo.chunk_stream(500, :batches)
  313. |> Stream.each(fn users ->
  314. users
  315. |> Enum.each(fn user -> User.set_confirmation(user, true) end)
  316. end)
  317. |> Stream.run()
  318. end
  319. def run(["unconfirm_all"]) do
  320. start_pleroma()
  321. Pleroma.User.Query.build(%{
  322. local: true,
  323. is_active: true,
  324. is_moderator: false,
  325. is_admin: false,
  326. invisible: false
  327. })
  328. |> Pleroma.Repo.chunk_stream(500, :batches)
  329. |> Stream.each(fn users ->
  330. users
  331. |> Enum.each(fn user -> User.set_confirmation(user, false) end)
  332. end)
  333. |> Stream.run()
  334. end
  335. def run(["sign_out", nickname]) do
  336. start_pleroma()
  337. with %User{local: true} = user <- User.get_cached_by_nickname(nickname) do
  338. User.global_sign_out(user)
  339. shell_info("#{nickname} signed out from all apps.")
  340. else
  341. _ ->
  342. shell_error("No local user #{nickname}")
  343. end
  344. end
  345. def run(["list"]) do
  346. start_pleroma()
  347. Pleroma.User.Query.build(%{local: true})
  348. |> Pleroma.Repo.chunk_stream(500, :batches)
  349. |> Stream.each(fn users ->
  350. users
  351. |> Enum.each(fn user ->
  352. shell_info(
  353. "#{user.nickname} moderator: #{user.is_moderator}, admin: #{user.is_admin}, locked: #{
  354. user.is_locked
  355. }, is_active: #{user.is_active}"
  356. )
  357. end)
  358. end)
  359. |> Stream.run()
  360. end
  361. defp set_moderator(user, value) do
  362. {:ok, user} =
  363. user
  364. |> Changeset.change(%{is_moderator: value})
  365. |> User.update_and_set_cache()
  366. shell_info("Moderator status of #{user.nickname}: #{user.is_moderator}")
  367. user
  368. end
  369. defp set_admin(user, value) do
  370. {:ok, user} = User.admin_api_update(user, %{is_admin: value})
  371. shell_info("Admin status of #{user.nickname}: #{user.is_admin}")
  372. user
  373. end
  374. defp set_locked(user, value) do
  375. {:ok, user} =
  376. user
  377. |> Changeset.change(%{is_locked: value})
  378. |> User.update_and_set_cache()
  379. shell_info("Locked status of #{user.nickname}: #{user.is_locked}")
  380. user
  381. end
  382. defp set_confirmation(user, value) do
  383. {:ok, user} = User.set_confirmation(user, value)
  384. shell_info("Confirmation status of #{user.nickname}: #{user.is_confirmed}")
  385. user
  386. end
  387. end