-
-
Notifications
You must be signed in to change notification settings - Fork 217
/
relating_to_actor.ex
78 lines (66 loc) · 2.54 KB
/
relating_to_actor.ex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
defmodule Ash.Policy.Check.RelatingToActor do
@moduledoc "This check is true when the specified relationship is being changed to the current actor."
use Ash.Policy.FilterCheck
@impl true
def describe(opts) do
"relating this.#{opts[:relationship]} to the actor"
end
@impl true
def filter(nil, _, _), do: false
def filter(actor, %{changeset: %Ash.Changeset{} = changeset}, opts) do
resource = changeset.resource
relationship = Ash.Resource.Info.relationship(resource, opts[:relationship])
if is_nil(Map.get(actor, relationship.destination_attribute)) do
false
else
unless relationship.type == :belongs_to do
raise "Can only use `belongs_to` relationships in relating_to_actor checks"
end
if Ash.Changeset.changing_attribute?(changeset, relationship.source_attribute) do
if changeset.action.type == :create do
actor_value = Map.get(actor, relationship.destination_attribute)
case Map.fetch(changeset.attributes, relationship.source_attribute) do
{:ok, ^actor_value} ->
if Keyword.has_key?(changeset.atomics, relationship.source_attribute) do
expr(
^atomic_ref(relationship.source_attribute) ==
^Map.get(actor, relationship.destination_attribute)
)
else
true
end
_ ->
false
end
else
if Keyword.has_key?(changeset.atomics, relationship.source_attribute) do
expr(
^atomic_ref(relationship.source_attribute) ==
^Map.get(actor, relationship.destination_attribute)
)
else
Ash.Changeset.get_attribute(changeset, relationship.source_attribute) ==
Map.get(actor, relationship.destination_attribute)
end
end
else
case changeset.relationships[relationship.name] do
[{[input], opts}] ->
primary_key = Ash.Resource.Info.primary_key(relationship.destination)
actor_keys = take_keys(actor, primary_key)
input_keys = take_keys(input, primary_key)
opts[:on_lookup] == :relate and Enum.all?(actor_keys, & &1) &&
Enum.all?(input_keys, & &1) and input_keys == actor_keys
_ ->
false
end
end
end
end
def filter(_, _, _), do: false
defp take_keys(input, primary_key) do
Enum.map(primary_key, fn key ->
Map.get(input, key) || Map.get(input, to_string(key))
end)
end
end