Fix member unlink: use User update_user action
UnrelateUserWhenArgumentNil used User :update which only accepts :email. Switch to :update_user with member: nil so manage_relationship clears member_id.
This commit is contained in:
parent
5194b20b5c
commit
95472424b1
2 changed files with 54 additions and 0 deletions
|
|
@ -153,6 +153,10 @@ defmodule Mv.Membership.Member do
|
||||||
|
|
||||||
change manage_relationship(:custom_field_values, on_match: :update, on_no_match: :create)
|
change manage_relationship(:custom_field_values, on_match: :update, on_no_match: :create)
|
||||||
|
|
||||||
|
# When :user argument is present and nil/empty, unrelate (admin-only via policy).
|
||||||
|
# Must run before manage_relationship; on_missing: :ignore then does nothing for nil input.
|
||||||
|
change Mv.Membership.Member.Changes.UnrelateUserWhenArgumentNil
|
||||||
|
|
||||||
# Manage the user relationship during member update
|
# Manage the user relationship during member update
|
||||||
# on_missing: :ignore so that omitting :user does NOT unlink (security: only admins may
|
# on_missing: :ignore so that omitting :user does NOT unlink (security: only admins may
|
||||||
# change the link; unlink is explicit via user: nil, forbidden for non-admins by policy).
|
# change the link; unlink is explicit via user: nil, forbidden for non-admins by policy).
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,50 @@
|
||||||
|
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
|
||||||
Loading…
Add table
Add a link
Reference in a new issue