Ash FrameworkAF
Ash Framework6mo ago
15 replies
Shahryar

Best option to read a relationship which has policy in Action

Hi, I so much searching today and with AI to be allowed load a relations in action, but i think there is better way!

for example in user resource get_by_subject I added this:
read :get_by_subject do
    description "Get a user by the subject claim in a JWT"
    argument :subject, :string, allow_nil?: false
    get? true
    prepare AshAuthentication.Preparations.FilterBySubject

    prepare fn query, _context ->
    query
    |> Ash.Query.load([:permissions, :permission_values])
    end
end


permissions is a many_to_many
many_to_many :permissions, MishkaCms.Accounts.Permission do
   through MishkaCms.Accounts.UserPermission
   source_attribute_on_join_resource :user_id
   destination_attribute_on_join_resource :permission_id
end


So i added this Policy in resource b and c
bypass always() do
   description "Allow when accessed through relationship"
   authorize_if expr(not is_nil(^context(:accessing_from)))
end

So it let me to to get the data of permissions before it it just return empty list []

I tried to add authorize?: false To |> Ash.Query.load([:permissions, :permission_values], authorize?: false)
But it did not work and return empty list

I think this (authorize_if expr(not is_nil(^context(:accessing_from)))) way can be a problem for me base on a mistake leak the data

Thank you in advance!
Solution
Finally i found :)) i created this debugger 😂 😂😂
defmodule MishkaCms.Accounts.Checks.DebugAccessingFrom do
  use Ash.Policy.SimpleCheck

  def describe(_opts), do: "Debug accessing_from"

  def match?(_actor, %{context: context} = _authorizer, _opts) do
    case context[:accessing_from] do
      nil -> 
        IO.puts("accessing_from is nil")
        false
      accessing_from ->
        IO.inspect(accessing_from, label: "accessing_from content", limit: :infinity)
        # Check what fields are available
        IO.inspect(Map.keys(accessing_from), label: "accessing_from keys")
        if Map.has_key?(accessing_from, :source) do
          IO.inspect(accessing_from.source, label: "Source resource")
        end
        if Map.has_key?(accessing_from, :name) do
          IO.inspect(accessing_from.name, label: "Relationship name")
        end
        true
    end
  end
end



in my user
many_to_many :permissions, MishkaCms.Accounts.Permission do
      through MishkaCms.Accounts.UserPermission
      source_attribute_on_join_resource :user_id
      destination_attribute_on_join_resource :permission_id
    end


inside MishkaCms.Accounts.Permission

policies do
    policy always() do
      authorize_if accessing_from(MishkaCms.Accounts.User, :permissions)

      authorize_if {MishkaCms.Accounts.Checks.AccessPermissions,
                    permissions: ["admin:dashboard:*", "admin:api:*", "*"]}
    end
  end


and MishkaCms.Accounts.UserPermission
policies do
    policy always() do
      authorize_if accessing_from(MishkaCms.Accounts.User, :permissions_join_assoc)

      authorize_if {MishkaCms.Accounts.Checks.AccessPermissions,
                    permissions: ["admin:dashboard:*", "admin:api:*", "*"]}
    end
  end
Was this page helpful?