mirror of
https://github.com/ash-project/ash.git
synced 2024-09-20 05:23:03 +12:00
fix: properly enforce tenancy on all mutative actions
This commit is contained in:
parent
9de400de9c
commit
e1dffc0c0c
4 changed files with 63 additions and 3 deletions
|
@ -509,6 +509,15 @@ defmodule Ash.Actions.Create do
|
||||||
defp manage_relationships(other, _, _, _), do: other
|
defp manage_relationships(other, _, _, _), do: other
|
||||||
|
|
||||||
defp set_tenant(changeset) do
|
defp set_tenant(changeset) do
|
||||||
|
changeset =
|
||||||
|
case changeset.data do
|
||||||
|
%{__metadata__: %{tenant: tenant}} ->
|
||||||
|
Ash.Changeset.set_tenant(changeset, tenant)
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
changeset
|
||||||
|
end
|
||||||
|
|
||||||
if changeset.tenant &&
|
if changeset.tenant &&
|
||||||
Ash.Resource.Info.multitenancy_strategy(changeset.resource) == :attribute do
|
Ash.Resource.Info.multitenancy_strategy(changeset.resource) == :attribute do
|
||||||
attribute = Ash.Resource.Info.multitenancy_attribute(changeset.resource)
|
attribute = Ash.Resource.Info.multitenancy_attribute(changeset.resource)
|
||||||
|
@ -517,7 +526,15 @@ defmodule Ash.Actions.Create do
|
||||||
|
|
||||||
Ash.Changeset.force_change_attribute(changeset, attribute, attribute_value)
|
Ash.Changeset.force_change_attribute(changeset, attribute, attribute_value)
|
||||||
else
|
else
|
||||||
changeset
|
if is_nil(Ash.Resource.Info.multitenancy_strategy(changeset.resource)) ||
|
||||||
|
Ash.Resource.Info.multitenancy_global?(changeset.resource) || changeset.tenant do
|
||||||
|
changeset
|
||||||
|
else
|
||||||
|
Ash.Changeset.add_error(
|
||||||
|
changeset,
|
||||||
|
Ash.Error.Invalid.TenantRequired.exception(resource: changeset.resource)
|
||||||
|
)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -267,6 +267,14 @@ defmodule Ash.Actions.Destroy do
|
||||||
end
|
end
|
||||||
|
|
||||||
defp set_tenant(changeset) do
|
defp set_tenant(changeset) do
|
||||||
|
changeset =
|
||||||
|
case changeset.data do
|
||||||
|
%{__metadata__: %{tenant: tenant}} ->
|
||||||
|
Ash.Changeset.set_tenant(changeset, tenant)
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
changeset
|
||||||
|
end
|
||||||
if changeset.tenant &&
|
if changeset.tenant &&
|
||||||
Ash.Resource.Info.multitenancy_strategy(changeset.resource) == :attribute do
|
Ash.Resource.Info.multitenancy_strategy(changeset.resource) == :attribute do
|
||||||
attribute = Ash.Resource.Info.multitenancy_attribute(changeset.resource)
|
attribute = Ash.Resource.Info.multitenancy_attribute(changeset.resource)
|
||||||
|
@ -276,7 +284,15 @@ defmodule Ash.Actions.Destroy do
|
||||||
|
|
||||||
Ash.Changeset.filter(changeset, [{attribute, attribute_value}])
|
Ash.Changeset.filter(changeset, [{attribute, attribute_value}])
|
||||||
else
|
else
|
||||||
changeset
|
if is_nil(Ash.Resource.Info.multitenancy_strategy(changeset.resource)) ||
|
||||||
|
Ash.Resource.Info.multitenancy_global?(changeset.resource) || changeset.tenant do
|
||||||
|
changeset
|
||||||
|
else
|
||||||
|
Ash.Changeset.add_error(
|
||||||
|
changeset,
|
||||||
|
Ash.Error.Invalid.TenantRequired.exception(resource: changeset.resource)
|
||||||
|
)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -622,7 +622,15 @@ defmodule Ash.Actions.Update do
|
||||||
|
|
||||||
Ash.Changeset.filter(changeset, expr(^ref(attribute) == ^attribute_value))
|
Ash.Changeset.filter(changeset, expr(^ref(attribute) == ^attribute_value))
|
||||||
else
|
else
|
||||||
changeset
|
if is_nil(Ash.Resource.Info.multitenancy_strategy(changeset.resource)) ||
|
||||||
|
Ash.Resource.Info.multitenancy_global?(changeset.resource) || changeset.tenant do
|
||||||
|
changeset
|
||||||
|
else
|
||||||
|
Ash.Changeset.add_error(
|
||||||
|
changeset,
|
||||||
|
Ash.Error.Invalid.TenantRequired.exception(resource: changeset.resource)
|
||||||
|
)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -311,6 +311,14 @@ defmodule Ash.Actions.MultitenancyTest do
|
||||||
|> Ash.create!()
|
|> Ash.create!()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "an error is produced when a tenant is not specified" do
|
||||||
|
assert_raise Ash.Error.Invalid, ~r/require a tenant to be specified/, fn ->
|
||||||
|
User
|
||||||
|
|> Ash.Changeset.for_create(:create, %{})
|
||||||
|
|> Ash.create!()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
test "a record written to one tenant cannot be read from another", %{
|
test "a record written to one tenant cannot be read from another", %{
|
||||||
tenant1: tenant1,
|
tenant1: tenant1,
|
||||||
tenant2: tenant2
|
tenant2: tenant2
|
||||||
|
@ -411,6 +419,17 @@ defmodule Ash.Actions.MultitenancyTest do
|
||||||
assert User |> Ash.Query.set_tenant(tenant2) |> Ash.read!() == []
|
assert User |> Ash.Query.set_tenant(tenant2) |> Ash.read!() == []
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "updates require a tenant as well", %{tenant1: tenant1} do
|
||||||
|
assert_raise Ash.Error.Invalid, ~r/require a tenant to be specified/, fn ->
|
||||||
|
User
|
||||||
|
|> Ash.Changeset.for_create(:create, %{}, tenant: tenant1)
|
||||||
|
|> Ash.create!()
|
||||||
|
|> Map.update!(:__metadata__, &Map.delete(&1, :tenant))
|
||||||
|
|> Ash.Changeset.for_update(:update, %{})
|
||||||
|
|> Ash.update!()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
test "a record for a different tenant cant be updated from the other one", %{
|
test "a record for a different tenant cant be updated from the other one", %{
|
||||||
tenant1: tenant1,
|
tenant1: tenant1,
|
||||||
tenant2: tenant2
|
tenant2: tenant2
|
||||||
|
|
Loading…
Reference in a new issue