diff --git a/lib/mv/email_sync/changes/sync_member_email_to_user.ex b/lib/mv/email_sync/changes/sync_member_email_to_user.ex index 48c7955..0c0d8f7 100644 --- a/lib/mv/email_sync/changes/sync_member_email_to_user.ex +++ b/lib/mv/email_sync/changes/sync_member_email_to_user.ex @@ -41,8 +41,10 @@ defmodule Mv.EmailSync.Changes.SyncMemberEmailToUser do Ash.Changeset.around_transaction(changeset, fn cs, callback -> result = callback.(cs) + actor = Map.get(changeset.context, :actor) + with {:ok, member} <- Helpers.extract_record(result), - linked_user <- Loader.get_linked_user(member) do + linked_user <- Loader.get_linked_user(member, actor) do Helpers.sync_email_to_linked_record(result, linked_user, new_email) else _ -> result diff --git a/lib/mv/email_sync/changes/sync_user_email_to_member.ex b/lib/mv/email_sync/changes/sync_user_email_to_member.ex index 7148067..54829a4 100644 --- a/lib/mv/email_sync/changes/sync_user_email_to_member.ex +++ b/lib/mv/email_sync/changes/sync_user_email_to_member.ex @@ -33,7 +33,17 @@ defmodule Mv.EmailSync.Changes.SyncUserEmailToMember do if Map.get(context, :syncing_email, false) do changeset else - sync_email(changeset) + # Ensure actor is in changeset context - get it from context if available + actor = Map.get(changeset.context, :actor) || Map.get(context, :actor) + + changeset_with_actor = + if actor && !Map.has_key?(changeset.context, :actor) do + Ash.Changeset.put_context(changeset, :actor, actor) + else + changeset + end + + sync_email(changeset_with_actor) end end @@ -42,7 +52,7 @@ defmodule Mv.EmailSync.Changes.SyncUserEmailToMember do result = callback.(cs) with {:ok, record} <- Helpers.extract_record(result), - {:ok, user, member} <- get_user_and_member(record) do + {:ok, user, member} <- get_user_and_member(record, cs) do # When called from Member-side, we need to update the member in the result # When called from User-side, we update the linked member in DB only case record do @@ -61,15 +71,19 @@ defmodule Mv.EmailSync.Changes.SyncUserEmailToMember do end # Retrieves user and member - works for both resource types - defp get_user_and_member(%Mv.Accounts.User{} = user) do - case Loader.get_linked_member(user) do + defp get_user_and_member(%Mv.Accounts.User{} = user, changeset) do + actor = Map.get(changeset.context, :actor) + + case Loader.get_linked_member(user, actor) do nil -> {:error, :no_member} member -> {:ok, user, member} end end - defp get_user_and_member(%Mv.Membership.Member{} = member) do - case Loader.load_linked_user!(member) do + defp get_user_and_member(%Mv.Membership.Member{} = member, changeset) do + actor = Map.get(changeset.context, :actor) + + case Loader.load_linked_user!(member, actor) do {:ok, user} -> {:ok, user, member} error -> error end diff --git a/lib/mv/email_sync/loader.ex b/lib/mv/email_sync/loader.ex index ecb1038..f6f6ecc 100644 --- a/lib/mv/email_sync/loader.ex +++ b/lib/mv/email_sync/loader.ex @@ -6,11 +6,16 @@ defmodule Mv.EmailSync.Loader do @doc """ Loads the member linked to a user, returns nil if not linked or on error. - """ - def get_linked_member(%{member_id: nil}), do: nil - def get_linked_member(%{member_id: id}) do - case Ash.get(Mv.Membership.Member, id) do + Accepts optional actor for authorization. + """ + def get_linked_member(user, actor \\ nil) + def get_linked_member(%{member_id: nil}, _actor), do: nil + + def get_linked_member(%{member_id: id}, actor) do + opts = if actor, do: [actor: actor], else: [] + + case Ash.get(Mv.Membership.Member, id, opts) do {:ok, member} -> member {:error, _} -> nil end @@ -18,9 +23,13 @@ defmodule Mv.EmailSync.Loader do @doc """ Loads the user linked to a member, returns nil if not linked or on error. + + Accepts optional actor for authorization. """ - def get_linked_user(member) do - case Ash.load(member, :user) do + def get_linked_user(member, actor \\ nil) do + opts = if actor, do: [actor: actor], else: [] + + case Ash.load(member, :user, opts) do {:ok, %{user: user}} -> user {:error, _} -> nil end @@ -29,9 +38,13 @@ defmodule Mv.EmailSync.Loader do @doc """ Loads the user linked to a member, returning an error tuple if not linked. Useful when a link is required for the operation. + + Accepts optional actor for authorization. """ - def load_linked_user!(member) do - case Ash.load(member, :user) do + def load_linked_user!(member, actor \\ nil) do + opts = if actor, do: [actor: actor], else: [] + + case Ash.load(member, :user, opts) do {:ok, %{user: user}} when not is_nil(user) -> {:ok, user} {:ok, _} -> {:error, :no_linked_user} {:error, _} = error -> error