Add the User LiveViews to manage roles.

dev
KKlochko 2 months ago
parent 524595da9a
commit 5e478b7e6d

@ -46,6 +46,11 @@ defmodule DecentralisedBookIndexWeb.Components.MyPartials.Navbar do
<a href={~p"/servers/"} class={selected_navbar_link_css(@page_title, "Listing Server")} aria-current="page">Servers</a>
</li>
<% end %>
<%= if @current_user != nil and Role.can_administrate?(@current_user.role) do %>
<li>
<a href={~p"/users/"} class={selected_navbar_link_css(@page_title, "Listing Users")} aria-current="page">Users</a>
</li>
<% end %>
</ul>
</div>
</div>

@ -0,0 +1,56 @@
defmodule DecentralisedBookIndexWeb.UserLive.Edit do
use DecentralisedBookIndexWeb, :live_view
alias DecentralisedBookIndex.Accounts.User
@impl true
def render(assigns) do
~H"""
<.live_component
module={DecentralisedBookIndexWeb.UserLive.FormComponent}
id={(@user && @user.id) || :new}
title={@page_title}
current_user={@current_user}
action={@live_action}
user={@user}
/>
"""
end
@impl true
def mount(_params, _session, socket) do
{:ok,
socket
|> assign_new(:current_user, fn -> nil end)}
end
@impl true
def handle_params(params, _url, socket) do
socket =
socket
|> assign(:params, params)
|> apply_action(socket.assigns.live_action, params)
{:noreply, socket}
end
defp apply_action(socket, :edit, %{"id" => id}) do
socket
|> assign(:page_title, "Edit User")
|> assign(
:user,
User.get_by_id!(id, actor: socket.assigns.current_user)
)
end
defp apply_action(socket, :new, _params) do
socket
|> assign(:page_title, "New User")
|> assign(:user, nil)
end
@impl true
def handle_info({DecentralisedBookIndexWeb.UserLive.FormComponent, {:saved, author}}, socket) do
{:noreply, socket}
end
end

@ -0,0 +1,116 @@
defmodule DecentralisedBookIndexWeb.UserLive.FormComponent do
use DecentralisedBookIndexWeb, :live_component
@impl true
def render(assigns) do
~H"""
<div>
<.header>
{@title}
</.header>
<.simple_form
for={@form}
id="user-form"
phx-target={@myself}
phx-change="validate"
phx-submit="save"
>
<%= if @form.source.type == :create do %>
<% end %>
<%= if @form.source.type == :update do %>
<.input field={@form[:role]} type="select" label="Role" options={@role_options} />
<% end %>
<:actions>
<.save_button phx-disable-with="Saving...">
Save
</.save_button>
<.cancel_button phx-click="cancel" phx-target={@myself}>
Cancel
</.cancel_button>
</:actions>
</.simple_form>
</div>
"""
end
@impl true
def update(assigns, socket) do
{:ok,
socket
|> assign(assigns)
|> assign(:role_options, role_options())
|> assign_form()}
end
@impl true
def handle_event("validate", %{"user" => user_params}, socket) do
{:noreply, assign(socket, form: AshPhoenix.Form.validate(socket.assigns.form, user_params))}
end
def handle_event("save", %{"user" => user_params}, socket) do
case AshPhoenix.Form.submit(socket.assigns.form, params: user_params) do
{:ok, user} ->
notify_parent({:saved, user})
socket =
socket
|> put_flash(:info, "User #{socket.assigns.form.source.type}d successfully")
|> push_redirect(to: patch_url(socket.assigns.action, user.id))
{:noreply, socket}
{:error, form} ->
{:noreply, assign(socket, form: form)}
end
end
def handle_event("cancel", _params, socket) do
user = socket.assigns.user
user_id = if user == nil, do: nil, else: user.id
socket =
socket
|> push_redirect(to: patch_url(socket.assigns.action, user_id))
{:noreply, socket}
end
defp notify_parent(msg), do: send(self(), {__MODULE__, msg})
defp assign_form(%{assigns: %{user: user}} = socket) do
if user do
form =
AshPhoenix.Form.for_update(user, :set_role,
as: "user",
actor: socket.assigns.current_user
)
assign(socket, form: to_form(form))
else
socket =
socket
|> put_flash(:info, "User not exists successfully")
|> push_redirect(to: patch_url(socket.assigns.action, nil))
{:noreply, socket}
end
end
defp patch_url(action, user_id) do
case action do
:edit -> ~p"/users/#{user_id}"
:new -> ~p"/users"
_ -> ~p"/users"
end
end
defp role_options() do
[
{"Regular user", "user"},
{"Moderator", "moderator"},
{"Admin", "admin"}
]
end
end

@ -0,0 +1,73 @@
defmodule DecentralisedBookIndexWeb.UserLive.Index do
use DecentralisedBookIndexWeb, :live_view
alias DecentralisedBookIndex.Accounts.User
@impl true
def render(assigns) do
~H"""
<.header>
Listing Users
</.header>
<div class="pt-2">
<.table
id="users"
rows={@users}
row_click={fn {_id, user} -> JS.navigate(~p"/users/#{user}") end}
>
<:col :let={{_id, user}} label="Email">{user.email}</:col>
<:col :let={{_id, user}} label="Role">{user.role}</:col>
<:action :let={{_id, user}}>
<div class="sr-only">
<.link navigate={~p"/users/#{user}"}>Show</.link>
</div>
<.link patch={~p"/users/#{user}/edit"}>Edit Role</.link>
</:action>
</.table>
</div>
"""
end
@impl true
def mount(params, _session, socket) do
search_query = Map.get(params, "query", "")
sort_by = Map.get(params, "sort_by", "name")
page_params = AshPhoenix.LiveView.page_from_params(params, 10)
page = User.search!(
search_query,
page: page_params ++ [count: true],
actor: socket.assigns.current_user
)
socket =
socket
|> assign(:sort_by, sort_by)
|> assign(:search_query, search_query)
|> assign(:page_params, page_params)
|> assign(:page, page)
|> assign(:users, user_row(page.results))
|> assign(:params, params)
|> apply_action(socket.assigns.live_action, params)
{:ok, socket}
end
@impl true
def handle_params(params, _url, socket) do
{:noreply, apply_action(socket, socket.assigns.live_action, params)}
end
defp apply_action(socket, :index, _params) do
socket
|> assign(:page_title, "Listing Users")
end
defp user_row(users) do
Enum.map(users, fn user -> {user.id, user} end)
end
end

@ -0,0 +1,46 @@
defmodule DecentralisedBookIndexWeb.UserLive.Show do
use DecentralisedBookIndexWeb, :live_view
@impl true
def render(assigns) do
~H"""
<.header>
{@user.email}
<:actions>
<.link navigate={~p"/users/#{@user}/edit"}>
<.edit_button>
Edit Role
</.edit_button>
</.link>
</:actions>
</.header>
<.list>
<:item title="Email">{@user.email}</:item>
<:item title="Role">{@user.role}</:item>
</.list>
<.back navigate={~p"/users"}>Back to users</.back>
"""
end
@impl true
def mount(_params, _session, socket) do
{:ok, socket}
end
@impl true
def handle_params(%{"id" => id}, _, socket) do
{:noreply,
socket
|> assign(:page_title, page_title(socket.assigns.live_action))
|> assign(
:user,
Ash.get!(DecentralisedBookIndex.Accounts.User, id, actor: socket.assigns.current_user)
)}
end
defp page_title(:show), do: "Show User"
defp page_title(:edit), do: "Edit User"
end

@ -57,6 +57,10 @@ defmodule DecentralisedBookIndexWeb.Router do
live "/servers/:id", DbiServerLive.Show, :show
live "/servers/:id/show/edit", DbiServerLive.Show, :edit
live "/users", UserLive.Index, :index
live "/users/:id", UserLive.Show, :show
live "/users/:id/edit", UserLive.Edit, :edit
end
ash_authentication_live_session :maybe_authenticated_routes, on_mount: {DecentralisedBookIndexWeb.LiveUserAuth, :live_user_optional} do

Loading…
Cancel
Save