defmodule Mv.Membership.JoinRequest.Changes.ApproveRequest do @moduledoc """ Sets the join request to approved and records the reviewer. Only transitions from :submitted status. If already approved, returns error (idempotency guard via status validation). Promotion to Member is handled by the domain function approve_join_request/2 after calling this action. """ use Ash.Resource.Change @spec change(Ash.Changeset.t(), keyword(), Ash.Resource.Change.context()) :: Ash.Changeset.t() def change(changeset, _opts, context) do current_status = Ash.Changeset.get_data(changeset, :status) if current_status == :submitted do reviewed_by_id = actor_id(context.actor) changeset |> Ash.Changeset.force_change_attribute(:status, :approved) |> Ash.Changeset.force_change_attribute(:approved_at, DateTime.utc_now()) |> Ash.Changeset.force_change_attribute(:reviewed_by_user_id, reviewed_by_id) else Ash.Changeset.add_error(changeset, field: :status, message: "can only approve a submitted join request (current status: #{current_status})" ) end end defp actor_id(nil), do: nil defp actor_id(actor) when is_map(actor) do Map.get(actor, :id) || Map.get(actor, "id") end defp actor_id(_), do: nil end