Integrate Member policies in LiveViews
- Add on_mount hook to ensure user role is loaded in all Member LiveViews - Pass actor parameter to all Ash operations (read, get, create, update, destroy, load)
This commit is contained in:
parent
a42fc8a6eb
commit
c544cdc07c
7 changed files with 160 additions and 65 deletions
|
|
@ -21,6 +21,8 @@ defmodule MvWeb.MemberLive.Form do
|
|||
"""
|
||||
use MvWeb, :live_view
|
||||
|
||||
on_mount {MvWeb.LiveHelpers, :ensure_user_role_loaded}
|
||||
|
||||
alias Mv.MembershipFees
|
||||
alias Mv.MembershipFees.MembershipFeeType
|
||||
alias MvWeb.Helpers.MembershipFeeHelpers
|
||||
|
|
@ -222,6 +224,8 @@ defmodule MvWeb.MemberLive.Form do
|
|||
|
||||
@impl true
|
||||
def mount(params, _session, socket) do
|
||||
# current_user should be set by on_mount hooks (LiveUserAuth + LiveHelpers)
|
||||
actor = socket.assigns[:current_user] || socket.assigns.current_user
|
||||
{:ok, custom_fields} = Mv.Membership.list_custom_fields()
|
||||
|
||||
initial_custom_field_values =
|
||||
|
|
@ -239,14 +243,14 @@ defmodule MvWeb.MemberLive.Form do
|
|||
member =
|
||||
case params["id"] do
|
||||
nil -> nil
|
||||
id -> Ash.get!(Mv.Membership.Member, id, load: [:membership_fee_type])
|
||||
id -> Ash.get!(Mv.Membership.Member, id, load: [:membership_fee_type], actor: actor)
|
||||
end
|
||||
|
||||
page_title =
|
||||
if is_nil(member), do: gettext("Create Member"), else: gettext("Edit Member")
|
||||
|
||||
# Load available membership fee types
|
||||
available_fee_types = load_available_fee_types(member)
|
||||
available_fee_types = load_available_fee_types(member, actor)
|
||||
|
||||
{:ok,
|
||||
socket
|
||||
|
|
@ -283,35 +287,59 @@ defmodule MvWeb.MemberLive.Form do
|
|||
end
|
||||
|
||||
def handle_event("save", %{"member" => member_params}, socket) do
|
||||
case AshPhoenix.Form.submit(socket.assigns.form, params: member_params) do
|
||||
{:ok, member} ->
|
||||
notify_parent({:saved, member})
|
||||
try do
|
||||
actor = socket.assigns[:current_user] || socket.assigns.current_user
|
||||
|
||||
action =
|
||||
case socket.assigns.form.source.type do
|
||||
:create -> gettext("create")
|
||||
:update -> gettext("update")
|
||||
other -> to_string(other)
|
||||
end
|
||||
case AshPhoenix.Form.submit(socket.assigns.form, params: member_params, actor: actor) do
|
||||
{:ok, member} ->
|
||||
handle_save_success(socket, member)
|
||||
|
||||
socket =
|
||||
socket
|
||||
|> put_flash(:info, gettext("Member %{action} successfully", action: action))
|
||||
|> push_navigate(to: return_path(socket.assigns.return_to, member))
|
||||
|
||||
{:noreply, socket}
|
||||
|
||||
{:error, form} ->
|
||||
{:noreply, assign(socket, form: form)}
|
||||
{:error, form} ->
|
||||
{:noreply, assign(socket, form: form)}
|
||||
end
|
||||
rescue
|
||||
_e in [Ash.Error.Forbidden, Ash.Error.Forbidden.Policy] ->
|
||||
handle_save_forbidden(socket)
|
||||
end
|
||||
end
|
||||
|
||||
defp handle_save_success(socket, member) do
|
||||
notify_parent({:saved, member})
|
||||
|
||||
action = get_action_name(socket.assigns.form.source.type)
|
||||
|
||||
socket =
|
||||
socket
|
||||
|> put_flash(:info, gettext("Member %{action} successfully", action: action))
|
||||
|> push_navigate(to: return_path(socket.assigns.return_to, member))
|
||||
|
||||
{:noreply, socket}
|
||||
end
|
||||
|
||||
defp handle_save_forbidden(socket) do
|
||||
# Handle policy violations that aren't properly displayed in forms
|
||||
# AshPhoenix.Form doesn't implement FormData.Error protocol for Forbidden errors
|
||||
action = get_action_name(socket.assigns.form.source.type)
|
||||
|
||||
error_message =
|
||||
gettext("You do not have permission to %{action} members.", action: action)
|
||||
|
||||
{:noreply, put_flash(socket, :error, error_message)}
|
||||
end
|
||||
|
||||
defp get_action_name(:create), do: gettext("create")
|
||||
defp get_action_name(:update), do: gettext("update")
|
||||
defp get_action_name(other), do: to_string(other)
|
||||
|
||||
defp notify_parent(msg), do: send(self(), {__MODULE__, msg})
|
||||
|
||||
defp assign_form(%{assigns: %{member: member}} = socket) do
|
||||
defp assign_form(%{assigns: assigns} = socket) do
|
||||
member = assigns.member
|
||||
actor = assigns[:current_user] || assigns.current_user
|
||||
|
||||
form =
|
||||
if member do
|
||||
{:ok, member} = Ash.load(member, custom_field_values: [:custom_field])
|
||||
{:ok, member} = Ash.load(member, custom_field_values: [:custom_field], actor: actor)
|
||||
|
||||
existing_custom_field_values =
|
||||
member.custom_field_values
|
||||
|
|
@ -342,7 +370,8 @@ defmodule MvWeb.MemberLive.Form do
|
|||
api: Mv.Membership,
|
||||
as: "member",
|
||||
params: params,
|
||||
forms: [auto?: true]
|
||||
forms: [auto?: true],
|
||||
actor: actor
|
||||
)
|
||||
|
||||
missing_custom_field_values =
|
||||
|
|
@ -360,7 +389,8 @@ defmodule MvWeb.MemberLive.Form do
|
|||
api: Mv.Membership,
|
||||
as: "member",
|
||||
params: %{"custom_field_values" => socket.assigns[:initial_custom_field_values]},
|
||||
forms: [auto?: true]
|
||||
forms: [auto?: true],
|
||||
actor: actor
|
||||
)
|
||||
end
|
||||
|
||||
|
|
@ -375,11 +405,11 @@ defmodule MvWeb.MemberLive.Form do
|
|||
# Helper Functions
|
||||
# -----------------------------------------------------------------
|
||||
|
||||
defp load_available_fee_types(member) do
|
||||
defp load_available_fee_types(member, actor) do
|
||||
all_types =
|
||||
MembershipFeeType
|
||||
|> Ash.Query.sort(name: :asc)
|
||||
|> Ash.read!(domain: MembershipFees)
|
||||
|> Ash.read!(domain: MembershipFees, actor: actor)
|
||||
|
||||
# If member has a fee type, filter to same interval
|
||||
if member && member.membership_fee_type do
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue