Added mix commands to manage users and view actors

Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
Thomas Citharel
2019-11-21 15:51:13 +01:00
parent 359bbe5449
commit 5e9c91e659
11 changed files with 542 additions and 9 deletions

View File

@@ -0,0 +1,34 @@
defmodule Mix.Tasks.Mobilizon.Actors.Show do
@moduledoc """
Task to display an actor details
"""
use Mix.Task
alias Mobilizon.Actors
alias Mobilizon.Actors.Actor
@shortdoc "Show a Mobilizon user details"
@impl Mix.Task
def run([preferred_username]) do
Mix.Task.run("app.start")
case {:actor, Actors.get_actor_by_name_with_preload(preferred_username)} do
{:actor, %Actor{} = actor} ->
Mix.shell().info("""
Informations for the actor #{actor.preferred_username}:
- Type: #{actor.type}
- Domain: #{if is_nil(actor.domain), do: "Local", else: actor.domain}
- Name: #{actor.name}
- Summary: #{actor.summary}
- User: #{if is_nil(actor.user), do: "Remote", else: actor.user.email}
""")
{:actor, nil} ->
Mix.raise("Error: No such actor")
end
end
def run(_) do
Mix.raise("mobilizon.actors.show requires an username as argument")
end
end

View File

@@ -0,0 +1,14 @@
defmodule Mix.Tasks.Mobilizon.Users do
@moduledoc """
Tasks to manage users
"""
use Mix.Task
@shortdoc "Manages Mobilizon users"
@impl Mix.Task
def run(_) do
Mix.shell().info("\nAvailable tasks:")
Mix.Tasks.Help.run(["--search", "mobilizon.users."])
end
end

View File

@@ -0,0 +1,47 @@
defmodule Mix.Tasks.Mobilizon.Users.Delete do
@moduledoc """
Task to delete a user
"""
use Mix.Task
alias Mobilizon.Users
alias Mobilizon.Users.User
@shortdoc "Deletes a Mobilizon user"
@impl Mix.Task
def run([email | rest]) do
{options, [], []} =
OptionParser.parse(
rest,
strict: [
assume_yes: :boolean
],
aliases: [
y: :assume_yes
]
)
assume_yes? = Keyword.get(options, :assume_yes, false)
Mix.Task.run("app.start")
with {:ok, %User{} = user} <- Users.get_user_by_email(email),
true <- assume_yes? or Mix.shell().yes?("Continue with deleting user #{user.email}?"),
{:ok, %User{} = user} <-
Users.delete_user(user) do
Mix.shell().info("""
The user #{user.email} has been deleted
""")
else
{:error, :user_not_found} ->
Mix.raise("Error: No such user")
_ ->
Mix.raise("User has not been deleted.")
end
end
def run(_) do
Mix.raise("mobilizon.users.delete requires an email as argument")
end
end

View File

@@ -0,0 +1,102 @@
defmodule Mix.Tasks.Mobilizon.Users.Modify do
@moduledoc """
Task to modify an existing Mobilizon user
"""
use Mix.Task
alias Mobilizon.Users
alias Mobilizon.Users.User
@shortdoc "Modify a Mobilizon user"
@impl Mix.Task
def run([email | rest]) do
{options, [], []} =
OptionParser.parse(
rest,
strict: [
email: :string,
disable: :boolean,
enable: :boolean,
user: :boolean,
moderator: :boolean,
admin: :boolean
]
)
user? = Keyword.get(options, :user, false)
moderator? = Keyword.get(options, :moderator, false)
admin? = Keyword.get(options, :admin, false)
disable? = Keyword.get(options, :disable, false)
enable? = Keyword.get(options, :enable, false)
new_email = Keyword.get(options, :email)
if disable? && enable? do
Mix.raise("Can't use both --enabled and --disable options at the same time.")
end
Mix.Task.run("app.start")
with {:ok, %User{} = user} <- Users.get_user_by_email(email),
attrs <- %{},
role <- calculate_role(admin?, moderator?, user?),
attrs <- process_new_value(attrs, :mail, new_email, user.email),
attrs <- process_new_value(attrs, :role, role, user.role),
attrs <-
if(disable? && !is_nil(user.confirmed_at),
do: Map.put(attrs, :confirmed_at, nil),
else: attrs
),
attrs <-
if(enable? && is_nil(user.confirmed_at),
do: Map.put(attrs, :confirmed_at, DateTime.utc_now()),
else: attrs
),
{:makes_changes, true} <- {:makes_changes, attrs != %{}},
{:ok, %User{} = user} <- Users.update_user(user, attrs) do
Mix.shell().info("""
An user has been modified with the following information:
- email: #{user.email}
- Role: #{user.role}
- Activated: #{if user.confirmed_at, do: user.confirmed_at, else: "False"}
""")
else
{:makes_changes, false} ->
Mix.shell().info("No change has been made")
{:error, :user_not_found} ->
Mix.raise("Error: No such user")
{:error, %Ecto.Changeset{errors: errors}} ->
Mix.shell().error(inspect(errors))
Mix.raise("User has not been modified because of the above reason.")
err ->
Mix.shell().error(inspect(err))
Mix.raise("User has not been modified because of an unknown reason.")
end
end
def run(_) do
Mix.raise("mobilizon.users.new requires an email as argument")
end
@spec process_new_value(map(), atom(), any(), any()) :: map()
defp process_new_value(attrs, attribute, new_value, old_value) do
if !is_nil(new_value) && new_value != old_value do
Map.put(attrs, attribute, new_value)
else
attrs
end
end
@spec calculate_role(boolean(), boolean(), boolean()) ::
:administrator | :moderator | :user | nil
defp calculate_role(admin?, moderator?, user?) do
cond do
admin? -> :administrator
moderator? -> :moderator
user? -> :user
true -> nil
end
end
end

View File

@@ -0,0 +1,75 @@
defmodule Mix.Tasks.Mobilizon.Users.New do
@moduledoc """
Task to create a new user
"""
use Mix.Task
alias Mobilizon.Users
alias Mobilizon.Users.User
@shortdoc "Manages Mobilizon users"
@impl Mix.Task
def run([email | rest]) do
{options, [], []} =
OptionParser.parse(
rest,
strict: [
password: :string,
moderator: :boolean,
admin: :boolean
],
aliases: [
p: :password
]
)
moderator? = Keyword.get(options, :moderator, false)
admin? = Keyword.get(options, :admin, false)
role =
cond do
admin? -> :administrator
moderator? -> :moderator
true -> :user
end
password =
Keyword.get(
options,
:password,
:crypto.strong_rand_bytes(16) |> Base.encode64() |> binary_part(0, 16)
)
Mix.Task.run("app.start")
case Users.register(%{
email: email,
password: password,
role: role,
confirmed_at: DateTime.utc_now(),
confirmation_sent_at: nil,
confirmation_token: nil
}) do
{:ok, %User{} = user} ->
Mix.shell().info("""
An user has been created with the following information:
- email: #{user.email}
- password: #{password}
- Role: #{user.role}
The user will be prompted to create a new profile after login for the first time.
""")
{:error, %Ecto.Changeset{errors: errors}} ->
Mix.shell().error(inspect(errors))
Mix.raise("User has not been created because of the above reason.")
err ->
Mix.shell().error(inspect(err))
Mix.raise("User has not been created because of an unknown reason.")
end
end
def run(_) do
Mix.raise("mobilizon.users.new requires an email as argument")
end
end

View File

@@ -0,0 +1,48 @@
defmodule Mix.Tasks.Mobilizon.Users.Show do
@moduledoc """
Task to display an user details
"""
use Mix.Task
alias Mobilizon.Users
alias Mobilizon.Users.User
alias Mobilizon.Actors.Actor
@shortdoc "Show a Mobilizon user details"
@impl Mix.Task
def run([email]) do
Mix.Task.run("app.start")
with {:ok, %User{} = user} <- Users.get_user_by_email(email),
actors <- Users.get_actors_for_user(user) do
Mix.shell().info("""
Informations for the user #{user.email}:
- Activated: #{user.confirmed_at}
- Role: #{user.role}
#{display_actors(actors)}
""")
else
{:error, :user_not_found} ->
Mix.raise("Error: No such user")
end
end
def run(_) do
Mix.raise("mobilizon.users.show requires an email as argument")
end
defp display_actors([]), do: ""
defp display_actors(actors) do
"""
Identities (#{length(actors)}):
#{actors |> Enum.map(&display_actor/1) |> Enum.join("")}
"""
end
defp display_actor(%Actor{} = actor) do
"""
- @#{actor.preferred_username} / #{actor.name}
"""
end
end