@@ -81,7 +81,10 @@ defmodule Ash.Test.Resource.UnrelatedExistsTest do
8181
8282 defmodule User do
8383 @ moduledoc false
84- use Ash.Resource , domain: Domain , data_layer: Ash.DataLayer.Ets
84+ use Ash.Resource ,
85+ domain: Domain ,
86+ data_layer: Ash.DataLayer.Ets ,
87+ authorizers: [ Ash.Policy.Authorizer ]
8588
8689 ets do
8790 private? true
@@ -93,11 +96,80 @@ defmodule Ash.Test.Resource.UnrelatedExistsTest do
9396 attribute :age , :integer , public?: true
9497 attribute :email , :string , public?: true
9598 attribute :role , :atom , default: :user , public?: true
99+ attribute :secret , :integer , public?: true
100+ end
101+
102+ actions do
103+ defaults [ :read , :destroy , create: :* , update: :* ]
104+ end
105+
106+ policies do
107+ policy always ( ) do
108+ authorize_if always ( )
109+ end
110+ end
111+
112+ field_policies do
113+ field_policy :* do
114+ authorize_if always ( )
115+ end
116+
117+ field_policy :name do
118+ authorize_if action ( [ :create , :read ] )
119+ end
120+
121+ field_policy :secret do
122+ authorize_if actor_attribute_equals ( :role , :admin )
123+ authorize_if action ( [ :create ] )
124+ end
125+ end
126+
127+ relationships do
128+ has_many :user_votes , Ash.Test.Resource.UnrelatedExistsTest.UserVote do
129+ public? true
130+ end
131+ end
132+ end
133+
134+ defmodule UserVote do
135+ @ moduledoc false
136+ use Ash.Resource ,
137+ domain: Domain ,
138+ data_layer: Ash.DataLayer.Ets ,
139+ authorizers: [ Ash.Policy.Authorizer ]
140+
141+ ets do
142+ private? true
143+ end
144+
145+ attributes do
146+ uuid_primary_key :id
147+ attribute :score , :integer , public?: true
96148 end
97149
98150 actions do
99151 defaults [ :read , :destroy , create: :* , update: :* ]
100152 end
153+
154+ policies do
155+ policy always ( ) do
156+ authorize_if always ( )
157+ end
158+ end
159+
160+ field_policies do
161+ field_policy :* do
162+ authorize_if always ( )
163+ end
164+
165+ field_policy :score do
166+ authorize_if actor_attribute_equals ( :role , :admin )
167+ end
168+ end
169+
170+ relationships do
171+ belongs_to :user , User , primary_key?: true , allow_nil?: false , public?: true
172+ end
101173 end
102174
103175 describe "basic unrelated exists expressions" do
@@ -212,9 +284,14 @@ defmodule Ash.Test.Resource.UnrelatedExistsTest do
212284
213285 describe "unrelated exists with filter_input" do
214286 setup do
215- admin = Ash . create! ( User , % { name: "Admin" , email: "[email protected] " , role: :admin } ) 216- user1 = Ash . create! ( User , % { name: "User1" , email: "[email protected] " , role: :user } ) 217- user2 = Ash . create! ( User , % { name: "User2" , email: "[email protected] " , role: :user } ) 287+ admin =
288+ Ash . create! ( User , % { name: "Admin" , email: "[email protected] " , role: :admin , secret: 40 } ) 289+
290+ user1 =
291+ Ash . create! ( User , % { name: "User1" , email: "[email protected] " , role: :user , secret: 25 } ) 292+
293+ user2 =
294+ Ash . create! ( User , % { name: "User2" , email: "[email protected] " , role: :user , secret: 30 } ) 218295
219296 Ash . create! ( Profile , % {
220297 name: "Admin" ,
@@ -349,6 +426,61 @@ defmodule Ash.Test.Resource.UnrelatedExistsTest do
349426
350427 assert length ( users ) == 3
351428 end
429+
430+ test "filter_input with unrelated exists respects field level authorization" , % {
431+ admin: admin ,
432+ user1: user1
433+ } do
434+ user1_users =
435+ User
436+ |> Ash.Query . filter_input ( expr ( exists ( Profile , age == parent ( secret ) ) ) )
437+ |> Ash . read! ( actor: user1 , authorize?: true )
438+
439+ assert user1_users == [ ]
440+
441+ admin_users =
442+ User
443+ |> Ash.Query . filter_input ( expr ( exists ( Profile , age == parent ( secret ) ) ) )
444+ |> Ash . read! ( actor: admin , authorize?: true )
445+
446+ assert length ( admin_users ) == 3
447+ end
448+
449+ test "filter_input with nested unrelated exists respects field level authorization" , % {
450+ admin: admin ,
451+ user1: user1
452+ } do
453+ UserVote
454+ |> Ash . create! ( % { user_id: user1 . id , score: 2 } )
455+
456+ user1_users =
457+ User
458+ |> Ash.Query . filter_input (
459+ expr (
460+ exists (
461+ user_votes ,
462+ score > 1 and exists ( UserVote , score > 1 )
463+ )
464+ )
465+ )
466+ |> Ash . read! ( actor: user1 , authorize?: true )
467+
468+ assert user1_users == [ ]
469+
470+ admin_users =
471+ User
472+ |> Ash.Query . filter_input (
473+ expr (
474+ exists (
475+ user_votes ,
476+ score > 1 and exists ( UserVote , score > 1 )
477+ )
478+ )
479+ )
480+ |> Ash . read! ( actor: admin , authorize?: true )
481+
482+ assert length ( admin_users ) == 1
483+ end
352484 end
353485
354486 describe "unrelated exists in calculations" do
0 commit comments