From 55e8d3407fb68a46f0bd5becd66b28f837db58de Mon Sep 17 00:00:00 2001 From: Andrew Dryga Date: Thu, 30 Nov 2023 13:55:07 -0600 Subject: [PATCH] Render deleted entities on fetch (#2692) Since we have flows we should either delete the flow when the related entity is deleted (making them not very useful) or allow viewing deleted entities properly marking them and removing all action buttons in the UI: Screenshot 2023-11-22 at 13 41 51 Screenshot 2023-11-22 at 13 41 54 Screenshot 2023-11-22 at 13 41 48 Screenshot 2023-11-22 at 13 07 47 This change only affects fetching relation by ID (eg. `actors/:id`), rest of pages (index, edit) will not show deleted entities unless they are a critical relation (eg. for Policy to work both actor group and resource are needed): Screenshot 2023-11-22 at 13 42 23 Closes #2681 Signed-off-by: Andrew Dryga --- elixir/apps/domain/lib/domain/actors.ex | 10 +- .../domain/lib/domain/actors/actor/query.ex | 31 ++++-- elixir/apps/domain/lib/domain/actors/group.ex | 2 +- .../domain/lib/domain/actors/group/query.ex | 33 ++++--- .../lib/domain/actors/membership/query.ex | 4 +- .../domain/lib/domain/auth/identity/query.ex | 28 +++--- .../domain/lib/domain/auth/provider/query.ex | 22 +++-- elixir/apps/domain/lib/domain/clients.ex | 5 +- .../domain/lib/domain/clients/client/query.ex | 16 +-- elixir/apps/domain/lib/domain/gateways.ex | 12 ++- .../lib/domain/gateways/gateway/query.ex | 22 +++-- .../domain/lib/domain/gateways/group/query.ex | 8 +- .../domain/lib/domain/gateways/token/query.ex | 6 +- elixir/apps/domain/lib/domain/policies.ex | 5 +- .../apps/domain/lib/domain/policies/policy.ex | 4 +- .../lib/domain/policies/policy/query.ex | 22 +++-- elixir/apps/domain/lib/domain/relays.ex | 10 +- .../domain/lib/domain/relays/group/query.ex | 10 +- .../domain/lib/domain/relays/relay/query.ex | 22 +++-- .../domain/lib/domain/relays/token/query.ex | 6 +- elixir/apps/domain/lib/domain/resources.ex | 9 +- .../lib/domain/resources/resource/query.ex | 20 ++-- .../apps/domain/test/domain/actors_test.exs | 11 ++- elixir/apps/domain/test/domain/auth_test.exs | 4 +- .../apps/domain/test/domain/clients_test.exs | 8 +- .../apps/domain/test/domain/gateways_test.exs | 9 +- .../apps/domain/test/domain/policies_test.exs | 5 +- .../apps/domain/test/domain/relays_test.exs | 9 +- .../domain/test/domain/resources_test.exs | 4 +- elixir/apps/web/lib/web/live/actors/edit.ex | 3 +- elixir/apps/web/lib/web/live/actors/show.ex | 18 ++-- elixir/apps/web/lib/web/live/clients/edit.ex | 5 +- elixir/apps/web/lib/web/live/clients/show.ex | 5 +- elixir/apps/web/lib/web/live/gateways/show.ex | 3 +- elixir/apps/web/lib/web/live/groups/edit.ex | 1 + .../web/lib/web/live/groups/edit_actors.ex | 1 + elixir/apps/web/lib/web/live/groups/show.ex | 9 +- elixir/apps/web/lib/web/live/policies/edit.ex | 3 +- elixir/apps/web/lib/web/live/policies/show.ex | 11 ++- .../web/lib/web/live/relay_groups/edit.ex | 3 +- .../web/lib/web/live/relay_groups/show.ex | 7 +- elixir/apps/web/lib/web/live/relays/show.ex | 5 +- .../apps/web/lib/web/live/resources/edit.ex | 1 + .../apps/web/lib/web/live/resources/show.ex | 5 +- elixir/apps/web/lib/web/live/sites/edit.ex | 5 +- elixir/apps/web/lib/web/live/sites/show.ex | 13 +-- .../web/test/web/live/actors/show_test.exs | 99 +++++++++++++++++-- .../web/test/web/live/clients/show_test.exs | 87 +++++++++++++++- .../web/test/web/live/gateways/show_test.exs | 11 ++- .../web/test/web/live/groups/show_test.exs | 12 ++- .../web/test/web/live/policies/show_test.exs | 12 ++- .../test/web/live/relay_groups/show_test.exs | 12 ++- .../web/test/web/live/relays/show_test.exs | 11 ++- .../web/test/web/live/resources/show_test.exs | 11 ++- .../test/web/live/{nav => }/sidebar_test.exs | 2 +- .../web/test/web/live/sites/show_test.exs | 12 ++- 56 files changed, 510 insertions(+), 214 deletions(-) rename elixir/apps/web/test/web/live/{nav => }/sidebar_test.exs (99%) diff --git a/elixir/apps/domain/lib/domain/actors.ex b/elixir/apps/domain/lib/domain/actors.ex index 6f248a46d..7364666a2 100644 --- a/elixir/apps/domain/lib/domain/actors.ex +++ b/elixir/apps/domain/lib/domain/actors.ex @@ -29,7 +29,8 @@ defmodule Domain.Actors do true <- Validator.valid_uuid?(id) do {preload, _opts} = Keyword.pop(opts, :preload, []) - Group.Query.by_id(id) + Group.Query.all() + |> Group.Query.by_id(id) |> Authorizer.for_subject(subject) |> Repo.fetch() |> case do @@ -47,7 +48,7 @@ defmodule Domain.Actors do {preload, _opts} = Keyword.pop(opts, :preload, []) {:ok, groups} = - Group.Query.all() + Group.Query.not_deleted() |> Authorizer.for_subject(subject) |> Repo.list() @@ -153,7 +154,8 @@ defmodule Domain.Actors do true <- Validator.valid_uuid?(id) do {preload, _opts} = Keyword.pop(opts, :preload, []) - Actor.Query.by_id(id) + Actor.Query.all() + |> Actor.Query.by_id(id) |> Authorizer.for_subject(subject) |> Repo.fetch() |> case do @@ -185,7 +187,7 @@ defmodule Domain.Actors do with :ok <- Auth.ensure_has_permissions(subject, Authorizer.manage_actors_permission()) do {:ok, actors} = - Actor.Query.all() + Actor.Query.not_deleted() |> Authorizer.for_subject(subject) |> Repo.list() diff --git a/elixir/apps/domain/lib/domain/actors/actor/query.ex b/elixir/apps/domain/lib/domain/actors/actor/query.ex index 2af9c5d91..92cf69928 100644 --- a/elixir/apps/domain/lib/domain/actors/actor/query.ex +++ b/elixir/apps/domain/lib/domain/actors/actor/query.ex @@ -3,10 +3,14 @@ defmodule Domain.Actors.Actor.Query do def all do from(actors in Domain.Actors.Actor, as: :actors) + end + + def not_deleted do + all() |> where([actors: actors], is_nil(actors.deleted_at)) end - def by_id(queryable \\ all(), id) + def by_id(queryable \\ not_deleted(), id) def by_id(queryable, {:in, ids}) do where(queryable, [actors: actors], actors.id in ^ids) @@ -20,19 +24,19 @@ defmodule Domain.Actors.Actor.Query do where(queryable, [actors: actors], actors.id == ^id) end - def by_account_id(queryable \\ all(), account_id) do + def by_account_id(queryable \\ not_deleted(), account_id) do where(queryable, [actors: actors], actors.account_id == ^account_id) end - def by_type(queryable \\ all(), type) do + def by_type(queryable \\ not_deleted(), type) do where(queryable, [actors: actors], actors.type == ^type) end - def not_disabled(queryable \\ all()) do + def not_disabled(queryable \\ not_deleted()) do where(queryable, [actors: actors], is_nil(actors.disabled_at)) end - def preload_few_groups_for_each_actor(queryable \\ all(), limit) do + def preload_few_groups_for_each_actor(queryable \\ not_deleted(), limit) do queryable |> with_joined_memberships(limit) |> with_joined_groups() @@ -49,7 +53,10 @@ defmodule Domain.Actors.Actor.Query do Domain.Actors.Membership.Query.all() |> where([memberships: memberships], memberships.actor_id == parent_as(:actors).id) # we need second join to exclude soft deleted actors before applying a limit - |> join(:inner, [memberships: memberships], groups in ^Domain.Actors.Group.Query.all(), + |> join( + :inner, + [memberships: memberships], + groups in ^Domain.Actors.Group.Query.not_deleted(), on: groups.id == memberships.group_id ) |> select([memberships: memberships], memberships.group_id) @@ -70,18 +77,22 @@ defmodule Domain.Actors.Actor.Query do ) end - def with_joined_groups(queryable \\ all()) do - join(queryable, :left, [memberships: memberships], groups in ^Domain.Actors.Group.Query.all(), + def with_joined_groups(queryable \\ not_deleted()) do + join( + queryable, + :left, + [memberships: memberships], + groups in ^Domain.Actors.Group.Query.not_deleted(), on: groups.id == memberships.group_id, as: :groups ) end - def lock(queryable \\ all()) do + def lock(queryable \\ not_deleted()) do lock(queryable, "FOR UPDATE") end - def with_assoc(queryable \\ all(), qual \\ :left, assoc) do + def with_assoc(queryable \\ not_deleted(), qual \\ :left, assoc) do with_named_binding(queryable, assoc, fn query, binding -> join(query, qual, [actors: actors], a in assoc(actors, ^binding), as: ^binding) end) diff --git a/elixir/apps/domain/lib/domain/actors/group.ex b/elixir/apps/domain/lib/domain/actors/group.ex index eb3ac7943..fe0748b90 100644 --- a/elixir/apps/domain/lib/domain/actors/group.ex +++ b/elixir/apps/domain/lib/domain/actors/group.ex @@ -5,7 +5,7 @@ defmodule Domain.Actors.Group do field :name, :string # Those fields will be set for groups we synced from IdP's - belongs_to :provider, Domain.Auth.Provider, where: [deleted_at: nil] + belongs_to :provider, Domain.Auth.Provider field :provider_identifier, :string has_many :policies, Domain.Policies.Policy, diff --git a/elixir/apps/domain/lib/domain/actors/group/query.ex b/elixir/apps/domain/lib/domain/actors/group/query.ex index aa1453778..013e89823 100644 --- a/elixir/apps/domain/lib/domain/actors/group/query.ex +++ b/elixir/apps/domain/lib/domain/actors/group/query.ex @@ -3,10 +3,14 @@ defmodule Domain.Actors.Group.Query do def all do from(groups in Domain.Actors.Group, as: :groups) + end + + def not_deleted do + all() |> where([groups: groups], is_nil(groups.deleted_at)) end - def by_id(queryable \\ all(), id) + def by_id(queryable \\ not_deleted(), id) def by_id(queryable, {:in, ids}) do where(queryable, [groups: groups], groups.id in ^ids) @@ -16,19 +20,19 @@ defmodule Domain.Actors.Group.Query do where(queryable, [groups: groups], groups.id == ^id) end - def by_account_id(queryable \\ all(), account_id) do + def by_account_id(queryable \\ not_deleted(), account_id) do where(queryable, [groups: groups], groups.account_id == ^account_id) end - def by_provider_id(queryable \\ all(), provider_id) do + def by_provider_id(queryable \\ not_deleted(), provider_id) do where(queryable, [groups: groups], groups.provider_id == ^provider_id) end - def by_not_empty_provider_id(queryable \\ all()) do + def by_not_empty_provider_id(queryable \\ not_deleted()) do where(queryable, [groups: groups], not is_nil(groups.provider_id)) end - def by_provider_identifier(queryable \\ all(), provider_identifier) + def by_provider_identifier(queryable \\ not_deleted(), provider_identifier) def by_provider_identifier(queryable, {:in, provider_identifiers}) do where(queryable, [groups: groups], groups.provider_identifier in ^provider_identifiers) @@ -38,7 +42,7 @@ defmodule Domain.Actors.Group.Query do where(queryable, [groups: groups], groups.provider_identifier == ^provider_identifier) end - def group_by_provider_id(queryable \\ all()) do + def group_by_provider_id(queryable \\ not_deleted()) do queryable |> group_by([groups: groups], groups.provider_id) |> where([groups: groups], not is_nil(groups.provider_id)) @@ -48,7 +52,7 @@ defmodule Domain.Actors.Group.Query do }) end - def preload_few_actors_for_each_group(queryable \\ all(), limit) do + def preload_few_actors_for_each_group(queryable \\ not_deleted(), limit) do queryable |> with_joined_memberships(limit) |> with_joined_actors() @@ -71,7 +75,10 @@ defmodule Domain.Actors.Group.Query do Domain.Actors.Membership.Query.all() |> where([memberships: memberships], memberships.group_id == parent_as(:groups).id) # we need second join to exclude soft deleted actors before applying a limit - |> join(:inner, [memberships: memberships], actors in ^Domain.Actors.Actor.Query.all(), + |> join( + :inner, + [memberships: memberships], + actors in ^Domain.Actors.Actor.Query.not_deleted(), on: actors.id == memberships.actor_id ) |> select([memberships: memberships], memberships.actor_id) @@ -92,14 +99,18 @@ defmodule Domain.Actors.Group.Query do ) end - def with_joined_actors(queryable \\ all()) do - join(queryable, :left, [memberships: memberships], actors in ^Domain.Actors.Actor.Query.all(), + def with_joined_actors(queryable \\ not_deleted()) do + join( + queryable, + :left, + [memberships: memberships], + actors in ^Domain.Actors.Actor.Query.not_deleted(), on: actors.id == memberships.actor_id, as: :actors ) end - def lock(queryable \\ all()) do + def lock(queryable \\ not_deleted()) do lock(queryable, "FOR UPDATE") end end diff --git a/elixir/apps/domain/lib/domain/actors/membership/query.ex b/elixir/apps/domain/lib/domain/actors/membership/query.ex index 19b2ac590..01bca998d 100644 --- a/elixir/apps/domain/lib/domain/actors/membership/query.ex +++ b/elixir/apps/domain/lib/domain/actors/membership/query.ex @@ -69,14 +69,14 @@ defmodule Domain.Actors.Membership.Query do end def with_joined_actors(queryable \\ all()) do - join(queryable, :inner, [memberships: memberships], actors in ^Actor.Query.all(), + join(queryable, :inner, [memberships: memberships], actors in ^Actor.Query.not_deleted(), on: actors.id == memberships.actor_id, as: :actors ) end def with_joined_groups(queryable \\ all()) do - join(queryable, :inner, [memberships: memberships], groups in ^Group.Query.all(), + join(queryable, :inner, [memberships: memberships], groups in ^Group.Query.not_deleted(), on: groups.id == memberships.group_id, as: :groups ) diff --git a/elixir/apps/domain/lib/domain/auth/identity/query.ex b/elixir/apps/domain/lib/domain/auth/identity/query.ex index 36b91ccaa..4a9c3701b 100644 --- a/elixir/apps/domain/lib/domain/auth/identity/query.ex +++ b/elixir/apps/domain/lib/domain/auth/identity/query.ex @@ -3,10 +3,14 @@ defmodule Domain.Auth.Identity.Query do def all do from(identities in Domain.Auth.Identity, as: :identities) + end + + def not_deleted do + all() |> where([identities: identities], is_nil(identities.deleted_at)) end - def by_id(queryable \\ all(), id) + def by_id(queryable \\ not_deleted(), id) def by_id(queryable, {:not, id}) do where(queryable, [identities: identities], identities.id != ^id) @@ -16,26 +20,26 @@ defmodule Domain.Auth.Identity.Query do where(queryable, [identities: identities], identities.id == ^id) end - def by_account_id(queryable \\ all(), account_id) do + def by_account_id(queryable \\ not_deleted(), account_id) do where(queryable, [identities: identities], identities.account_id == ^account_id) end - def by_actor_id(queryable \\ all(), actor_id) do + def by_actor_id(queryable \\ not_deleted(), actor_id) do where(queryable, [identities: identities], identities.actor_id == ^actor_id) end - def by_provider_id(queryable \\ all(), provider_id) do + def by_provider_id(queryable \\ not_deleted(), provider_id) do queryable |> where([identities: identities], identities.provider_id == ^provider_id) |> with_assoc(:inner, :provider) |> where([provider: provider], is_nil(provider.disabled_at) and is_nil(provider.deleted_at)) end - def by_adapter(queryable \\ all(), adapter) do + def by_adapter(queryable \\ not_deleted(), adapter) do where(queryable, [identities: identities], identities.adapter == ^adapter) end - def by_provider_identifier(queryable \\ all(), provider_identifier) + def by_provider_identifier(queryable \\ not_deleted(), provider_identifier) def by_provider_identifier(queryable, {:in, provider_identifiers}) do where( @@ -53,7 +57,7 @@ defmodule Domain.Auth.Identity.Query do ) end - def by_id_or_provider_identifier(queryable \\ all(), id_or_provider_identifier) do + def by_id_or_provider_identifier(queryable \\ not_deleted(), id_or_provider_identifier) do if Domain.Validator.valid_uuid?(id_or_provider_identifier) do where( queryable, @@ -66,18 +70,18 @@ defmodule Domain.Auth.Identity.Query do end end - def not_disabled(queryable \\ all()) do + def not_disabled(queryable \\ not_deleted()) do queryable |> join(:inner, [identities: identities], actors in assoc(identities, :actor), as: :actors) |> where([actors: actors], is_nil(actors.deleted_at)) |> where([actors: actors], is_nil(actors.disabled_at)) end - def lock(queryable \\ all()) do + def lock(queryable \\ not_deleted()) do lock(queryable, "FOR UPDATE") end - def group_by_provider_id(queryable \\ all()) do + def group_by_provider_id(queryable \\ not_deleted()) do queryable |> group_by([identities: identities], identities.provider_id) |> select([identities: identities], %{ @@ -86,13 +90,13 @@ defmodule Domain.Auth.Identity.Query do }) end - def with_preloaded_assoc(queryable \\ all(), type \\ :left, assoc) do + def with_preloaded_assoc(queryable \\ not_deleted(), type \\ :left, assoc) do queryable |> with_assoc(type, assoc) |> preload([{^assoc, assoc}], [{^assoc, assoc}]) end - def with_assoc(queryable \\ all(), type \\ :left, assoc) do + def with_assoc(queryable \\ not_deleted(), type \\ :left, assoc) do with_named_binding(queryable, assoc, fn query, binding -> join(query, type, [identities: identities], a in assoc(identities, ^binding), as: ^binding) end) diff --git a/elixir/apps/domain/lib/domain/auth/provider/query.ex b/elixir/apps/domain/lib/domain/auth/provider/query.ex index f7cfdd5e1..f1735a01e 100644 --- a/elixir/apps/domain/lib/domain/auth/provider/query.ex +++ b/elixir/apps/domain/lib/domain/auth/provider/query.ex @@ -3,10 +3,14 @@ defmodule Domain.Auth.Provider.Query do def all do from(provider in Domain.Auth.Provider, as: :provider) + end + + def not_deleted do + all() |> where([provider: provider], is_nil(provider.deleted_at)) end - def by_id(queryable \\ all(), id) + def by_id(queryable \\ not_deleted(), id) def by_id(queryable, {:not, id}) do where(queryable, [provider: provider], provider.id != ^id) @@ -16,7 +20,7 @@ defmodule Domain.Auth.Provider.Query do where(queryable, [provider: provider], provider.id == ^id) end - def by_adapter(queryable \\ all(), adapter) + def by_adapter(queryable \\ not_deleted(), adapter) def by_adapter(queryable, {:not_in, adapters}) do where(queryable, [provider: provider], provider.adapter not in ^adapters) @@ -26,7 +30,7 @@ defmodule Domain.Auth.Provider.Query do where(queryable, [provider: provider], provider.adapter == ^adapter) end - def last_synced_at(queryable \\ all(), {:lt, datetime}) do + def last_synced_at(queryable \\ not_deleted(), {:lt, datetime}) do where( queryable, [provider: provider], @@ -34,7 +38,7 @@ defmodule Domain.Auth.Provider.Query do ) end - def by_non_empty_refresh_token(queryable \\ all()) do + def by_non_empty_refresh_token(queryable \\ not_deleted()) do where( queryable, [provider: provider], @@ -42,7 +46,7 @@ defmodule Domain.Auth.Provider.Query do ) end - def token_expires_at(queryable \\ all(), {:lt, datetime}) do + def token_expires_at(queryable \\ not_deleted(), {:lt, datetime}) do where( queryable, [provider: provider], @@ -50,19 +54,19 @@ defmodule Domain.Auth.Provider.Query do ) end - def by_provisioner(queryable \\ all(), provisioner) do + def by_provisioner(queryable \\ not_deleted(), provisioner) do where(queryable, [provider: provider], provider.provisioner == ^provisioner) end - def by_account_id(queryable \\ all(), account_id) do + def by_account_id(queryable \\ not_deleted(), account_id) do where(queryable, [provider: provider], provider.account_id == ^account_id) end - def not_disabled(queryable \\ all()) do + def not_disabled(queryable \\ not_deleted()) do where(queryable, [provider: provider], is_nil(provider.disabled_at)) end - def lock(queryable \\ all()) do + def lock(queryable \\ not_deleted()) do lock(queryable, "FOR UPDATE") end end diff --git a/elixir/apps/domain/lib/domain/clients.ex b/elixir/apps/domain/lib/domain/clients.ex index 3d37f5d9f..6cb03a781 100644 --- a/elixir/apps/domain/lib/domain/clients.ex +++ b/elixir/apps/domain/lib/domain/clients.ex @@ -38,7 +38,8 @@ defmodule Domain.Clients do true <- Validator.valid_uuid?(id) do {preload, _opts} = Keyword.pop(opts, :preload, []) - Client.Query.by_id(id) + Client.Query.all() + |> Client.Query.by_id(id) |> Authorizer.for_subject(subject) |> Repo.fetch() |> case do @@ -80,7 +81,7 @@ defmodule Domain.Clients do with :ok <- Auth.ensure_has_permissions(subject, required_permissions) do {:ok, clients} = - Client.Query.all() + Client.Query.not_deleted() |> Authorizer.for_subject(subject) |> Repo.list() diff --git a/elixir/apps/domain/lib/domain/clients/client/query.ex b/elixir/apps/domain/lib/domain/clients/client/query.ex index fdeef4eb8..2f6dda25c 100644 --- a/elixir/apps/domain/lib/domain/clients/client/query.ex +++ b/elixir/apps/domain/lib/domain/clients/client/query.ex @@ -3,26 +3,30 @@ defmodule Domain.Clients.Client.Query do def all do from(clients in Domain.Clients.Client, as: :clients) + end + + def not_deleted do + all() |> where([clients: clients], is_nil(clients.deleted_at)) end - def by_id(queryable \\ all(), id) do + def by_id(queryable \\ not_deleted(), id) do where(queryable, [clients: clients], clients.id == ^id) end - def by_actor_id(queryable \\ all(), actor_id) do + def by_actor_id(queryable \\ not_deleted(), actor_id) do where(queryable, [clients: clients], clients.actor_id == ^actor_id) end - def by_account_id(queryable \\ all(), account_id) do + def by_account_id(queryable \\ not_deleted(), account_id) do where(queryable, [clients: clients], clients.account_id == ^account_id) end - def returning_all(queryable \\ all()) do + def returning_not_deleted(queryable \\ not_deleted()) do select(queryable, [clients: clients], clients) end - def with_preloaded_actor(queryable \\ all()) do + def with_preloaded_actor(queryable \\ not_deleted()) do with_named_binding(queryable, :actor, fn queryable, binding -> queryable |> join(:inner, [clients: clients], actor in assoc(clients, ^binding), as: ^binding) @@ -30,7 +34,7 @@ defmodule Domain.Clients.Client.Query do end) end - def with_preloaded_identity(queryable \\ all()) do + def with_preloaded_identity(queryable \\ not_deleted()) do with_named_binding(queryable, :identity, fn queryable, binding -> queryable |> join(:inner, [clients: clients], identity in assoc(clients, ^binding), as: ^binding) diff --git a/elixir/apps/domain/lib/domain/gateways.ex b/elixir/apps/domain/lib/domain/gateways.ex index 617b85c3d..6132a8e1f 100644 --- a/elixir/apps/domain/lib/domain/gateways.ex +++ b/elixir/apps/domain/lib/domain/gateways.ex @@ -42,7 +42,8 @@ defmodule Domain.Gateways do true <- Validator.valid_uuid?(id) do {preload, _opts} = Keyword.pop(opts, :preload, []) - Group.Query.by_id(id) + Group.Query.all() + |> Group.Query.by_id(id) |> Authorizer.for_subject(subject) |> Repo.fetch() |> case do @@ -68,7 +69,7 @@ defmodule Domain.Gateways do {preload, _opts} = Keyword.pop(opts, :preload, []) {:ok, groups} = - Group.Query.all() + Group.Query.not_deleted() |> Authorizer.for_subject(subject) |> Repo.list() @@ -193,7 +194,8 @@ defmodule Domain.Gateways do true <- Validator.valid_uuid?(id) do {preload, _opts} = Keyword.pop(opts, :preload, []) - Gateway.Query.by_id(id) + Gateway.Query.all() + |> Gateway.Query.by_id(id) |> Authorizer.for_subject(subject) |> Repo.fetch() |> case do @@ -228,7 +230,7 @@ defmodule Domain.Gateways do with :ok <- Auth.ensure_has_permissions(subject, Authorizer.manage_gateways_permission()) do {:ok, gateways} = - Gateway.Query.all() + Gateway.Query.not_deleted() |> Authorizer.for_subject(subject) |> Repo.list() @@ -263,7 +265,7 @@ defmodule Domain.Gateways do {preload, _opts} = Keyword.pop(opts, :preload, []) {:ok, gateways} = - Gateway.Query.all() + Gateway.Query.not_deleted() |> Gateway.Query.by_group_id(group.id) |> Authorizer.for_subject(subject) |> Repo.list() diff --git a/elixir/apps/domain/lib/domain/gateways/gateway/query.ex b/elixir/apps/domain/lib/domain/gateways/gateway/query.ex index b07784b3b..412882afd 100644 --- a/elixir/apps/domain/lib/domain/gateways/gateway/query.ex +++ b/elixir/apps/domain/lib/domain/gateways/gateway/query.ex @@ -3,40 +3,44 @@ defmodule Domain.Gateways.Gateway.Query do def all do from(gateways in Domain.Gateways.Gateway, as: :gateways) + end + + def not_deleted do + all() |> where([gateways: gateways], is_nil(gateways.deleted_at)) end - def by_id(queryable \\ all(), id) do + def by_id(queryable \\ not_deleted(), id) do where(queryable, [gateways: gateways], gateways.id == ^id) end - def by_ids(queryable \\ all(), ids) do + def by_ids(queryable \\ not_deleted(), ids) do where(queryable, [gateways: gateways], gateways.id in ^ids) end - def by_user_id(queryable \\ all(), user_id) do + def by_user_id(queryable \\ not_deleted(), user_id) do where(queryable, [gateways: gateways], gateways.user_id == ^user_id) end - def by_group_id(queryable \\ all(), group_id) do + def by_group_id(queryable \\ not_deleted(), group_id) do where(queryable, [gateways: gateways], gateways.group_id == ^group_id) end - def by_account_id(queryable \\ all(), account_id) do + def by_account_id(queryable \\ not_deleted(), account_id) do where(queryable, [gateways: gateways], gateways.account_id == ^account_id) end - def by_resource_id(queryable \\ all(), resource_id) do + def by_resource_id(queryable \\ not_deleted(), resource_id) do queryable |> with_joined_connections() |> where([connections: connections], connections.resource_id == ^resource_id) end - def returning_all(queryable \\ all()) do + def returning_not_deleted(queryable \\ not_deleted()) do select(queryable, [gateways: gateways], gateways) end - def with_joined_connections(queryable \\ all()) do + def with_joined_connections(queryable \\ not_deleted()) do with_named_binding(queryable, :connections, fn queryable, binding -> queryable |> join( @@ -49,7 +53,7 @@ defmodule Domain.Gateways.Gateway.Query do end) end - def with_preloaded_user(queryable \\ all()) do + def with_preloaded_user(queryable \\ not_deleted()) do with_named_binding(queryable, :user, fn queryable, binding -> queryable |> join(:inner, [gateways: gateways], user in assoc(gateways, ^binding), as: ^binding) diff --git a/elixir/apps/domain/lib/domain/gateways/group/query.ex b/elixir/apps/domain/lib/domain/gateways/group/query.ex index abd98faa1..63d2f84e7 100644 --- a/elixir/apps/domain/lib/domain/gateways/group/query.ex +++ b/elixir/apps/domain/lib/domain/gateways/group/query.ex @@ -3,14 +3,18 @@ defmodule Domain.Gateways.Group.Query do def all do from(groups in Domain.Gateways.Group, as: :groups) + end + + def not_deleted do + all() |> where([groups: groups], is_nil(groups.deleted_at)) end - def by_id(queryable \\ all(), id) do + def by_id(queryable \\ not_deleted(), id) do where(queryable, [groups: groups], groups.id == ^id) end - def by_account_id(queryable \\ all(), account_id) do + def by_account_id(queryable \\ not_deleted(), account_id) do where(queryable, [groups: groups], groups.account_id == ^account_id) end end diff --git a/elixir/apps/domain/lib/domain/gateways/token/query.ex b/elixir/apps/domain/lib/domain/gateways/token/query.ex index 8661bb224..c38d22509 100644 --- a/elixir/apps/domain/lib/domain/gateways/token/query.ex +++ b/elixir/apps/domain/lib/domain/gateways/token/query.ex @@ -1,16 +1,16 @@ defmodule Domain.Gateways.Token.Query do use Domain, :query - def all do + def not_deleted do from(token in Domain.Gateways.Token, as: :token) |> where([token: token], is_nil(token.deleted_at)) end - def by_id(queryable \\ all(), id) do + def by_id(queryable \\ not_deleted(), id) do where(queryable, [token: token], token.id == ^id) end - def by_group_id(queryable \\ all(), group_id) do + def by_group_id(queryable \\ not_deleted(), group_id) do where(queryable, [token: token], token.group_id == ^group_id) end end diff --git a/elixir/apps/domain/lib/domain/policies.ex b/elixir/apps/domain/lib/domain/policies.ex index 2ca7cb58d..1c961aa9b 100644 --- a/elixir/apps/domain/lib/domain/policies.ex +++ b/elixir/apps/domain/lib/domain/policies.ex @@ -15,7 +15,8 @@ defmodule Domain.Policies do with :ok <- Auth.ensure_has_permissions(subject, required_permissions), true <- Validator.valid_uuid?(id) do - Policy.Query.by_id(id) + Policy.Query.all() + |> Policy.Query.by_id(id) |> Authorizer.for_subject(subject) |> Repo.fetch() |> case do @@ -40,7 +41,7 @@ defmodule Domain.Policies do with :ok <- Auth.ensure_has_permissions(subject, required_permissions) do {:ok, policies} = - Policy.Query.all() + Policy.Query.not_deleted() |> Authorizer.for_subject(subject) |> Repo.list() diff --git a/elixir/apps/domain/lib/domain/policies/policy.ex b/elixir/apps/domain/lib/domain/policies/policy.ex index 7b94adf1a..c4babba2f 100644 --- a/elixir/apps/domain/lib/domain/policies/policy.ex +++ b/elixir/apps/domain/lib/domain/policies/policy.ex @@ -4,8 +4,8 @@ defmodule Domain.Policies.Policy do schema "policies" do field :description, :string - belongs_to :actor_group, Domain.Actors.Group, where: [deleted_at: nil] - belongs_to :resource, Domain.Resources.Resource, where: [deleted_at: nil] + belongs_to :actor_group, Domain.Actors.Group + belongs_to :resource, Domain.Resources.Resource belongs_to :account, Domain.Accounts.Account field :created_by, Ecto.Enum, values: ~w[identity]a diff --git a/elixir/apps/domain/lib/domain/policies/policy/query.ex b/elixir/apps/domain/lib/domain/policies/policy/query.ex index 72b14b288..b2f7aff9d 100644 --- a/elixir/apps/domain/lib/domain/policies/policy/query.ex +++ b/elixir/apps/domain/lib/domain/policies/policy/query.ex @@ -3,6 +3,10 @@ defmodule Domain.Policies.Policy.Query do def all do from(policies in Domain.Policies.Policy, as: :policies) + end + + def not_deleted do + from(policies in Domain.Policies.Policy, as: :policies) |> where([policies: policies], is_nil(policies.deleted_at)) |> with_joined_actor_group() |> where([actor_group: actor_group], is_nil(actor_group.deleted_at)) @@ -10,29 +14,29 @@ defmodule Domain.Policies.Policy.Query do |> where([resource: resource], is_nil(resource.deleted_at)) end - def by_id(queryable \\ all(), id) do + def by_id(queryable \\ not_deleted(), id) do where(queryable, [policies: policies], policies.id == ^id) end - def by_account_id(queryable \\ all(), account_id) do + def by_account_id(queryable \\ not_deleted(), account_id) do where(queryable, [policies: policies], policies.account_id == ^account_id) end - def by_resource_id(queryable \\ all(), resource_id) do + def by_resource_id(queryable \\ not_deleted(), resource_id) do where(queryable, [policies: policies], policies.resource_id == ^resource_id) end - def by_resource_ids(queryable \\ all(), resource_ids) do + def by_resource_ids(queryable \\ not_deleted(), resource_ids) do where(queryable, [policies: policies], policies.resource_id in ^resource_ids) end - def by_actor_id(queryable \\ all(), actor_id) do + def by_actor_id(queryable \\ not_deleted(), actor_id) do queryable |> with_joined_memberships() |> where([memberships: memberships], memberships.actor_id == ^actor_id) end - def count_by_resource_id(queryable \\ all()) do + def count_by_resource_id(queryable \\ not_deleted()) do queryable |> group_by([policies: policies], policies.resource_id) |> select([policies: policies], %{ @@ -41,7 +45,7 @@ defmodule Domain.Policies.Policy.Query do }) end - def with_joined_actor_group(queryable \\ all()) do + def with_joined_actor_group(queryable \\ not_deleted()) do with_named_binding(queryable, :actor_group, fn queryable, binding -> join(queryable, :inner, [policies: policies], actor_group in assoc(policies, ^binding), as: ^binding @@ -49,7 +53,7 @@ defmodule Domain.Policies.Policy.Query do end) end - def with_joined_resource(queryable \\ all()) do + def with_joined_resource(queryable \\ not_deleted()) do with_named_binding(queryable, :resource, fn queryable, binding -> join(queryable, :inner, [policies: policies], resource in assoc(policies, ^binding), as: ^binding @@ -57,7 +61,7 @@ defmodule Domain.Policies.Policy.Query do end) end - def with_joined_memberships(queryable \\ all()) do + def with_joined_memberships(queryable \\ not_deleted()) do queryable |> with_joined_actor_group() |> with_named_binding(:memberships, fn queryable, binding -> diff --git a/elixir/apps/domain/lib/domain/relays.ex b/elixir/apps/domain/lib/domain/relays.ex index b4ac95395..486f733ab 100644 --- a/elixir/apps/domain/lib/domain/relays.ex +++ b/elixir/apps/domain/lib/domain/relays.ex @@ -21,7 +21,8 @@ defmodule Domain.Relays do true <- Validator.valid_uuid?(id) do {preload, _opts} = Keyword.pop(opts, :preload, []) - Group.Query.by_id(id) + Group.Query.all() + |> Group.Query.by_id(id) |> Authorizer.for_subject(subject) |> Repo.fetch() |> case do @@ -47,7 +48,7 @@ defmodule Domain.Relays do {preload, _opts} = Keyword.pop(opts, :preload, []) {:ok, groups} = - Group.Query.all() + Group.Query.not_deleted() |> Authorizer.for_subject(subject) |> Repo.list() @@ -186,7 +187,8 @@ defmodule Domain.Relays do true <- Validator.valid_uuid?(id) do {preload, _opts} = Keyword.pop(opts, :preload, []) - Relay.Query.by_id(id) + Relay.Query.all() + |> Relay.Query.by_id(id) |> Authorizer.for_subject(subject) |> Repo.fetch() |> case do @@ -221,7 +223,7 @@ defmodule Domain.Relays do {preload, _opts} = Keyword.pop(opts, :preload, []) {:ok, relays} = - Relay.Query.all() + Relay.Query.not_deleted() |> Authorizer.for_subject(subject) |> Repo.list() diff --git a/elixir/apps/domain/lib/domain/relays/group/query.ex b/elixir/apps/domain/lib/domain/relays/group/query.ex index 0ca8130c0..5ff2bfd49 100644 --- a/elixir/apps/domain/lib/domain/relays/group/query.ex +++ b/elixir/apps/domain/lib/domain/relays/group/query.ex @@ -3,18 +3,22 @@ defmodule Domain.Relays.Group.Query do def all do from(groups in Domain.Relays.Group, as: :groups) + end + + def not_deleted do + all() |> where([groups: groups], is_nil(groups.deleted_at)) end - def by_id(queryable \\ all(), id) do + def by_id(queryable \\ not_deleted(), id) do where(queryable, [groups: groups], groups.id == ^id) end - def by_account_id(queryable \\ all(), account_id) do + def by_account_id(queryable \\ not_deleted(), account_id) do where(queryable, [groups: groups], groups.account_id == ^account_id) end - def global_or_by_account_id(queryable \\ all(), account_id) do + def global_or_by_account_id(queryable \\ not_deleted(), account_id) do where( queryable, [groups: groups], diff --git a/elixir/apps/domain/lib/domain/relays/relay/query.ex b/elixir/apps/domain/lib/domain/relays/relay/query.ex index f0dcc1c56..d91a46cd7 100644 --- a/elixir/apps/domain/lib/domain/relays/relay/query.ex +++ b/elixir/apps/domain/lib/domain/relays/relay/query.ex @@ -3,26 +3,30 @@ defmodule Domain.Relays.Relay.Query do def all do from(relays in Domain.Relays.Relay, as: :relays) + end + + def not_deleted do + all() |> where([relays: relays], is_nil(relays.deleted_at)) end - def by_id(queryable \\ all(), id) do + def by_id(queryable \\ not_deleted(), id) do where(queryable, [relays: relays], relays.id == ^id) end - def by_ids(queryable \\ all(), ids) do + def by_ids(queryable \\ not_deleted(), ids) do where(queryable, [relays: relays], relays.id in ^ids) end - def by_user_id(queryable \\ all(), user_id) do + def by_user_id(queryable \\ not_deleted(), user_id) do where(queryable, [relays: relays], relays.user_id == ^user_id) end - def by_account_id(queryable \\ all(), account_id) do + def by_account_id(queryable \\ not_deleted(), account_id) do where(queryable, [relays: relays], relays.account_id == ^account_id) end - def public(queryable \\ all()) do + def public(queryable \\ not_deleted()) do where( queryable, [relays: relays], @@ -30,7 +34,7 @@ defmodule Domain.Relays.Relay.Query do ) end - def public_or_by_account_id(queryable \\ all(), account_id) do + def public_or_by_account_id(queryable \\ not_deleted(), account_id) do where( queryable, [relays: relays], @@ -38,7 +42,7 @@ defmodule Domain.Relays.Relay.Query do ) end - def global_or_by_account_id(queryable \\ all(), account_id) do + def global_or_by_account_id(queryable \\ not_deleted(), account_id) do where( queryable, [relays: relays], @@ -46,11 +50,11 @@ defmodule Domain.Relays.Relay.Query do ) end - def returning_all(queryable \\ all()) do + def returning_not_deleted(queryable \\ not_deleted()) do select(queryable, [relays: relays], relays) end - def with_preloaded_user(queryable \\ all()) do + def with_preloaded_user(queryable \\ not_deleted()) do with_named_binding(queryable, :user, fn queryable, binding -> queryable |> join(:inner, [relays: relays], user in assoc(relays, ^binding), as: ^binding) diff --git a/elixir/apps/domain/lib/domain/relays/token/query.ex b/elixir/apps/domain/lib/domain/relays/token/query.ex index 7e6905856..d7d7d92f9 100644 --- a/elixir/apps/domain/lib/domain/relays/token/query.ex +++ b/elixir/apps/domain/lib/domain/relays/token/query.ex @@ -1,16 +1,16 @@ defmodule Domain.Relays.Token.Query do use Domain, :query - def all do + def not_deleted do from(token in Domain.Relays.Token, as: :token) |> where([token: token], is_nil(token.deleted_at)) end - def by_id(queryable \\ all(), id) do + def by_id(queryable \\ not_deleted(), id) do where(queryable, [token: token], token.id == ^id) end - def by_group_id(queryable \\ all(), group_id) do + def by_group_id(queryable \\ not_deleted(), group_id) do where(queryable, [token: token], token.group_id == ^group_id) end end diff --git a/elixir/apps/domain/lib/domain/resources.ex b/elixir/apps/domain/lib/domain/resources.ex index 39dc1467b..ab9e7ce81 100644 --- a/elixir/apps/domain/lib/domain/resources.ex +++ b/elixir/apps/domain/lib/domain/resources.ex @@ -15,7 +15,8 @@ defmodule Domain.Resources do with :ok <- Auth.ensure_has_permissions(subject, required_permissions), true <- Validator.valid_uuid?(id) do - Resource.Query.by_id(id) + Resource.Query.all() + |> Resource.Query.by_id(id) |> Authorizer.for_subject(subject) |> Repo.fetch() |> case do @@ -77,7 +78,7 @@ defmodule Domain.Resources do {preload, _opts} = Keyword.pop(opts, :preload, []) {:ok, resources} = - Resource.Query.all() + Resource.Query.not_deleted() |> Authorizer.for_subject(subject) |> Repo.list() @@ -95,7 +96,7 @@ defmodule Domain.Resources do with :ok <- Auth.ensure_has_permissions(subject, required_permissions) do count = - Resource.Query.all() + Resource.Query.not_deleted() |> Authorizer.for_subject(subject) |> Resource.Query.by_gateway_group_id(gateway.group_id) |> Repo.aggregate(:count) @@ -114,7 +115,7 @@ defmodule Domain.Resources do with :ok <- Auth.ensure_has_permissions(subject, required_permissions) do resources = - Resource.Query.all() + Resource.Query.not_deleted() |> Resource.Query.by_account_id(subject.account.id) |> Resource.Query.by_gateway_group_id(gateway.group_id) |> Repo.all() diff --git a/elixir/apps/domain/lib/domain/resources/resource/query.ex b/elixir/apps/domain/lib/domain/resources/resource/query.ex index 00eacf435..a8d0c6d96 100644 --- a/elixir/apps/domain/lib/domain/resources/resource/query.ex +++ b/elixir/apps/domain/lib/domain/resources/resource/query.ex @@ -3,10 +3,14 @@ defmodule Domain.Resources.Resource.Query do def all do from(resources in Domain.Resources.Resource, as: :resources) + end + + def not_deleted do + all() |> where([resources: resources], is_nil(resources.deleted_at)) end - def by_id(queryable \\ all(), id) + def by_id(queryable \\ not_deleted(), id) def by_id(queryable, {:in, ids}) do where(queryable, [resources: resources], resources.id in ^ids) @@ -16,11 +20,11 @@ defmodule Domain.Resources.Resource.Query do where(queryable, [resources: resources], resources.id == ^id) end - def by_account_id(queryable \\ all(), account_id) do + def by_account_id(queryable \\ not_deleted(), account_id) do where(queryable, [resources: resources], resources.account_id == ^account_id) end - def by_authorized_actor_id(queryable \\ all(), actor_id) do + def by_authorized_actor_id(queryable \\ not_deleted(), actor_id) do subquery = Domain.Policies.Policy.Query.by_actor_id(actor_id) queryable @@ -37,7 +41,7 @@ defmodule Domain.Resources.Resource.Query do |> select_merge([authorized_by_policies: policies], %{authorized_by_policy: policies}) end - def preload_few_actor_groups_for_each_resource(queryable \\ all(), limit) do + def preload_few_actor_groups_for_each_resource(queryable \\ not_deleted(), limit) do queryable |> with_joined_actor_groups(limit) |> with_joined_policies_counts() @@ -53,13 +57,13 @@ defmodule Domain.Resources.Resource.Query do def with_joined_actor_groups(queryable, limit) do policies_subquery = - Domain.Policies.Policy.Query.all() + Domain.Policies.Policy.Query.not_deleted() |> where([policies: policies], policies.resource_id == parent_as(:resources).id) |> select([policies: policies], policies.actor_group_id) |> limit(^limit) actor_groups_subquery = - Domain.Actors.Group.Query.all() + Domain.Actors.Group.Query.not_deleted() |> where([groups: groups], groups.id in subquery(policies_subquery)) join( @@ -81,13 +85,13 @@ defmodule Domain.Resources.Resource.Query do ) end - def by_gateway_group_id(queryable \\ all(), gateway_group_id) do + def by_gateway_group_id(queryable \\ not_deleted(), gateway_group_id) do queryable |> with_joined_connections() |> where([connections: connections], connections.gateway_group_id == ^gateway_group_id) end - def with_joined_connections(queryable \\ all()) do + def with_joined_connections(queryable \\ not_deleted()) do with_named_binding(queryable, :connections, fn queryable, binding -> queryable |> join( diff --git a/elixir/apps/domain/test/domain/actors_test.exs b/elixir/apps/domain/test/domain/actors_test.exs index 63948d825..09d26d722 100644 --- a/elixir/apps/domain/test/domain/actors_test.exs +++ b/elixir/apps/domain/test/domain/actors_test.exs @@ -30,7 +30,7 @@ defmodule Domain.ActorsTest do assert fetch_group_by_id(group.id, subject) == {:error, :not_found} end - test "does not return deleted groups", %{ + test "returns deleted groups", %{ account: account, subject: subject } do @@ -38,7 +38,8 @@ defmodule Domain.ActorsTest do Fixtures.Actors.create_group(account: account) |> Fixtures.Actors.delete_group() - assert fetch_group_by_id(group.id, subject) == {:error, :not_found} + assert {:ok, fetched_group} = fetch_group_by_id(group.id, subject) + assert fetched_group.id == group.id end test "returns group by id", %{account: account, subject: subject} do @@ -497,7 +498,7 @@ defmodule Domain.ActorsTest do assert Enum.all?(["G:GROUP_ID1", "OU:OU_ID1"], &(&1 in delete)) assert Repo.aggregate(Actors.Group, :count) == 2 - assert Repo.aggregate(Actors.Group.Query.all(), :count) == 0 + assert Repo.aggregate(Actors.Group.Query.not_deleted(), :count) == 0 assert Enum.empty?(group_ids_by_provider_identifier) end @@ -1871,8 +1872,8 @@ defmodule Domain.ActorsTest do assert {:ok, actor} = delete_actor(actor_to_delete, subject) assert actor.deleted_at - assert Repo.aggregate(Domain.Clients.Client.Query.all(), :count) == 0 - assert Repo.aggregate(Domain.Auth.Identity.Query.all(), :count) == 1 + assert Repo.aggregate(Domain.Clients.Client.Query.not_deleted(), :count) == 0 + assert Repo.aggregate(Domain.Auth.Identity.Query.not_deleted(), :count) == 1 end test "returns error when trying to delete the last admin actor" do diff --git a/elixir/apps/domain/test/domain/auth_test.exs b/elixir/apps/domain/test/domain/auth_test.exs index 8b5720a0a..23c7c11b4 100644 --- a/elixir/apps/domain/test/domain/auth_test.exs +++ b/elixir/apps/domain/test/domain/auth_test.exs @@ -1258,7 +1258,7 @@ defmodule Domain.AuthTest do assert Enum.all?(provider_identifiers, &(&1 in delete)) assert Repo.aggregate(Auth.Identity, :count) == 2 - assert Repo.aggregate(Auth.Identity.Query.all(), :count) == 0 + assert Repo.aggregate(Auth.Identity.Query.not_deleted(), :count) == 0 assert Enum.empty?(actor_ids_by_provider_identifier) end @@ -1798,7 +1798,7 @@ defmodule Domain.AuthTest do assert Repo.aggregate(Auth.Identity.Query.all(), :count) == 3 assert delete_actor_identities(actor) == :ok - assert Repo.aggregate(Auth.Identity.Query.all(), :count) == 0 + assert Repo.aggregate(Auth.Identity.Query.not_deleted(), :count) == 0 end test "does not remove identities that belong to another actor", %{ diff --git a/elixir/apps/domain/test/domain/clients_test.exs b/elixir/apps/domain/test/domain/clients_test.exs index 04a55ee8f..d329285d5 100644 --- a/elixir/apps/domain/test/domain/clients_test.exs +++ b/elixir/apps/domain/test/domain/clients_test.exs @@ -55,7 +55,7 @@ defmodule Domain.ClientsTest do assert fetch_client_by_id("foo", subject) == {:error, :not_found} end - test "does not return deleted clients", %{ + test "returns deleted clients", %{ unprivileged_actor: actor, unprivileged_subject: subject } do @@ -63,7 +63,7 @@ defmodule Domain.ClientsTest do Fixtures.Clients.create_client(actor: actor) |> Fixtures.Clients.delete_client() - assert fetch_client_by_id(client.id, subject) == {:error, :not_found} + assert {:ok, _client} = fetch_client_by_id(client.id, subject) end test "returns client by id", %{unprivileged_actor: actor, unprivileged_subject: subject} do @@ -702,9 +702,9 @@ defmodule Domain.ClientsTest do Fixtures.Clients.create_client(actor: actor) Fixtures.Clients.create_client(actor: actor) - assert Repo.aggregate(Clients.Client.Query.all(), :count) == 3 + assert Repo.aggregate(Clients.Client.Query.not_deleted(), :count) == 3 assert delete_actor_clients(actor) == :ok - assert Repo.aggregate(Clients.Client.Query.all(), :count) == 0 + assert Repo.aggregate(Clients.Client.Query.not_deleted(), :count) == 0 end test "does not remove clients that belong to another actor" do diff --git a/elixir/apps/domain/test/domain/gateways_test.exs b/elixir/apps/domain/test/domain/gateways_test.exs index 71bc9f3ac..96d337bc4 100644 --- a/elixir/apps/domain/test/domain/gateways_test.exs +++ b/elixir/apps/domain/test/domain/gateways_test.exs @@ -29,7 +29,7 @@ defmodule Domain.GatewaysTest do assert fetch_group_by_id(group.id, subject) == {:error, :not_found} end - test "does not return deleted groups", %{ + test "returns deleted groups", %{ account: account, subject: subject } do @@ -37,7 +37,8 @@ defmodule Domain.GatewaysTest do Fixtures.Gateways.create_group(account: account) |> Fixtures.Gateways.delete_group() - assert fetch_group_by_id(group.id, subject) == {:error, :not_found} + assert {:ok, fetched_group} = fetch_group_by_id(group.id, subject) + assert fetched_group.id == group.id end test "returns group by id", %{account: account, subject: subject} do @@ -387,7 +388,7 @@ defmodule Domain.GatewaysTest do assert fetch_gateway_by_id(gateway.id, subject) == {:error, :not_found} end - test "does not return deleted gateways", %{ + test "returns deleted gateways", %{ account: account, subject: subject } do @@ -395,7 +396,7 @@ defmodule Domain.GatewaysTest do Fixtures.Gateways.create_gateway(account: account) |> Fixtures.Gateways.delete_gateway() - assert fetch_gateway_by_id(gateway.id, subject) == {:error, :not_found} + assert fetch_gateway_by_id(gateway.id, subject) == {:ok, gateway} end test "returns gateway by id", %{account: account, subject: subject} do diff --git a/elixir/apps/domain/test/domain/policies_test.exs b/elixir/apps/domain/test/domain/policies_test.exs index 2976d2d3c..de69daae6 100644 --- a/elixir/apps/domain/test/domain/policies_test.exs +++ b/elixir/apps/domain/test/domain/policies_test.exs @@ -34,12 +34,13 @@ defmodule Domain.PoliciesTest do assert fetched_policy.id == policy.id end - test "does not return deleted policy", %{account: account, subject: subject} do + test "returns deleted policies", %{account: account, subject: subject} do {:ok, policy} = Fixtures.Policies.create_policy(account: account) |> delete_policy(subject) - assert fetch_policy_by_id(policy.id, subject) == {:error, :not_found} + assert {:ok, fetched_policy} = fetch_policy_by_id(policy.id, subject) + assert fetched_policy.id == policy.id end test "does not return policies in other accounts", %{subject: subject} do diff --git a/elixir/apps/domain/test/domain/relays_test.exs b/elixir/apps/domain/test/domain/relays_test.exs index 09e0e77a2..b189aad15 100644 --- a/elixir/apps/domain/test/domain/relays_test.exs +++ b/elixir/apps/domain/test/domain/relays_test.exs @@ -29,7 +29,7 @@ defmodule Domain.RelaysTest do assert fetch_group_by_id(group.id, subject) == {:error, :not_found} end - test "does not return deleted groups", %{ + test "returns deleted groups", %{ account: account, subject: subject } do @@ -37,7 +37,8 @@ defmodule Domain.RelaysTest do Fixtures.Relays.create_group(account: account) |> Fixtures.Relays.delete_group() - assert fetch_group_by_id(group.id, subject) == {:error, :not_found} + assert {:ok, fetched_group} = fetch_group_by_id(group.id, subject) + assert fetched_group.id == group.id end test "returns group by id", %{account: account, subject: subject} do @@ -409,7 +410,7 @@ defmodule Domain.RelaysTest do assert fetch_relay_by_id(relay.id, subject) == {:error, :not_found} end - test "does not return deleted relays", %{ + test "returns deleted relays", %{ account: account, subject: subject } do @@ -417,7 +418,7 @@ defmodule Domain.RelaysTest do Fixtures.Relays.create_relay(account: account) |> Fixtures.Relays.delete_relay() - assert fetch_relay_by_id(relay.id, subject) == {:error, :not_found} + assert {:ok, _relay} = fetch_relay_by_id(relay.id, subject) end test "returns relay by id", %{account: account, subject: subject} do diff --git a/elixir/apps/domain/test/domain/resources_test.exs b/elixir/apps/domain/test/domain/resources_test.exs index def7426e3..c007ae81b 100644 --- a/elixir/apps/domain/test/domain/resources_test.exs +++ b/elixir/apps/domain/test/domain/resources_test.exs @@ -60,12 +60,12 @@ defmodule Domain.ResourcesTest do refute is_nil(fetched_resource.authorized_by_policy) end - test "does not return deleted resources", %{account: account, subject: subject} do + test "returns deleted resources", %{account: account, subject: subject} do {:ok, resource} = Fixtures.Resources.create_resource(account: account) |> delete_resource(subject) - assert fetch_resource_by_id(resource.id, subject) == {:error, :not_found} + assert {:ok, _resource} = fetch_resource_by_id(resource.id, subject) end test "does not return resources in other accounts", %{subject: subject} do diff --git a/elixir/apps/web/lib/web/live/actors/edit.ex b/elixir/apps/web/lib/web/live/actors/edit.ex index 51a3f7d7d..e10c5c50d 100644 --- a/elixir/apps/web/lib/web/live/actors/edit.ex +++ b/elixir/apps/web/lib/web/live/actors/edit.ex @@ -6,6 +6,7 @@ defmodule Web.Actors.Edit do def mount(%{"id" => id}, _session, socket) do with {:ok, actor} <- Actors.fetch_actor_by_id(id, socket.assigns.subject, preload: [:memberships]), + nil <- actor.deleted_at, {:ok, groups} <- Actors.list_groups(socket.assigns.subject) do changeset = Actors.change_actor(actor) @@ -19,7 +20,7 @@ defmodule Web.Actors.Edit do page_title: "Edit actor #{actor.name}" ]} else - {:error, _reason} -> raise Web.LiveErrors.NotFoundError + _other -> raise Web.LiveErrors.NotFoundError end end diff --git a/elixir/apps/web/lib/web/live/actors/show.ex b/elixir/apps/web/lib/web/live/actors/show.ex index 062f45b39..ba24aa9de 100644 --- a/elixir/apps/web/lib/web/live/actors/show.ex +++ b/elixir/apps/web/lib/web/live/actors/show.ex @@ -25,7 +25,7 @@ defmodule Web.Actors.Show do flow_activities_enabled?: Domain.Config.flow_activities_enabled?() )} else - {:error, _reason} -> raise Web.LiveErrors.NotFoundError + _other -> raise Web.LiveErrors.NotFoundError end end @@ -42,8 +42,9 @@ defmodule Web.Actors.Show do <:title> <%= actor_type(@actor.type) %>: <%= @actor.name %> (you) + (deleted) - <:action> + <:action :if={is_nil(@actor.deleted_at)}> <.edit_button navigate={~p"/#{@account}/actors/#{@actor}/edit"}> Edit <%= actor_type(@actor.type) %> @@ -90,7 +91,7 @@ defmodule Web.Actors.Show do <.section> <:title>Authentication Identities - <:action> + <:action :if={is_nil(@actor.deleted_at)}> <.add_button :if={@actor.type == :service_account} navigate={~p"/#{@account}/actors/service_accounts/#{@actor}/new_identity"} @@ -98,7 +99,7 @@ defmodule Web.Actors.Show do Create Token - <:action> + <:action :if={is_nil(@actor.deleted_at)}> <.add_button :if={@actor.type != :service_account} navigate={~p"/#{@account}/actors/users/#{@actor}/new_identity"} @@ -139,13 +140,13 @@ defmodule Web.Actors.Show do No authentication identities to display <.add_button - :if={@actor.type == :service_account} + :if={is_nil(@actor.deleted_at) and @actor.type == :service_account} navigate={~p"/#{@account}/actors/service_accounts/#{@actor}/new_identity"} > Create Token <.add_button - :if={@actor.type != :service_account} + :if={is_nil(@actor.deleted_at) and @actor.type != :service_account} navigate={~p"/#{@account}/actors/users/#{@actor}/new_identity"} > Create Identity @@ -175,9 +176,6 @@ defmodule Web.Actors.Show do <:empty>
No clients to display
-
- Clients are created automatically when user connects to a resource. -
@@ -231,7 +229,7 @@ defmodule Web.Actors.Show do - <.danger_zone> + <.danger_zone :if={is_nil(@actor.deleted_at)}> <:action> <.delete_button :if={not Actors.actor_synced?(@actor)} diff --git a/elixir/apps/web/lib/web/live/clients/edit.ex b/elixir/apps/web/lib/web/live/clients/edit.ex index d663c4594..99d32d6c5 100644 --- a/elixir/apps/web/lib/web/live/clients/edit.ex +++ b/elixir/apps/web/lib/web/live/clients/edit.ex @@ -3,11 +3,12 @@ defmodule Web.Clients.Edit do alias Domain.Clients def mount(%{"id" => id}, _session, socket) do - with {:ok, client} <- Clients.fetch_client_by_id(id, socket.assigns.subject) do + with {:ok, client} <- Clients.fetch_client_by_id(id, socket.assigns.subject), + nil <- client.deleted_at do changeset = Clients.change_client(client) {:ok, assign(socket, client: client, form: to_form(changeset))} else - {:error, _reason} -> raise Web.LiveErrors.NotFoundError + _other -> raise Web.LiveErrors.NotFoundError end end diff --git a/elixir/apps/web/lib/web/live/clients/show.ex b/elixir/apps/web/lib/web/live/clients/show.ex index fdcf16f04..335574ad6 100644 --- a/elixir/apps/web/lib/web/live/clients/show.ex +++ b/elixir/apps/web/lib/web/live/clients/show.ex @@ -37,8 +37,9 @@ defmodule Web.Clients.Show do <.section> <:title> Client Details + (deleted) - <:action> + <:action :if={is_nil(@client.deleted_at)}> <.edit_button navigate={~p"/#{@account}/clients/#{@client}/edit"}> Edit Client @@ -143,7 +144,7 @@ defmodule Web.Clients.Show do - <.danger_zone> + <.danger_zone :if={is_nil(@client.deleted_at)}> <:action> <.delete_button phx-click="delete" diff --git a/elixir/apps/web/lib/web/live/gateways/show.ex b/elixir/apps/web/lib/web/live/gateways/show.ex index b33ce3137..107eb976e 100644 --- a/elixir/apps/web/lib/web/live/gateways/show.ex +++ b/elixir/apps/web/lib/web/live/gateways/show.ex @@ -36,6 +36,7 @@ defmodule Web.Gateways.Show do <.section> <:title> Gateway: <%= @gateway.name %> + (deleted) <:content> <.vertical_table id="gateway"> @@ -102,7 +103,7 @@ defmodule Web.Gateways.Show do - <.danger_zone> + <.danger_zone :if={is_nil(@gateway.deleted_at)}> <:action> <.delete_button phx-click="delete" diff --git a/elixir/apps/web/lib/web/live/groups/edit.ex b/elixir/apps/web/lib/web/live/groups/edit.ex index b8aecbbb2..bacee4525 100644 --- a/elixir/apps/web/lib/web/live/groups/edit.ex +++ b/elixir/apps/web/lib/web/live/groups/edit.ex @@ -5,6 +5,7 @@ defmodule Web.Groups.Edit do def mount(%{"id" => id}, _session, socket) do with {:ok, group} <- Actors.fetch_group_by_id(id, socket.assigns.subject, preload: [:memberships]), + nil <- group.deleted_at, false <- Actors.group_synced?(group) do changeset = Actors.change_group(group) {:ok, assign(socket, group: group, form: to_form(changeset))} diff --git a/elixir/apps/web/lib/web/live/groups/edit_actors.ex b/elixir/apps/web/lib/web/live/groups/edit_actors.ex index d70280093..93f771fc3 100644 --- a/elixir/apps/web/lib/web/live/groups/edit_actors.ex +++ b/elixir/apps/web/lib/web/live/groups/edit_actors.ex @@ -6,6 +6,7 @@ defmodule Web.Groups.EditActors do def mount(%{"id" => id}, _session, socket) do with {:ok, group} <- Actors.fetch_group_by_id(id, socket.assigns.subject, preload: [:memberships]), + nil <- group.deleted_at, false <- Actors.group_synced?(group), {:ok, actors} <- Actors.list_actors(socket.assigns.subject, preload: [identities: :provider]) do diff --git a/elixir/apps/web/lib/web/live/groups/show.ex b/elixir/apps/web/lib/web/live/groups/show.ex index d1c86ce7c..282624aec 100644 --- a/elixir/apps/web/lib/web/live/groups/show.ex +++ b/elixir/apps/web/lib/web/live/groups/show.ex @@ -31,8 +31,9 @@ defmodule Web.Groups.Show do <.section> <:title> Group: <%= @group.name %> + (deleted) - <:action> + <:action :if={is_nil(@group.deleted_at)}> <.edit_button :if={not Actors.group_synced?(@group)} navigate={~p"/#{@account}/groups/#{@group}/edit"} @@ -58,7 +59,7 @@ defmodule Web.Groups.Show do <.section> <:title>Actors - <:action> + <:action :if={is_nil(@group.deleted_at)}> <.edit_button :if={not Actors.group_synced?(@group)} navigate={~p"/#{@account}/groups/#{@group}/edit_actors"} @@ -85,7 +86,7 @@ defmodule Web.Groups.Show do No actors in group <.edit_button - :if={not Actors.group_synced?(@group)} + :if={is_nil(@group.deleted_at)} navigate={~p"/#{@account}/groups/#{@group}/edit"} > Edit Group @@ -100,7 +101,7 @@ defmodule Web.Groups.Show do - <.danger_zone> + <.danger_zone :if={is_nil(@group.deleted_at)}> <:action> <.delete_button phx-click="delete" diff --git a/elixir/apps/web/lib/web/live/policies/edit.ex b/elixir/apps/web/lib/web/live/policies/edit.ex index d5855f4a6..5be8787e8 100644 --- a/elixir/apps/web/lib/web/live/policies/edit.ex +++ b/elixir/apps/web/lib/web/live/policies/edit.ex @@ -7,7 +7,8 @@ defmodule Web.Policies.Edit do with {:ok, policy} <- Policies.fetch_policy_by_id(id, socket.assigns.subject, preload: [:actor_group, :resource] - ) do + ), + nil <- policy.deleted_at do form = to_form(Policies.Policy.Changeset.update(policy, %{})) socket = assign(socket, policy: policy, page_title: "Edit Policy", form: form) {:ok, socket, temporary_assigns: [form: %Phoenix.HTML.Form{}]} diff --git a/elixir/apps/web/lib/web/live/policies/show.ex b/elixir/apps/web/lib/web/live/policies/show.ex index ef109d962..3df3050bc 100644 --- a/elixir/apps/web/lib/web/live/policies/show.ex +++ b/elixir/apps/web/lib/web/live/policies/show.ex @@ -38,8 +38,9 @@ defmodule Web.Policies.Show do <.section> <:title> <%= @page_title %>: <%= @policy.id %> + (deleted) - <:action> + <:action :if={is_nil(@policy.deleted_at)}> <.edit_button navigate={~p"/#{@account}/policies/#{@policy}/edit"}> Edit Policy @@ -62,6 +63,9 @@ defmodule Web.Policies.Show do <.link navigate={~p"/#{@account}/groups/#{@policy.actor_group_id}"} class={link_style()}> <%= @policy.actor_group.name %> + + (deleted) + <.vertical_table_row> @@ -72,6 +76,9 @@ defmodule Web.Policies.Show do <.link navigate={~p"/#{@account}/resources/#{@policy.resource_id}"} class={link_style()}> <%= @policy.resource.name %> + + (deleted) + <.vertical_table_row> @@ -140,7 +147,7 @@ defmodule Web.Policies.Show do - <.danger_zone> + <.danger_zone :if={is_nil(@policy.deleted_at)}> <:action> <.delete_button phx-click="delete" diff --git a/elixir/apps/web/lib/web/live/relay_groups/edit.ex b/elixir/apps/web/lib/web/live/relay_groups/edit.ex index 7a21e2f7f..ecccd57da 100644 --- a/elixir/apps/web/lib/web/live/relay_groups/edit.ex +++ b/elixir/apps/web/lib/web/live/relay_groups/edit.ex @@ -4,7 +4,8 @@ defmodule Web.RelayGroups.Edit do def mount(%{"id" => id}, _session, socket) do with true <- Domain.Config.self_hosted_relays_enabled?(), - {:ok, group} <- Relays.fetch_group_by_id(id, socket.assigns.subject) do + {:ok, group} <- Relays.fetch_group_by_id(id, socket.assigns.subject), + nil <- group.deleted_at do changeset = Relays.change_group(group) {:ok, assign(socket, group: group, form: to_form(changeset))} else diff --git a/elixir/apps/web/lib/web/live/relay_groups/show.ex b/elixir/apps/web/lib/web/live/relay_groups/show.ex index 41e01451b..827ebdbb4 100644 --- a/elixir/apps/web/lib/web/live/relay_groups/show.ex +++ b/elixir/apps/web/lib/web/live/relay_groups/show.ex @@ -30,8 +30,9 @@ defmodule Web.RelayGroups.Show do <.section> <:title> Relay Instance Group: <%= @group.name %> + (deleted) - <:action :if={@group.account_id}> + <:action :if={not is_nil(@group.account_id) and is_nil(@group.deleted_at)}> <.edit_button navigate={~p"/#{@account}/relay_groups/#{@group}/edit"}> Edit Instance Group @@ -56,7 +57,7 @@ defmodule Web.RelayGroups.Show do <.section> <:title>Relays - <:action> + <:action :if={not is_nil(@group.account_id) and is_nil(@group.deleted_at)}> <.add_button navigate={~p"/#{@account}/relay_groups/#{@group}/new_token"}> Deploy @@ -94,7 +95,7 @@ defmodule Web.RelayGroups.Show do - <.danger_zone> + <.danger_zone :if={not is_nil(@group.account_id) and is_nil(@group.deleted_at)}> <:action :if={@group.account_id}> <.delete_button phx-click="delete" diff --git a/elixir/apps/web/lib/web/live/relays/show.ex b/elixir/apps/web/lib/web/live/relays/show.ex index 54a587a4c..b02c67ee0 100644 --- a/elixir/apps/web/lib/web/live/relays/show.ex +++ b/elixir/apps/web/lib/web/live/relays/show.ex @@ -43,6 +43,7 @@ defmodule Web.Relays.Show do <%= @relay.ipv4 %> + (deleted) <:content>
@@ -112,9 +113,9 @@ defmodule Web.Relays.Show do - <.danger_zone> + <.danger_zone :if={is_nil(@relay.deleted_at)}> <:action :if={@relay.account_id}> - <.delete_button phx-click="delete"> + <.delete_button phx-click="delete" data-confirm="Are you sure you want to delete this relay?"> Delete Relay diff --git a/elixir/apps/web/lib/web/live/resources/edit.ex b/elixir/apps/web/lib/web/live/resources/edit.ex index 7285ce399..4b3264084 100644 --- a/elixir/apps/web/lib/web/live/resources/edit.ex +++ b/elixir/apps/web/lib/web/live/resources/edit.ex @@ -6,6 +6,7 @@ defmodule Web.Resources.Edit do def mount(%{"id" => id} = params, _session, socket) do with {:ok, resource} <- Resources.fetch_resource_by_id(id, socket.assigns.subject, preload: :gateway_groups), + nil <- resource.deleted_at, {:ok, gateway_groups} <- Gateways.list_groups(socket.assigns.subject) do form = Resources.change_resource(resource, socket.assigns.subject) |> to_form() diff --git a/elixir/apps/web/lib/web/live/resources/show.ex b/elixir/apps/web/lib/web/live/resources/show.ex index f67f9606f..e300db09c 100644 --- a/elixir/apps/web/lib/web/live/resources/show.ex +++ b/elixir/apps/web/lib/web/live/resources/show.ex @@ -41,8 +41,9 @@ defmodule Web.Resources.Show do <.section> <:title> Resource: <%= @resource.name %> + (deleted) - <:action> + <:action :if={is_nil(@resource.deleted_at)}> <.edit_button navigate={~p"/#{@account}/resources/#{@resource.id}/edit?#{@params}"}> Edit Resource @@ -232,7 +233,7 @@ defmodule Web.Resources.Show do - <.danger_zone> + <.danger_zone :if={is_nil(@resource.deleted_at)}> <:action> <.delete_button data-confirm="Are you sure want to delete this resource?" diff --git a/elixir/apps/web/lib/web/live/sites/edit.ex b/elixir/apps/web/lib/web/live/sites/edit.ex index 9ce7615d4..d15414b50 100644 --- a/elixir/apps/web/lib/web/live/sites/edit.ex +++ b/elixir/apps/web/lib/web/live/sites/edit.ex @@ -4,11 +4,12 @@ defmodule Web.Sites.Edit do alias Domain.Gateways def mount(%{"id" => id}, _session, socket) do - with {:ok, group} <- Gateways.fetch_group_by_id(id, socket.assigns.subject) do + with {:ok, group} <- Gateways.fetch_group_by_id(id, socket.assigns.subject), + nil <- group.deleted_at do changeset = Gateways.change_group(group) {:ok, assign(socket, group: group, form: to_form(changeset))} else - {:error, _reason} -> raise Web.LiveErrors.NotFoundError + _other -> raise Web.LiveErrors.NotFoundError end end diff --git a/elixir/apps/web/lib/web/live/sites/show.ex b/elixir/apps/web/lib/web/live/sites/show.ex index 6add5a8ca..b860ddaf0 100644 --- a/elixir/apps/web/lib/web/live/sites/show.ex +++ b/elixir/apps/web/lib/web/live/sites/show.ex @@ -46,8 +46,9 @@ defmodule Web.Sites.Show do <.section> <:title> Site: <%= @group.name %> + (deleted) - <:action> + <:action :if={is_nil(@group.deleted_at)}> <.edit_button navigate={~p"/#{@account}/sites/#{@group}/edit"}> Edit Site @@ -80,7 +81,7 @@ defmodule Web.Sites.Show do see all <.icon name="hero-arrow-right" class="w-2 h-2" /> - <:action> + <:action :if={is_nil(@group.deleted_at)}> <.add_button navigate={~p"/#{@account}/sites/#{@group}/new_token"}> Deploy @@ -112,12 +113,12 @@ defmodule Web.Sites.Show do
No gateways to display.
-
+
<.add_button navigate={~p"/#{@account}/sites/#{@group}/new_token"}> Deploy a Gateway
-
+

Deploy gateways to terminate connections to your site's resources. All gateways deployed within a site must be able to reach all its resources.

@@ -133,7 +134,7 @@ defmodule Web.Sites.Show do <:title> Resources - <:action> + <:action :if={is_nil(@group.deleted_at)}> <.add_button navigate={~p"/#{@account}/resources/new?site_id=#{@group}"}> Create @@ -212,7 +213,7 @@ defmodule Web.Sites.Show do - <.danger_zone> + <.danger_zone :if={is_nil(@group.deleted_at)}> <:action> <.delete_button phx-click="delete" diff --git a/elixir/apps/web/test/web/live/actors/show_test.exs b/elixir/apps/web/test/web/live/actors/show_test.exs index 6058acf9f..b4ace7bf6 100644 --- a/elixir/apps/web/test/web/live/actors/show_test.exs +++ b/elixir/apps/web/test/web/live/actors/show_test.exs @@ -14,20 +14,26 @@ defmodule Web.Live.Actors.ShowTest do }}} end - test "renders not found error when actor is deleted", %{conn: conn} do + test "renders deleted actor without action buttons", %{conn: conn} do account = Fixtures.Accounts.create_account() actor = Fixtures.Actors.create_actor(type: :account_admin_user, account: account) |> Fixtures.Actors.delete() - identity = Fixtures.Auth.create_identity(account: account, actor: actor) + auth_actor = Fixtures.Actors.create_actor(type: :account_admin_user, account: account) + auth_identity = Fixtures.Auth.create_identity(account: account, actor: auth_actor) - assert_raise Web.LiveErrors.NotFoundError, fn -> + {:ok, _lv, html} = conn - |> authorize_conn(identity) + |> authorize_conn(auth_identity) |> live(~p"/#{account}/actors/#{actor}") - end + + assert html =~ "(deleted)" + refute html =~ "Danger Zone" + refute html =~ "Add" + refute html =~ "Edit" + refute html =~ "Deploy" end test "renders breadcrumbs item", %{conn: conn} do @@ -46,7 +52,7 @@ defmodule Web.Live.Actors.ShowTest do assert breadcrumbs =~ actor.name end - test "renders logs table", %{ + test "renders flows table", %{ conn: conn } do account = Fixtures.Accounts.create_account() @@ -85,6 +91,87 @@ defmodule Web.Live.Actors.ShowTest do "#{flow.gateway.group.name}-#{flow.gateway.name} (189.172.73.153)" end + test "renders flows even for deleted policies", %{ + conn: conn + } do + account = Fixtures.Accounts.create_account() + actor = Fixtures.Actors.create_actor(type: :account_admin_user, account: account) + identity = Fixtures.Auth.create_identity(account: account, actor: actor) + client = Fixtures.Clients.create_client(account: account, actor: actor) + + flow = + Fixtures.Flows.create_flow( + account: account, + client: client + ) + + flow = Repo.preload(flow, [:client, gateway: [:group], policy: [:actor_group, :resource]]) + Fixtures.Policies.delete_policy(flow.policy) + + {:ok, lv, _html} = + conn + |> authorize_conn(identity) + |> live(~p"/#{account}/actors/#{actor}") + + [row] = + lv + |> element("#flows") + |> render() + |> table_to_map() + + assert row["authorized at"] + assert row["expires at"] + assert row["policy"] =~ flow.policy.actor_group.name + assert row["policy"] =~ flow.policy.resource.name + + assert row["client (ip)"] == + "#{flow.client.name} (#{client.last_seen_remote_ip})" + + assert row["gateway (ip)"] == + "#{flow.gateway.group.name}-#{flow.gateway.name} (189.172.73.153)" + end + + test "renders flows even for deleted policy assocs", %{ + conn: conn + } do + account = Fixtures.Accounts.create_account() + actor = Fixtures.Actors.create_actor(type: :account_admin_user, account: account) + identity = Fixtures.Auth.create_identity(account: account, actor: actor) + client = Fixtures.Clients.create_client(account: account, actor: actor) + + flow = + Fixtures.Flows.create_flow( + account: account, + client: client + ) + + flow = Repo.preload(flow, [:client, gateway: [:group], policy: [:actor_group, :resource]]) + Fixtures.Actors.delete_group(flow.policy.actor_group) + Fixtures.Resources.delete_resource(flow.policy.resource) + + {:ok, lv, _html} = + conn + |> authorize_conn(identity) + |> live(~p"/#{account}/actors/#{actor}") + + [row] = + lv + |> element("#flows") + |> render() + |> table_to_map() + + assert row["authorized at"] + assert row["expires at"] + assert row["policy"] =~ flow.policy.actor_group.name + assert row["policy"] =~ flow.policy.resource.name + + assert row["client (ip)"] == + "#{flow.client.name} (#{client.last_seen_remote_ip})" + + assert row["gateway (ip)"] == + "#{flow.gateway.group.name}-#{flow.gateway.name} (189.172.73.153)" + end + describe "users" do setup do account = Fixtures.Accounts.create_account() diff --git a/elixir/apps/web/test/web/live/clients/show_test.exs b/elixir/apps/web/test/web/live/clients/show_test.exs index f1c151089..d7805e880 100644 --- a/elixir/apps/web/test/web/live/clients/show_test.exs +++ b/elixir/apps/web/test/web/live/clients/show_test.exs @@ -32,7 +32,7 @@ defmodule Web.Live.Clients.ShowTest do }}} end - test "renders not found error when client is deleted", %{ + test "renders deleted client without action buttons", %{ account: account, client: client, identity: identity, @@ -40,11 +40,17 @@ defmodule Web.Live.Clients.ShowTest do } do client = Fixtures.Clients.delete_client(client) - assert_raise Web.LiveErrors.NotFoundError, fn -> + {:ok, _lv, html} = conn |> authorize_conn(identity) |> live(~p"/#{account}/clients/#{client}") - end + + assert html =~ "(deleted)" + refute html =~ "Danger Zone" + refute html =~ "Add" + refute html =~ "Delete" + refute html =~ "Edit" + refute html =~ "Deploy" end test "renders breadcrumbs item", %{ @@ -112,7 +118,7 @@ defmodule Web.Live.Clients.ShowTest do |> Map.fetch!("owner") =~ actor.name end - test "renders logs table", %{ + test "renders flows table", %{ account: account, identity: identity, client: client, @@ -147,6 +153,79 @@ defmodule Web.Live.Clients.ShowTest do "#{flow.gateway.group.name}-#{flow.gateway.name} (189.172.73.153)" end + test "renders flows even for deleted policies", %{ + account: account, + identity: identity, + client: client, + conn: conn + } do + flow = + Fixtures.Flows.create_flow( + account: account, + client: client + ) + + flow = Repo.preload(flow, [:client, gateway: [:group], policy: [:actor_group, :resource]]) + Fixtures.Policies.delete_policy(flow.policy) + + {:ok, lv, _html} = + conn + |> authorize_conn(identity) + |> live(~p"/#{account}/clients/#{client}") + + [row] = + lv + |> element("#flows") + |> render() + |> table_to_map() + + assert row["authorized at"] + assert row["expires at"] + assert row["remote ip"] == to_string(client.last_seen_remote_ip) + assert row["policy"] =~ flow.policy.actor_group.name + assert row["policy"] =~ flow.policy.resource.name + + assert row["gateway (ip)"] == + "#{flow.gateway.group.name}-#{flow.gateway.name} (189.172.73.153)" + end + + test "renders flows even for deleted policy assocs", %{ + account: account, + identity: identity, + client: client, + conn: conn + } do + flow = + Fixtures.Flows.create_flow( + account: account, + client: client + ) + + flow = Repo.preload(flow, [:client, gateway: [:group], policy: [:actor_group, :resource]]) + Fixtures.Actors.delete_group(flow.policy.actor_group) + Fixtures.Resources.delete_resource(flow.policy.resource) + + {:ok, lv, _html} = + conn + |> authorize_conn(identity) + |> live(~p"/#{account}/clients/#{client}") + + [row] = + lv + |> element("#flows") + |> render() + |> table_to_map() + + assert row["authorized at"] + assert row["expires at"] + assert row["remote ip"] == to_string(client.last_seen_remote_ip) + assert row["policy"] =~ flow.policy.actor_group.name + assert row["policy"] =~ flow.policy.resource.name + + assert row["gateway (ip)"] == + "#{flow.gateway.group.name}-#{flow.gateway.name} (189.172.73.153)" + end + test "allows editing clients", %{ account: account, client: client, diff --git a/elixir/apps/web/test/web/live/gateways/show_test.exs b/elixir/apps/web/test/web/live/gateways/show_test.exs index c1f95813f..567e2be1b 100644 --- a/elixir/apps/web/test/web/live/gateways/show_test.exs +++ b/elixir/apps/web/test/web/live/gateways/show_test.exs @@ -33,7 +33,7 @@ defmodule Web.Live.Gateways.ShowTest do }}} end - test "renders not found error when gateway is deleted", %{ + test "renders deleted gateway without action buttons", %{ account: account, gateway: gateway, identity: identity, @@ -41,11 +41,16 @@ defmodule Web.Live.Gateways.ShowTest do } do gateway = Fixtures.Gateways.delete_gateway(gateway) - assert_raise Web.LiveErrors.NotFoundError, fn -> + {:ok, _lv, html} = conn |> authorize_conn(identity) |> live(~p"/#{account}/gateways/#{gateway}") - end + + assert html =~ "(deleted)" + refute html =~ "Danger Zone" + refute html =~ "Add" + refute html =~ "Delete" + refute html =~ "Edit" end test "renders breadcrumbs item", %{ diff --git a/elixir/apps/web/test/web/live/groups/show_test.exs b/elixir/apps/web/test/web/live/groups/show_test.exs index eecc8e018..88d4cbbd2 100644 --- a/elixir/apps/web/test/web/live/groups/show_test.exs +++ b/elixir/apps/web/test/web/live/groups/show_test.exs @@ -30,7 +30,7 @@ defmodule Web.Live.Groups.ShowTest do }}} end - test "renders not found error when group is deleted", %{ + test "renders deleted group without action buttons", %{ account: account, group: group, identity: identity, @@ -38,11 +38,17 @@ defmodule Web.Live.Groups.ShowTest do } do group = Fixtures.Actors.delete_group(group) - assert_raise Web.LiveErrors.NotFoundError, fn -> + {:ok, _lv, html} = conn |> authorize_conn(identity) |> live(~p"/#{account}/groups/#{group}") - end + + assert html =~ "(deleted)" + refute html =~ "Danger Zone" + refute html =~ "Add" + refute html =~ "Delete" + refute html =~ "Edit" + refute html =~ "Deploy" end test "renders breadcrumbs item", %{ diff --git a/elixir/apps/web/test/web/live/policies/show_test.exs b/elixir/apps/web/test/web/live/policies/show_test.exs index 0a9775bd4..ebf8bb6e3 100644 --- a/elixir/apps/web/test/web/live/policies/show_test.exs +++ b/elixir/apps/web/test/web/live/policies/show_test.exs @@ -43,7 +43,7 @@ defmodule Web.Live.Policies.ShowTest do }}} end - test "renders not found error when gateway is deleted", %{ + test "renders deleted gateway group without action buttons", %{ account: account, policy: policy, identity: identity, @@ -51,11 +51,17 @@ defmodule Web.Live.Policies.ShowTest do } do policy = Fixtures.Policies.delete_policy(policy) - assert_raise Web.LiveErrors.NotFoundError, fn -> + {:ok, _lv, html} = conn |> authorize_conn(identity) |> live(~p"/#{account}/policies/#{policy}") - end + + assert html =~ "(deleted)" + refute html =~ "Danger Zone" + refute html =~ "Add" + refute html =~ "Delete" + refute html =~ "Edit" + refute html =~ "Deploy" end test "renders breadcrumbs item", %{ diff --git a/elixir/apps/web/test/web/live/relay_groups/show_test.exs b/elixir/apps/web/test/web/live/relay_groups/show_test.exs index dc36af13a..25b829185 100644 --- a/elixir/apps/web/test/web/live/relay_groups/show_test.exs +++ b/elixir/apps/web/test/web/live/relay_groups/show_test.exs @@ -35,7 +35,7 @@ defmodule Web.Live.RelayGroups.ShowTest do }}} end - test "renders not found error when relay is deleted", %{ + test "renders deleted relay without action buttons", %{ account: account, group: group, identity: identity, @@ -43,11 +43,17 @@ defmodule Web.Live.RelayGroups.ShowTest do } do group = Fixtures.Relays.delete_group(group) - assert_raise Web.LiveErrors.NotFoundError, fn -> + {:ok, _lv, html} = conn |> authorize_conn(identity) |> live(~p"/#{account}/relay_groups/#{group}") - end + + assert html =~ "(deleted)" + refute html =~ "Danger Zone" + refute html =~ "Add" + refute html =~ "Delete" + refute html =~ "Edit" + refute html =~ "Deploy" end test "renders breadcrumbs item", %{ diff --git a/elixir/apps/web/test/web/live/relays/show_test.exs b/elixir/apps/web/test/web/live/relays/show_test.exs index 63a905db1..c21c14ee0 100644 --- a/elixir/apps/web/test/web/live/relays/show_test.exs +++ b/elixir/apps/web/test/web/live/relays/show_test.exs @@ -33,7 +33,7 @@ defmodule Web.Live.Relays.ShowTest do }}} end - test "renders not found error when relay is deleted", %{ + test "renders deleted relay without action buttons", %{ account: account, relay: relay, identity: identity, @@ -41,11 +41,16 @@ defmodule Web.Live.Relays.ShowTest do } do relay = Fixtures.Relays.delete_relay(relay) - assert_raise Web.LiveErrors.NotFoundError, fn -> + {:ok, _lv, html} = conn |> authorize_conn(identity) |> live(~p"/#{account}/relays/#{relay}") - end + + assert html =~ "(deleted)" + refute html =~ "Danger Zone" + refute html =~ "Add" + refute html =~ "Delete" + refute html =~ "Edit" end test "renders breadcrumbs item", %{ diff --git a/elixir/apps/web/test/web/live/resources/show_test.exs b/elixir/apps/web/test/web/live/resources/show_test.exs index 46ae27de4..a70be832e 100644 --- a/elixir/apps/web/test/web/live/resources/show_test.exs +++ b/elixir/apps/web/test/web/live/resources/show_test.exs @@ -43,7 +43,7 @@ defmodule Web.Live.Resources.ShowTest do }}} end - test "renders not found error when resource is deleted", %{ + test "renders deleted resource without action buttons", %{ account: account, resource: resource, identity: identity, @@ -51,11 +51,16 @@ defmodule Web.Live.Resources.ShowTest do } do resource = Fixtures.Resources.delete_resource(resource) - assert_raise Web.LiveErrors.NotFoundError, fn -> + {:ok, _lv, html} = conn |> authorize_conn(identity) |> live(~p"/#{account}/resources/#{resource}") - end + + assert html =~ "(deleted)" + refute html =~ "Danger Zone" + refute html =~ "Delete" + refute html =~ "Edit" + refute html =~ "Deploy" end test "renders breadcrumbs item", %{ diff --git a/elixir/apps/web/test/web/live/nav/sidebar_test.exs b/elixir/apps/web/test/web/live/sidebar_test.exs similarity index 99% rename from elixir/apps/web/test/web/live/nav/sidebar_test.exs rename to elixir/apps/web/test/web/live/sidebar_test.exs index 8599b28a5..7aa0e61d7 100644 --- a/elixir/apps/web/test/web/live/nav/sidebar_test.exs +++ b/elixir/apps/web/test/web/live/sidebar_test.exs @@ -1,4 +1,4 @@ -defmodule Web.Live.Nav.SidebarTest do +defmodule Web.SidebarTest do use Web.ConnCase, async: true setup do diff --git a/elixir/apps/web/test/web/live/sites/show_test.exs b/elixir/apps/web/test/web/live/sites/show_test.exs index 847ea236a..6e18dce81 100644 --- a/elixir/apps/web/test/web/live/sites/show_test.exs +++ b/elixir/apps/web/test/web/live/sites/show_test.exs @@ -35,7 +35,7 @@ defmodule Web.Live.Sites.ShowTest do }}} end - test "renders not found error when gateway is deleted", %{ + test "renders deleted gateway group without action buttons", %{ account: account, group: group, identity: identity, @@ -43,11 +43,17 @@ defmodule Web.Live.Sites.ShowTest do } do group = Fixtures.Gateways.delete_group(group) - assert_raise Web.LiveErrors.NotFoundError, fn -> + {:ok, _lv, html} = conn |> authorize_conn(identity) |> live(~p"/#{account}/sites/#{group}") - end + + assert html =~ "(deleted)" + refute html =~ "Danger Zone" + refute html =~ "Add" + refute html =~ "Delete" + refute html =~ "Edit" + refute html =~ "Deploy" end test "renders breadcrumbs item", %{