From 555ae151737e81fae27964c3d1d9679ecc07702e Mon Sep 17 00:00:00 2001 From: Moritz Date: Tue, 13 Jan 2026 14:05:39 +0100 Subject: [PATCH] feat: Add shared helper functions for actor handling - Add Mv.Helpers module with ash_actor_opts/1 helper - Add current_actor/1 with @spec to LiveHelpers - Add ash_actor_opts/1 delegate and submit_form/3 wrapper to LiveHelpers - Standardize actor access pattern across LiveViews --- lib/mv/helpers.ex | 27 +++++++++++++++++++++++++++ lib/mv_web/live_helpers.ex | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 lib/mv/helpers.ex diff --git a/lib/mv/helpers.ex b/lib/mv/helpers.ex new file mode 100644 index 0000000..e20db67 --- /dev/null +++ b/lib/mv/helpers.ex @@ -0,0 +1,27 @@ +defmodule Mv.Helpers do + @moduledoc """ + Shared helper functions used across the Mv application. + + Provides utilities that are not specific to a single domain or layer. + """ + + @doc """ + Converts an actor to Ash options list for authorization. + Returns empty list if actor is nil. + + This helper ensures consistent actor handling across all Ash operations + in the application, whether called from LiveViews, changes, validations, + or other contexts. + + ## Examples + + opts = ash_actor_opts(actor) + Ash.read(query, opts) + + opts = ash_actor_opts(nil) + # => [] + """ + @spec ash_actor_opts(Mv.Accounts.User.t() | nil) :: keyword() + def ash_actor_opts(nil), do: [] + def ash_actor_opts(actor) when not is_nil(actor), do: [actor: actor] +end diff --git a/lib/mv_web/live_helpers.ex b/lib/mv_web/live_helpers.ex index 6af71ec..95d8235 100644 --- a/lib/mv_web/live_helpers.ex +++ b/lib/mv_web/live_helpers.ex @@ -71,7 +71,41 @@ defmodule MvWeb.LiveHelpers do actor = current_actor(socket) members = Membership.list_members!(actor: actor) """ + @spec current_actor(Phoenix.LiveView.Socket.t()) :: Mv.Accounts.User.t() | nil def current_actor(socket) do socket.assigns[:current_user] || socket.assigns.current_user end + + @doc """ + Converts an actor to Ash options list for authorization. + Returns empty list if actor is nil. + + Delegates to `Mv.Helpers.ash_actor_opts/1` for consistency across the application. + + ## Examples + + opts = ash_actor_opts(actor) + Ash.read(query, opts) + """ + @spec ash_actor_opts(Mv.Accounts.User.t() | nil) :: keyword() + defdelegate ash_actor_opts(actor), to: Mv.Helpers + + @doc """ + Submits an AshPhoenix form with consistent actor handling. + + This wrapper ensures that actor is always passed via `action_opts` + in a consistent manner across all LiveViews. + + ## Examples + + case submit_form(form, params, actor) do + {:ok, resource} -> # success + {:error, form} -> # validation errors + end + """ + @spec submit_form(AshPhoenix.Form.t(), map(), Mv.Accounts.User.t() | nil) :: + {:ok, Ash.Resource.t()} | {:error, AshPhoenix.Form.t()} + def submit_form(form, params, actor) do + AshPhoenix.Form.submit(form, params: params, action_opts: ash_actor_opts(actor)) + end end