UnrelateUserWhenArgumentNil used User :update which only accepts :email. Switch to :update_user with member: nil so manage_relationship clears member_id.
50 lines
1.7 KiB
Elixir
50 lines
1.7 KiB
Elixir
defmodule Mv.Membership.Member.Changes.UnrelateUserWhenArgumentNil do
|
|
@moduledoc """
|
|
When :user argument is present and nil/empty on update_member, unrelate the current user.
|
|
|
|
With on_missing: :ignore, manage_relationship does not unrelate when input is nil/[].
|
|
This change handles explicit unlink (user: nil or user: %{}) by updating the linked
|
|
User to set member_id = nil. Only runs when the argument key is present (policy
|
|
ForbidMemberUserLinkUnlessAdmin ensures only admins can pass :user).
|
|
"""
|
|
use Ash.Resource.Change
|
|
|
|
@spec change(Ash.Changeset.t(), keyword(), Ash.Resource.Change.context()) :: Ash.Changeset.t()
|
|
def change(changeset, _opts, _context) do
|
|
if unlink_requested?(changeset) do
|
|
unrelate_current_user(changeset)
|
|
else
|
|
changeset
|
|
end
|
|
end
|
|
|
|
defp unlink_requested?(changeset) do
|
|
args = changeset.arguments || %{}
|
|
|
|
if Map.has_key?(args, :user) or Map.has_key?(args, "user") do
|
|
user_arg = Ash.Changeset.get_argument(changeset, :user)
|
|
user_arg == nil or (is_map(user_arg) and map_size(user_arg) == 0)
|
|
else
|
|
false
|
|
end
|
|
end
|
|
|
|
defp unrelate_current_user(changeset) do
|
|
member = changeset.data
|
|
actor = Map.get(changeset.context || %{}, :actor)
|
|
|
|
case Ash.load(member, :user, domain: Mv.Membership, authorize?: false) do
|
|
{:ok, %{user: user}} when not is_nil(user) ->
|
|
# User's :update action only accepts [:email]; use :update_user so
|
|
# manage_relationship(:member, ..., on_missing: :unrelate) runs and clears member_id.
|
|
user
|
|
|> Ash.Changeset.for_update(:update_user, %{member: nil}, domain: Mv.Accounts)
|
|
|> Ash.update(domain: Mv.Accounts, actor: actor, authorize?: false)
|
|
|
|
changeset
|
|
|
|
_ ->
|
|
changeset
|
|
end
|
|
end
|
|
end
|