Skip to content

Commit 9b3f121

Browse files
Merge branch '1169'
2 parents 78ea1ed + c8fa7d5 commit 9b3f121

12 files changed

Lines changed: 120 additions & 52 deletions

File tree

REUSE.toml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# SPDX-FileCopyrightText: 2019 ash contributors <https://github.com/ash-project/ash/graphs/contributors>
2+
#
3+
# SPDX-License-Identifier: MIT
4+
5+
version = 1
6+
7+
# AALang-Gab assets are JSON-LD and other formats that cannot carry SPDX tags inline;
8+
# annotate the tree for REUSE compliance (see https://reuse.software/spec/).
9+
[[annotations]]
10+
path = "lib/AALang-Gab/.gitignore"
11+
SPDX-FileCopyrightText = "2019 ash contributors <https://github.com/ash-project/ash/graphs/contributors>"
12+
SPDX-License-Identifier = "MIT"
13+
14+
[[annotations]]
15+
path = "lib/AALang-Gab/**/*.jsonld"
16+
SPDX-FileCopyrightText = "2019 ash contributors <https://github.com/ash-project/ash/graphs/contributors>"
17+
SPDX-License-Identifier = "MIT"
18+
19+
[[annotations]]
20+
path = "lib/AALang-Gab/**/*.md"
21+
SPDX-FileCopyrightText = "2019 ash contributors <https://github.com/ash-project/ash/graphs/contributors>"
22+
SPDX-License-Identifier = "MIT"
23+
24+
[[annotations]]
25+
path = "lib/AALang-Gab/**/*.py"
26+
SPDX-FileCopyrightText = "2019 ash contributors <https://github.com/ash-project/ash/graphs/contributors>"
27+
SPDX-License-Identifier = "MIT"
28+
29+
[[annotations]]
30+
path = "lib/AALang-Gab/**/*.aacomp"
31+
SPDX-FileCopyrightText = "2019 ash contributors <https://github.com/ash-project/ash/graphs/contributors>"
32+
SPDX-License-Identifier = "MIT"

lib/ash/actions/action.ex

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -372,9 +372,6 @@ defmodule Ash.Actions.Action do
372372
373373
Received #{inspect(filter)} when authorizing #{inspect(input.resource)}.#{input.action.name}
374374
"""
375-
376-
:forbidden ->
377-
{:halt, {:error, Ash.Authorizer.exception(authorizer, :forbidden, authorizer_state)}}
378375
end
379376
end
380377
)

lib/ash/actions/create/create.ex

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -588,11 +588,10 @@ defmodule Ash.Actions.Create do
588588
end
589589

590590
defp validate_manual_action_return_result!(
591-
{:ok, %resource{}, notifications} = result,
591+
{:ok, %resource{}, %{notifications: _notifications}} = result,
592592
resource,
593593
_
594-
)
595-
when is_list(notifications) do
594+
) do
596595
result
597596
end
598597

lib/ash/actions/managed_relationships.ex

Lines changed: 39 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -963,28 +963,30 @@ defmodule Ash.Actions.ManagedRelationships do
963963
opts,
964964
notifications
965965
),
966-
creates <- additional_creates ++ creates,
967-
# Batch creates
966+
# Apply updates before batch-creating new related records. This preserves
967+
# the relative ordering of already-present vs newly-created items for
968+
# relationship lists backed by order-sensitive data layers (e.g. ETS).
968969
{:ok, new_value, notifications} <-
969-
batch_creates(
970-
creates,
970+
process_updates(
971+
updates,
971972
record,
972973
new_value,
973974
relationship,
974975
changeset,
975976
actor,
976-
index,
977+
pkeys,
977978
opts,
978979
notifications
979980
) do
980-
process_updates(
981-
updates,
981+
# Batch creates
982+
batch_creates(
983+
additional_creates ++ creates,
982984
record,
983985
new_value,
984986
relationship,
985987
changeset,
986988
actor,
987-
pkeys,
989+
index,
988990
opts,
989991
notifications
990992
)
@@ -1387,10 +1389,13 @@ defmodule Ash.Actions.ManagedRelationships do
13871389
end)
13881390

13891391
inputs_to_bulk_create =
1390-
Enum.map(map_inputs_with_joins, fn {{input, join_params}, _} ->
1391-
{input, join_params}
1392+
Enum.map(map_inputs_with_joins, fn {{input, join_params}, {_orig_input, input_index}} ->
1393+
{input, join_params, input_index}
13921394
end)
13931395

1396+
input_indices_to_bulk_create =
1397+
Enum.map(inputs_to_bulk_create, fn {_, _, input_index} -> input_index end)
1398+
13941399
if inputs_to_bulk_create == [] do
13951400
# Only struct inputs - just create join records
13961401
create_join_records_for_m2m(
@@ -1406,7 +1411,7 @@ defmodule Ash.Actions.ManagedRelationships do
14061411
)
14071412
else
14081413
# Bulk create destination records
1409-
bulk_inputs = Enum.map(inputs_to_bulk_create, fn {input, _} -> input end)
1414+
bulk_inputs = Enum.map(inputs_to_bulk_create, fn {input, _, _} -> input end)
14101415

14111416
bulk_context =
14121417
Map.take(changeset.context, [:shared])
@@ -1446,7 +1451,7 @@ defmodule Ash.Actions.ManagedRelationships do
14461451
created_with_joins =
14471452
Enum.zip(
14481453
created_records || [],
1449-
Enum.map(inputs_to_bulk_create, fn {_, join} -> join end)
1454+
Enum.map(inputs_to_bulk_create, fn {_, join, _} -> join end)
14501455
)
14511456
|> Enum.map(fn {created, join_params} -> {created, join_params} end)
14521457

@@ -1469,7 +1474,28 @@ defmodule Ash.Actions.ManagedRelationships do
14691474
error = List.first(List.wrap(errors))
14701475

14711476
if error do
1472-
{:error, add_bread_crumb(error, relationship, :create)}
1477+
# Bulk create errors don't carry the manage_relationship input index
1478+
# in a way AshPhoenix can route the nested errors. Reattach the
1479+
# index based on the position in the bulk inputs we sent.
1480+
bulk_index =
1481+
error
1482+
|> Map.get(:meta)
1483+
|> case do
1484+
%{bulk_create_index: idx} -> idx
1485+
_ -> nil
1486+
end || Map.get(error, :bulk_create_index) || 0
1487+
1488+
input_index = Enum.at(input_indices_to_bulk_create, bulk_index) || 0
1489+
1490+
relationship_error_key =
1491+
opts
1492+
|> Keyword.get(:meta, [])
1493+
|> Keyword.get(:id) || relationship.name
1494+
1495+
error
1496+
|> add_bread_crumb(relationship, :create)
1497+
|> Ash.Error.set_path([relationship_error_key, input_index])
1498+
|> then(&{:error, &1})
14731499
else
14741500
{:error,
14751501
add_bread_crumb(

lib/ash/actions/read/read.ex

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3730,6 +3730,7 @@ defmodule Ash.Actions.Read do
37303730
end
37313731
end
37323732

3733+
@dialyzer {:nowarn_function, do_add_field_level_auth: 3}
37333734
defp do_add_field_level_auth(query, domain, opts) do
37343735
data = %{
37353736
query: query,
@@ -4181,6 +4182,7 @@ defmodule Ash.Actions.Read do
41814182
|> then(&{&1, query})
41824183
end
41834184

4185+
@dialyzer {:nowarn_function, validate_manual_action_return_result!: 3}
41844186
defp validate_manual_action_return_result!({:ok, list} = result, _resource, _)
41854187
when is_list(list) do
41864188
result

lib/ash/actions/read/relationships.ex

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -513,7 +513,6 @@ defmodule Ash.Actions.Read.Relationships do
513513
|> case do
514514
{:ok, result} -> {:ok, result}
515515
{:error, error} -> {:error, error}
516-
result when is_list(result) -> {:ok, result}
517516
end
518517
|> case do
519518
{:ok, result_records} ->

lib/ash/actions/update/update.ex

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -688,11 +688,10 @@ defmodule Ash.Actions.Update do
688688
end
689689

690690
defp validate_manual_action_return_result!(
691-
{:ok, %resource{}, notifications} = result,
691+
{:ok, %resource{}, %{notifications: _notifications}} = result,
692692
resource,
693693
_
694-
)
695-
when is_list(notifications) do
694+
) do
696695
result
697696
end
698697

lib/ash/can.ex

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -667,11 +667,6 @@ defmodule Ash.Can do
667667
{:authorized, authorizer_state} ->
668668
{:cont, {true, query, [{authorizer, authorizer_state, context} | authorizers]}}
669669

670-
:forbidden ->
671-
{:halt,
672-
{false, Ash.Authorizer.exception(authorizer, :forbidden, authorizer_state),
673-
{authorizer, authorizer_state, context}}}
674-
675670
_ when not is_nil(context.action_input) ->
676671
raise """
677672
Cannot use filter or runtime checks with generic actions

lib/ash/error/forbidden/policy.ex

Lines changed: 40 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
# SPDX-License-Identifier: MIT
44

55
defmodule Ash.Error.Forbidden.Policy do
6+
@dialyzer {:nowarn_function, describe: 5}
67
@moduledoc "Raised when policy authorization for an action fails"
78

89
require Logger
@@ -495,31 +496,49 @@ defmodule Ash.Error.Forbidden.Policy do
495496

496497
if subject && function_exported?(mod, :expand_description, 3) do
497498
authorizer =
498-
%Ash.Policy.Authorizer{
499-
subject: subject,
500-
actor: actor,
501-
resource: resource
502-
}
503-
504-
key =
505499
case subject do
506-
%Ash.Changeset{} -> :changeset
507-
%Ash.Query{} -> :query
508-
%Ash.ActionInput{} -> :action_input
500+
%Ash.Changeset{} = subject ->
501+
%Ash.Policy.Authorizer{
502+
subject: subject,
503+
actor: actor,
504+
resource: resource
505+
}
506+
|> Map.put(:changeset, subject)
507+
508+
%Ash.Query{} = subject ->
509+
%Ash.Policy.Authorizer{
510+
subject: subject,
511+
actor: actor,
512+
resource: resource
513+
}
514+
|> Map.put(:query, subject)
515+
516+
%Ash.ActionInput{} = subject ->
517+
%Ash.Policy.Authorizer{
518+
subject: subject,
519+
actor: actor,
520+
resource: resource
521+
}
522+
|> Map.put(:action_input, subject)
523+
524+
_ ->
525+
nil
509526
end
510527

511-
authorizer = Map.put(authorizer, key, subject)
512-
513-
case Ash.Policy.Check.expand_description(mod, actor, authorizer, opts) do
514-
{:ok, desc} ->
515-
if Ash.Policy.Check.prefer_expanded_description?(mod) do
516-
desc
517-
else
518-
description <> " | #{desc}"
519-
end
528+
if authorizer do
529+
case Ash.Policy.Check.expand_description(mod, actor, authorizer, opts) do
530+
{:ok, desc} ->
531+
if Ash.Policy.Check.prefer_expanded_description?(mod) do
532+
desc
533+
else
534+
description <> " | #{desc}"
535+
end
520536

521-
_ ->
522-
description
537+
_ ->
538+
description
539+
end
540+
else
541+
description
523542
end
524543
else
525544
description

lib/ash/policy/chart/mermaid.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ defmodule Ash.Policy.Chart.Mermaid do
196196
description = Ash.Policy.Check.describe(check.check_module, check.check_opts)
197197

198198
description =
199-
if description && description != "" do
199+
if description != "" do
200200
"{#{quote_and_escape(description)}}"
201201
else
202202
"{}"

0 commit comments

Comments
 (0)