mirror of
https://github.com/ClaperCo/Claper.git
synced 2025-12-16 11:57:58 +01:00
Add soft delete user account
This commit is contained in:
@@ -16,6 +16,7 @@
|
|||||||
- Improve design and UX for interactions and presentation settings in the manager view
|
- Improve design and UX for interactions and presentation settings in the manager view
|
||||||
- Add pagination for events on the dashboard
|
- Add pagination for events on the dashboard
|
||||||
- Fix STMP adapter to work with secure connection
|
- Fix STMP adapter to work with secure connection
|
||||||
|
- Add soft delete for user accounts
|
||||||
|
|
||||||
## v2.2.0
|
## v2.2.0
|
||||||
|
|
||||||
|
|||||||
@@ -38,7 +38,9 @@ defmodule Claper.Accounts do
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
def get_user_by_email(email) when is_binary(email) do
|
def get_user_by_email(email) when is_binary(email) do
|
||||||
Repo.get_by(User, email: email)
|
User
|
||||||
|
|> where([u], is_nil(u.deleted_at))
|
||||||
|
|> Repo.get_by(email: email)
|
||||||
end
|
end
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
@@ -79,8 +81,8 @@ defmodule Claper.Accounts do
|
|||||||
"""
|
"""
|
||||||
def get_user_by_email_and_password(email, password)
|
def get_user_by_email_and_password(email, password)
|
||||||
when is_binary(email) and is_binary(password) do
|
when is_binary(email) and is_binary(password) do
|
||||||
user = Repo.get_by(User, email: email)
|
user = User |> where([u], u.email == ^email and is_nil(u.deleted_at)) |> Repo.one()
|
||||||
if User.valid_password?(user, password), do: user
|
if user && User.valid_password?(user, password), do: user
|
||||||
end
|
end
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
@@ -99,6 +101,37 @@ defmodule Claper.Accounts do
|
|||||||
"""
|
"""
|
||||||
def get_user!(id), do: Repo.get!(User, id)
|
def get_user!(id), do: Repo.get!(User, id)
|
||||||
|
|
||||||
|
def get_user(id) do
|
||||||
|
User
|
||||||
|
|> where([u], is_nil(u.deleted_at))
|
||||||
|
|> Repo.get(id)
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Soft deletes a user.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
iex> delete_user(user)
|
||||||
|
{:ok, %User{}}
|
||||||
|
|
||||||
|
iex> delete_user(user)
|
||||||
|
{:error, %Ecto.Changeset{}}
|
||||||
|
|
||||||
|
"""
|
||||||
|
def delete_user(%User{} = user) do
|
||||||
|
user
|
||||||
|
|> User.delete_changeset()
|
||||||
|
|> Repo.update()
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Returns true if the user has been soft deleted.
|
||||||
|
"""
|
||||||
|
def deleted?(%User{} = user) do
|
||||||
|
not is_nil(user.deleted_at)
|
||||||
|
end
|
||||||
|
|
||||||
## User registration
|
## User registration
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
@@ -515,10 +548,6 @@ defmodule Claper.Accounts do
|
|||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def delete(user) do
|
|
||||||
Repo.delete(user)
|
|
||||||
end
|
|
||||||
|
|
||||||
## OIDC
|
## OIDC
|
||||||
|
|
||||||
def create_oidc_user(attrs) do
|
def create_oidc_user(attrs) do
|
||||||
|
|||||||
@@ -14,7 +14,8 @@ defmodule Claper.Accounts.User do
|
|||||||
locale: String.t() | nil,
|
locale: String.t() | nil,
|
||||||
events: [Claper.Events.Event.t()] | nil,
|
events: [Claper.Events.Event.t()] | nil,
|
||||||
inserted_at: NaiveDateTime.t(),
|
inserted_at: NaiveDateTime.t(),
|
||||||
updated_at: NaiveDateTime.t()
|
updated_at: NaiveDateTime.t(),
|
||||||
|
deleted_at: NaiveDateTime.t() | nil
|
||||||
}
|
}
|
||||||
|
|
||||||
schema "users" do
|
schema "users" do
|
||||||
@@ -25,6 +26,7 @@ defmodule Claper.Accounts.User do
|
|||||||
field :is_randomized_password, :boolean
|
field :is_randomized_password, :boolean
|
||||||
field :confirmed_at, :naive_datetime
|
field :confirmed_at, :naive_datetime
|
||||||
field :locale, :string
|
field :locale, :string
|
||||||
|
field :deleted_at, :naive_datetime
|
||||||
|
|
||||||
has_many :events, Claper.Events.Event
|
has_many :events, Claper.Events.Event
|
||||||
has_one :lti_user, Lti13.Users.User
|
has_one :lti_user, Lti13.Users.User
|
||||||
@@ -44,6 +46,14 @@ defmodule Claper.Accounts.User do
|
|||||||
|> cast(attrs, [:locale])
|
|> cast(attrs, [:locale])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
A changeset for marking a user as deleted.
|
||||||
|
"""
|
||||||
|
def delete_changeset(user) do
|
||||||
|
now = NaiveDateTime.utc_now() |> NaiveDateTime.truncate(:second)
|
||||||
|
change(user, deleted_at: now)
|
||||||
|
end
|
||||||
|
|
||||||
defp validate_email(changeset) do
|
defp validate_email(changeset) do
|
||||||
changeset
|
changeset
|
||||||
|> validate_required([:email])
|
|> validate_required([:email])
|
||||||
|
|||||||
@@ -75,7 +75,8 @@ defmodule Claper.Accounts.UserToken do
|
|||||||
query =
|
query =
|
||||||
from token in token_and_context_query(token, "session"),
|
from token in token_and_context_query(token, "session"),
|
||||||
join: user in assoc(token, :user),
|
join: user in assoc(token, :user),
|
||||||
where: token.inserted_at > ago(@session_validity_in_days, "day"),
|
where:
|
||||||
|
token.inserted_at > ago(@session_validity_in_days, "day") and is_nil(user.deleted_at),
|
||||||
select: user
|
select: user
|
||||||
|
|
||||||
{:ok, query}
|
{:ok, query}
|
||||||
|
|||||||
@@ -43,6 +43,14 @@ defmodule ClaperWeb.UserRegistrationController do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def delete(conn, _params) do
|
||||||
|
Accounts.delete_user(conn.assigns.current_user)
|
||||||
|
|
||||||
|
conn
|
||||||
|
|> put_flash(:info, gettext("Your account has been deleted."))
|
||||||
|
|> UserAuth.log_out_user()
|
||||||
|
end
|
||||||
|
|
||||||
defp user_params(params) do
|
defp user_params(params) do
|
||||||
if Application.get_env(:claper, :email_confirmation) do
|
if Application.get_env(:claper, :email_confirmation) do
|
||||||
params
|
params
|
||||||
|
|||||||
@@ -209,7 +209,7 @@
|
|||||||
<% end %>
|
<% end %>
|
||||||
</ul>
|
</ul>
|
||||||
<%= if @page < @total_pages do %>
|
<%= if @page < @total_pages do %>
|
||||||
<div class="flex justify-center mt-8">
|
<div class="flex justify-center my-4">
|
||||||
<button
|
<button
|
||||||
phx-click="load-more"
|
phx-click="load-more"
|
||||||
class="inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md text-primary-700 bg-primary-100 hover:bg-primary-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500"
|
class="inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md text-primary-700 bg-primary-100 hover:bg-primary-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500"
|
||||||
|
|||||||
@@ -210,16 +210,6 @@ defmodule ClaperWeb.UserSettingsLive.Show do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@impl true
|
|
||||||
def handle_event("delete_account", _params, %{assigns: %{current_user: user}} = socket) do
|
|
||||||
Accounts.delete(user)
|
|
||||||
|
|
||||||
{:noreply,
|
|
||||||
socket
|
|
||||||
|> put_flash(:info, gettext("Your account has been deleted."))
|
|
||||||
|> redirect(to: ~p"/users/log_in")}
|
|
||||||
end
|
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def handle_event("validate", _params, socket) do
|
def handle_event("validate", _params, socket) do
|
||||||
{:noreply, socket}
|
{:noreply, socket}
|
||||||
|
|||||||
@@ -280,16 +280,15 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="border-t border-gray-200 py-5 sm:p-0">
|
<div class="border-t border-gray-200 py-5 sm:p-0">
|
||||||
<dl class="sm:divide-y sm:divide-gray-200">
|
<dl class="sm:divide-y sm:divide-gray-200">
|
||||||
<div class="mt-5">
|
<div class="my-5">
|
||||||
<button
|
<%= link(gettext("Delete account"),
|
||||||
data-confirm={
|
to: ~p"/users/register/delete",
|
||||||
gettext("All your events and files will be permanently deleted, are you sure?")
|
method: :delete,
|
||||||
}
|
"data-confirm":
|
||||||
phx-click="delete_account"
|
gettext("All your events and files will be permanently deleted, are you sure?"),
|
||||||
class="w-full lg:w-auto px-6 text-center text-white py-2 rounded-md tracking-wide font-bold focus:outline-none focus:shadow-outline bg-gradient-to-tl from-supporting-red-600 to-supporting-red-400 bg-size-200 bg-pos-0 hover:bg-pos-100 transition-all duration-500"
|
class:
|
||||||
>
|
"w-full lg:w-auto px-6 text-center text-white py-2 rounded-md tracking-wide font-bold focus:outline-none focus:shadow-outline bg-gradient-to-tl from-supporting-red-600 to-supporting-red-400 bg-size-200 bg-pos-0 hover:bg-pos-100 transition-all duration-500"
|
||||||
<%= gettext("Delete account") %>
|
) %>
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
</dl>
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -154,6 +154,7 @@ defmodule ClaperWeb.Router do
|
|||||||
|
|
||||||
post("/events/:uuid/slide.jpg", EventController, :slide_generate)
|
post("/events/:uuid/slide.jpg", EventController, :slide_generate)
|
||||||
get("/users/settings/confirm_email/:token", UserSettingsController, :confirm_email)
|
get("/users/settings/confirm_email/:token", UserSettingsController, :confirm_email)
|
||||||
|
delete("/users/register/delete", UserRegistrationController, :delete)
|
||||||
end
|
end
|
||||||
|
|
||||||
scope "/", ClaperWeb do
|
scope "/", ClaperWeb do
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
defmodule Claper.Repo.Migrations.AddDeletedAtToUsers do
|
||||||
|
use Ecto.Migration
|
||||||
|
|
||||||
|
def change do
|
||||||
|
alter table(:users) do
|
||||||
|
add :deleted_at, :naive_datetime, null: true
|
||||||
|
end
|
||||||
|
|
||||||
|
create index(:users, [:deleted_at])
|
||||||
|
end
|
||||||
|
end
|
||||||
Reference in New Issue
Block a user