Skip to content

Commit 507b7f4

Browse files
Change order of args in verify_record/3 and add delegation as do?/3
1 parent cea451c commit 507b7f4

5 files changed

Lines changed: 55 additions & 7 deletions

File tree

CHANGELOG.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,21 @@ All notable changes to this project will be documented in this file.
66

77
## [Unreleased]
88

9+
- [Breaking] Change order of args in `Permit.verify_record/3` and add delegation as `do?/3` when doing `use Permit`.
10+
11+
This way, permisisons to perform a dynamically computed action can be checked like this:
12+
```elixir
13+
action = :read
14+
can(user) |> do?(action, %Item{id: 1})
15+
```
16+
instead of the previously required, rather clumsy, and undocumented notation:
17+
18+
```elixir
19+
# Note: this is the previously used argument order; as of now, arguments 2 and 3 have been reversed.
20+
can(user) |> Permit.verify_record(%Item{id: 1}, action)
21+
```
22+
If you happened to use `Permit.verify_record(3)`, the way to migrate is swapping arguments 2 and 3 in all calls, or - better still - migrating to the `do?/3` syntactic sugar.
23+
924
## [v0.2.1]
1025
### Fixed
1126
- Fix runtime and compile-time warnings (#38).

lib/permit.ex

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ defmodule Permit do
122122
@spec unquote(predicate)(Permit.Context.t(), Types.object_or_resource_module()) ::
123123
boolean()
124124
def unquote(predicate)(authorization, resource) do
125-
Permit.verify_record(authorization, resource, unquote(name))
125+
Permit.verify_record(authorization, unquote(name), resource)
126126
end
127127
end
128128
end)
@@ -153,6 +153,10 @@ defmodule Permit do
153153
defoverridable resolver_module: 0
154154

155155
unquote(predicates)
156+
157+
defdelegate do?(authorization, action, resource_or_module),
158+
to: Permit,
159+
as: :verify_record
156160
end
157161
end
158162

@@ -166,17 +170,17 @@ defmodule Permit do
166170
end
167171

168172
@doc false
169-
@spec verify_record(Permit.Context.t(), Types.object_or_resource_module(), Types.action_group()) ::
173+
@spec verify_record(Permit.Context.t(), Types.action_group(), Types.object_or_resource_module()) ::
170174
boolean()
171175
def verify_record(
172176
%{
173177
permissions: permissions,
174178
subject: subject
175179
} = _authorization,
176-
record,
177-
action
180+
action,
181+
resource_or_module
178182
) do
179-
Permissions.granted?(permissions, action, record, subject)
183+
Permissions.granted?(permissions, action, resource_or_module, subject)
180184
end
181185

182186
defp add_predicate_name(atom),

lib/permit/actions/traversal.ex

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,14 @@ defmodule Permit.Actions.Traversal do
3737
disj_function = funs[:disj]
3838
value_function = funs[:value]
3939

40+
# case Map.get(forest, :action_name, []) do
4041
case forest[action_name] do
4142
# action_name can be directly checked
4243
# in this case, the entire trace should be verified.
4344
# For example, if :see implies :read implies :index,
4445
# then asking for :index verifies whether explicitly
4546
# given is the permission to :see, or :read, or :index
47+
4648
[] ->
4749
[action_name | trace]
4850
|> Enum.map(value_function)
@@ -54,7 +56,12 @@ defmodule Permit.Actions.Traversal do
5456
|> Enum.map(&traverse(f, &1, funs, [action_name | trace]))
5557
|> conj_function.()
5658

59+
# TODO: dubious after the introduction of reading out actions from the router
60+
#
61+
# Action not defined in the action definitions file. Assume it's an action
62+
# that doesn't map to any different action in the forest.
5763
nil ->
64+
# traverse(%{f | forest: Map.put(forest, action_name, [])}, action_name, funs, trace)
5865
throw({:not_defined, action_name})
5966
end
6067
end

lib/permit/resolver_base.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ defmodule Permit.ResolverBase do
9292
def authorized?(subject, authorization_module, resource_or_module, action) do
9393
auth = authorization_module.can(subject)
9494
actions_module = authorization_module.actions_module()
95-
verify_fn = &Permit.verify_record(auth, resource_or_module, &1)
95+
verify_fn = &Permit.verify_record(auth, &1, resource_or_module)
9696

9797
Permit.Actions.verify_transitively!(actions_module, action, verify_fn)
9898
end

test/permit/permit_test.exs

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,14 @@ defmodule Permit.PermitTest do
22
@moduledoc false
33
use Permit.Case
44

5+
defmodule TestUser do
6+
defstruct [:id]
7+
end
8+
9+
defmodule TestItem do
10+
defstruct [:id]
11+
end
12+
513
defmodule TestActions do
614
use Permit.Actions
715

@@ -21,7 +29,7 @@ defmodule Permit.PermitTest do
2129
use Permit.Permissions,
2230
actions_module: TestActions
2331

24-
def can(_role), do: permit()
32+
def can(_role), do: permit() |> a(TestItem)
2533
end
2634

2735
defmodule TestAuthorization do
@@ -45,5 +53,19 @@ defmodule Permit.PermitTest do
4553
assert predicate in TestAuthorization.__info__(:functions)
4654
end)
4755
end
56+
57+
test "should delegate do?/3 to Permit.verify_record/3" do
58+
assert TestAuthorization.can(%TestUser{id: 1})
59+
|> TestAuthorization.do?(:a, TestItem)
60+
61+
assert TestAuthorization.can(%TestUser{id: 1})
62+
|> TestAuthorization.do?(:a, %TestItem{id: 1})
63+
64+
refute TestAuthorization.can(%TestUser{id: 1})
65+
|> TestAuthorization.do?(:b, TestItem)
66+
67+
refute TestAuthorization.can(%TestUser{id: 1})
68+
|> TestAuthorization.do?(:b, %TestItem{id: 1})
69+
end
4870
end
4971
end

0 commit comments

Comments
 (0)