Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions lib/ash_backpex/live_resource/transformers/generate_backpex.ex
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,25 @@ defmodule AshBackpex.LiveResource.Transformers.GenerateBackpex do
def can?(_assigns, :delete, _item), do: false
end

# Fallback for custom item actions and any other actions
# Checks Ash authorization if a matching action exists, otherwise allows by default
def can?(assigns, action, item) do
case Ash.Resource.Info.action(@resource, action) do
nil ->
true

ash_action ->
target =
if is_struct(item) and item.__struct__ == @resource do
{item, ash_action.name}
else
{@resource, ash_action.name}
end

Ash.can?(target, Map.get(assigns, :current_user))
end
end

def maybe_default_options(assigns) do
case assigns do
%{field: {attribute_name, _field_cfg}} ->
Expand Down
14 changes: 14 additions & 0 deletions test/ash_backpex/authz_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,20 @@ defmodule AshBackpex.AuthzTest do
end
end

describe "AshBackpex.LiveResource :: can? with custom item actions" do
test "returns true for unknown actions that don't exist on the resource" do
# :promote is not an Ash action on Item, so fallback returns true
assert TestCustomItemActionLive.can?(%{current_user: nil}, :promote, %{})
assert TestCustomItemActionLive.can?(%{current_user: nil}, :some_unknown_action, %{})
end

test "checks Ash authorization when action exists on resource" do
# :read exists on Item resource, so it checks Ash.can?
# Item has no policies, so it should return true
assert TestCustomItemActionLive.can?(%{current_user: nil}, :read, %{})
end
end

describe "AshBackpex.Adapter :: it can" do
test "list/3" do
user = user()
Expand Down
43 changes: 43 additions & 0 deletions test/support/test_live.ex
Original file line number Diff line number Diff line change
Expand Up @@ -113,3 +113,46 @@ defmodule TestLayout do
"""
end
end

# Custom item action for testing can?/3 fallback
defmodule TestPromoteItemAction do
@moduledoc false
use BackpexWeb, :item_action

@impl Backpex.ItemAction
def icon(assigns, _item) do
~H"""
<Backpex.HTML.CoreComponents.icon
name="hero-arrow-up-circle"
class="h-5 w-5 cursor-pointer transition duration-75 hover:scale-110 hover:text-success"
/>
"""
end

@impl Backpex.ItemAction
def label(_assigns, _item), do: "Promote"

@impl Backpex.ItemAction
def handle(socket, _items, _data) do
{:ok, socket}
end
end

# LiveResource with custom item action for testing can?/3 fallback
defmodule TestCustomItemActionLive do
@moduledoc false
use AshBackpex.LiveResource

backpex do
resource(AshBackpex.TestDomain.Item)
layout({TestLayout, :admin})

item_actions do
action :promote, TestPromoteItemAction
end

fields do
field(:name)
end
end
end
Loading