Skip to content

Commit

Permalink
Allow different rules and action for delete user (#2714)
Browse files Browse the repository at this point in the history
* Refactor user profile for remaining components

* Rename components module

* Remove unnecessary vertical bar between table actions in UserLive.Components

* Replace not working private with metadata

* Address the user directly yet once more

* Fix use of metadata modal

* Fix cancel scheduled deletion on admin users

* Revert change

* There is pre-existing bug that needs to be fixed when clicking outside the modal

* Fix test cases and revert to attrs string keys

* Rename menu context to current user

---------

Co-authored-by: Elias W. BA <[email protected]>
  • Loading branch information
jyeshe and elias-ba authored Dec 11, 2024
1 parent 5effcb3 commit c9cad42
Show file tree
Hide file tree
Showing 15 changed files with 311 additions and 206 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ and this project adheres to

### Added

- Allow different rules and action for delete user.
[#2500](https://github.com/OpenFn/lightning/issues/2500)

### Changed

### Fixed
Expand Down
5 changes: 4 additions & 1 deletion config/config.exs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,10 @@ config :lightning, Lightning.Extensions,
config :lightning, Lightning.Extensions.Routing,
session_opts: [on_mount: LightningWeb.InitAssigns],
routes: [
{"/projects", LightningWeb.DashboardLive.Index, :index, []}
{"/projects", LightningWeb.DashboardLive.Index, :index, []},
{"/profile", LightningWeb.ProfileLive.Edit, :edit,
metadata: %{delete_modal: LightningWeb.Components.UserDeletionModal}},
{"/settings/users", LightningWeb.UserLive.Index, :index, []}
]

# TODO: don't use this value in production
Expand Down
13 changes: 8 additions & 5 deletions lib/lightning/accounts.ex
Original file line number Diff line number Diff line change
Expand Up @@ -449,11 +449,13 @@ defmodule Lightning.Accounts do
end

def cancel_scheduled_deletion(user_id) do
get_user!(user_id)
|> update_user_details(%{
scheduled_deletion: nil,
disabled: false
user_id
|> get_user!()
|> User.details_changeset(%{
"scheduled_deletion" => nil,
"disabled" => false
})
|> Repo.update()
end

@doc """
Expand Down Expand Up @@ -671,7 +673,8 @@ defmodule Lightning.Accounts do
integer -> DateTime.utc_now() |> Timex.shift(days: integer)
end

User.scheduled_deletion_changeset(user, %{
user
|> User.scheduled_deletion_changeset(%{
"scheduled_deletion" => date,
"disabled" => true,
"scheduled_deletion_email" => email
Expand Down
9 changes: 6 additions & 3 deletions lib/lightning_web/live/components/user_deletion_modal.ex
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ defmodule LightningWeb.Components.UserDeletionModal do
|> assign(
delete_now?: !is_nil(user.scheduled_deletion),
has_activity_in_projects?: Accounts.has_activity_in_projects?(user),
is_current_user: Map.get(assigns, :is_current_user, true),
scheduled_deletion_changeset: Accounts.change_scheduled_deletion(user)
)
|> assign(assigns)}
Expand Down Expand Up @@ -106,7 +107,7 @@ defmodule LightningWeb.Components.UserDeletionModal do
</:title>
<div class="">
<p class="text-sm text-gray-500">
This user cannot be deleted until their auditable activities have also been purged.
<%= if @is_current_user, do: "Your account", else: "This user" %> cannot be deleted until their auditable activities have also been purged.
<br /><br />Audit trails are removed on a project-basis and may be controlled by the project owner or a superuser.
</p>
</div>
Expand Down Expand Up @@ -158,10 +159,12 @@ defmodule LightningWeb.Components.UserDeletionModal do
>
<div class="">
<p class="">
This user's account and credential data will be deleted. Please make sure none of these credentials are used in production workflows.
<%= if @is_current_user, do: "Your", else: "This user's" %> account and credential data will be deleted. Please make sure none of these credentials are used in production workflows.
</p>
<p :if={@has_activity_in_projects?} class="mt-2">
*Note that this user still has activity related to active projects. We may not be able to delete them entirely from the app until those projects are deleted.
*Note that <%= if @is_current_user,
do: "you still have",
else: "this user still has" %> activity related to active projects. We may not be able to delete them entirely from the app until those projects are deleted.
</p>
<br />
<.input
Expand Down
90 changes: 90 additions & 0 deletions lib/lightning_web/live/profile_live/components.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
defmodule LightningWeb.ProfileLive.Components do
use LightningWeb, :component

attr :current_user, Lightning.Accounts.User, required: true

def user_info(assigns) do
~H"""
<div class="px-4 sm:px-0">
<h2 class="text-base font-semibold leading-7 text-gray-900">
<%= @current_user.first_name %> <%= @current_user.last_name %>
</h2>
<p class="mt-1 text-sm leading-6 text-gray-600">
Change name, email, password, and request deletion.
</p>
<div class="border-b border-gray-900/10 mt-6 mb-6" />
<p class="mt-1 text-sm leading-6 text-gray-600">
Created: <%= @current_user.inserted_at |> Calendar.strftime("%c %Z") %> UTC
</p>
<p class="mt-1 text-sm leading-6 text-gray-600">
Email: <%= @current_user.email %>
</p>
</div>
"""
end

attr :page_title, :string, required: true
attr :live_action, :atom, required: true
attr :current_user, Lightning.Accounts.User, required: true

attr :user_deletion_modal, :atom,
default: LightningWeb.Components.UserDeletionModal

attr :delete_user_url, :string, required: true

def action_cards(assigns) do
~H"""
<div id={"user-#{@current_user.id}"} class="md:col-span-2">
<.live_component
:if={@live_action == :delete}
module={@user_deletion_modal}
id={@current_user.id}
user={@current_user}
logout={true}
return_to={~p"/profile"}
/>
<.live_component
module={LightningWeb.ProfileLive.FormComponent}
id={@current_user.id}
title={@page_title}
action={@live_action}
user={@current_user}
return_to={~p"/profile"}
/>
<.live_component
module={LightningWeb.ProfileLive.MfaComponent}
id={"#{@current_user.id}_mfa_section"}
user={@current_user}
/>
<.live_component
module={LightningWeb.ProfileLive.GithubComponent}
id={"#{@current_user.id}_github_section"}
user={@current_user}
/>
<.delete_user_card url={@delete_user_url} />
</div>
"""
end

attr :url, :string, required: true

defp delete_user_card(assigns) do
~H"""
<div class="bg-white shadow-sm ring-1 ring-gray-900/5 sm:rounded-xl md:col-span-2 mb-4">
<div class="px-4 py-6 sm:p-8">
<span class="text-xl">Delete account</span>
<span class="float-right">
<.link navigate={@url}>
<button
type="button"
class="inline-flex justify-center py-2 px-4 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-danger-500 hover:bg-danger-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-danger-500"
>
Delete my account
</button>
</.link>
</span>
</div>
</div>
"""
end
end
9 changes: 9 additions & 0 deletions lib/lightning_web/live/profile_live/edit.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ defmodule LightningWeb.ProfileLive.Edit do
LiveView for user profile page.
"""
use LightningWeb, :live_view

import LightningWeb.ProfileLive.Components

alias Lightning.VersionControl

on_mount {LightningWeb.Hooks, :assign_projects}
Expand Down Expand Up @@ -67,9 +70,15 @@ defmodule LightningWeb.ProfileLive.Edit do
)

if can_delete_account do
modal =
socket.router
|> Phoenix.Router.route_info("GET", ~p"/profile", nil)
|> Map.get(:delete_modal)

socket
|> assign(:page_title, "User Profile")
|> assign(:user, user)
|> assign(:user_deletion_modal, modal)
else
put_flash(socket, :error, "You can't perform this action")
|> push_patch(to: ~p"/profile")
Expand Down
31 changes: 9 additions & 22 deletions lib/lightning_web/live/profile_live/edit.html.heex
Original file line number Diff line number Diff line change
Expand Up @@ -6,28 +6,15 @@
</:header>
<LayoutComponents.centered>
<div class="grid grid-cols-1 gap-x-8 gap-y-8 md:grid-cols-3">
<div class="px-4 sm:px-0">
<h2 class="text-base font-semibold leading-7 text-gray-900">
<%= @current_user.first_name %> <%= @current_user.last_name %>
</h2>
<p class="mt-1 text-sm leading-6 text-gray-600">
Change name, email, password, and request deletion.
</p>
<div class="border-b border-gray-900/10 mt-6 mb-6" />
<p class="mt-1 text-sm leading-6 text-gray-600">
Created: <%= @current_user.inserted_at |> Calendar.strftime("%c %Z") %> UTC
</p>
<p class="mt-1 text-sm leading-6 text-gray-600">
Email: <%= @current_user.email %>
</p>
</div>
<.live_component
module={LightningWeb.ProfileLive.FormComponent}
id={@current_user.id}
title={@page_title}
action={@live_action}
user={@user}
return_to={~p"/profile"}
<.user_info current_user={@current_user} />
<.action_cards
page_title={@page_title}
current_user={@current_user}
live_action={@live_action}
user_deletion_modal={assigns[:user_deletion_modal]}
delete_user_url={
Routes.profile_edit_path(@socket, :delete, @current_user)
}
/>
</div>
</LayoutComponents.centered>
Expand Down
38 changes: 1 addition & 37 deletions lib/lightning_web/live/profile_live/form_component.html.heex
Original file line number Diff line number Diff line change
@@ -1,14 +1,4 @@
<div id={"user-#{@user.id}"} class="md:col-span-2">
<%= if @action == :delete do %>
<.live_component
module={LightningWeb.Components.UserDeletionModal}
id={@user.id}
user={@user}
logout={true}
return_to={~p"/profile"}
/>
<% end %>

<div>
<.form
:let={f}
as={:user}
Expand Down Expand Up @@ -154,30 +144,4 @@
Update password
</button>
</.form>
<.live_component
module={LightningWeb.ProfileLive.MfaComponent}
id={"#{@user.id}_mfa_section"}
user={@user}
/>

<.live_component
module={LightningWeb.ProfileLive.GithubComponent}
id={"#{@user.id}_github_section"}
user={@user}
/>
<div class="bg-white shadow-sm ring-1 ring-gray-900/5 sm:rounded-xl md:col-span-2 mb-4">
<div class="px-4 py-6 sm:p-8">
<span class="text-xl">Delete account</span>
<span class="float-right">
<.link navigate={Routes.profile_edit_path(@socket, :delete, @user)}>
<button
type="button"
class="inline-flex justify-center py-2 px-4 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-danger-500 hover:bg-danger-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-danger-500"
>
Delete my account
</button>
</.link>
</span>
</div>
</div>
</div>
Loading

0 comments on commit c9cad42

Please sign in to comment.