How to delete a user View Source

Haytni does not directly handle account deletion (account removal) because everyone might want to do it in very different ways:

  • delay it to give some time to the user to think about it and cancel it if wished
  • confirm the action
  • do some kind of soft-deletion instead
  • remove extra data, even non-SQL
  • ...

So, it has to be written as a plugin which implements the Haytni.Plugin.on_delete_user/4 callback. Let's see some use cases as examples and guidelines.

Hard deletion

To delete the user from the database (meaning issue a DELETE SQL statement), your Haytni.Plugin.on_delete_user/4 callback just need to add a c:Ecto.Multi.delete/4 operation to the Ecto.Multi received from its parameters :

defmodule YourApp.HaytniPlugin do
  use Haytni.Plugin

  @impl Haytni.Plugin
  def on_delete_user(multi = %Ecto.Multi{}, user = %_{}, _module, _config) do
    multi
    |> Ecto.Multi.delete(:deletion, user)
  end
end

Soft deletion

The idea is the same but instead of deleting the user, we update (c:Ecto.Multi.update/4) it to turn off some field and flag reflecting this state.

defmodule YourApp.HaytniPlugin do
  use Haytni.Plugin

  @impl Haytni.Plugin
  def fields(_module) do
    quote do
      field :deleted, :boolean, default: true
    end
  end

  @impl Haytni.Plugin
  def invalid?(user = %_{}, _module, _config) do
    user.deleted && {:error, :deleted}
  end

  @impl Haytni.Plugin
  def on_delete_user(multi = %Ecto.Multi{}, user = %_{}, _module, _config) do
    multi
    |> Ecto.Multi.update(:deletion, Ecto.Changeset.change(user, [deleted: true]))
  end
end

The callbacks Haytni.Plugin.fields/1 and Haytni.Plugin.invalid?/3 were also implemented to deal with this additional information.

Anonymize account

In this scenario, the idea is to issue an UPDATE to nullify (at least) the password and email.

defmodule YourApp.HaytniPlugin do
  use Haytni.Plugin

  @impl Haytni.Plugin
  def on_delete_user(multi = %Ecto.Multi{}, user = %_{}, _module, _config) do
    multi
    |> Ecto.Multi.update(:deletion, Ecto.Changeset.change(user, [encrypted_password: nil, email: nil]))
  end
end

But don't forget to write a migration for encrypted_password and email to be nullable.