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
2 changes: 1 addition & 1 deletion lib/permit/permissions/parsed_condition.ex
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ defmodule Permit.Permissions.ParsedCondition do
check_conditions(sub_assoc, assoc_conditions)

sub_assoc when is_list(sub_assoc) ->
Enum.all?(sub_assoc, &check_conditions(&1, assoc_conditions))
Enum.any?(sub_assoc, &check_conditions(&1, assoc_conditions))

sub_assoc ->
sub_assoc == assoc_conditions
Expand Down
31 changes: 29 additions & 2 deletions test/permit/permissions/condition_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -78,27 +78,54 @@ defmodule Permit.Permissions.ConditionTest do
|> ParsedCondition.satisfied?(test_object, nil)
end

test "should not satisfy nested has-many associations" do
test "should use ANY semantics for has-many associations" do
# None of the actors have age 123, so should fail
condition = {:actors, {:==, [age: 123]}}

test_object = %Movie{actors: [%Actor{age: 666}]}

refute ConditionParser.build(condition)
|> ParsedCondition.satisfied?(test_object, nil)

# With ANY semantics: at least one actor has age 666, so should PASS
condition = {:actors, {:==, [age: 666]}}

test_object = %Movie{actors: [%Actor{age: 123}, %Actor{age: 666}]}

refute ConditionParser.build(condition)
assert ConditionParser.build(condition)
|> ParsedCondition.satisfied?(test_object, nil)

# At least one actor matches both age AND name conditions
condition = {:actors, {:==, [age: 123, name: "test"]}}

test_object = %Movie{
actors: [%Actor{age: 123, name: "test"}, %Actor{age: 123, name: "test_666"}]
}

# With ANY semantics: first actor matches both conditions
assert ConditionParser.build(condition)
|> ParsedCondition.satisfied?(test_object, nil)

# No actor matches both conditions simultaneously
condition = {:actors, {:==, [age: 123, name: "test"]}}

test_object = %Movie{
actors: [%Actor{age: 666, name: "test"}, %Actor{age: 123, name: "wrong"}]
}

# No single actor has both age 123 AND name "test"
refute ConditionParser.build(condition)
|> ParsedCondition.satisfied?(test_object, nil)
end

test "should not satisfy nested has-many associations when association is empty" do
condition = {:actors, {:==, [age: 123]}}

# An empty list of actors should NOT satisfy the condition
# because there is no actor with age 123
test_object = %Movie{actors: []}

# Changed to any? semantic (PR #22 in permit_ecto)
refute ConditionParser.build(condition)
|> ParsedCondition.satisfied?(test_object, nil)
end
Expand Down