diff --git a/elixir/apps/api/lib/api/controllers/actor_group_membership_controller.ex b/elixir/apps/api/lib/api/controllers/actor_group_membership_controller.ex index ff3b9e429..34fc14c5a 100644 --- a/elixir/apps/api/lib/api/controllers/actor_group_membership_controller.ex +++ b/elixir/apps/api/lib/api/controllers/actor_group_membership_controller.ex @@ -65,7 +65,7 @@ defmodule API.ActorGroupMembershipController do ) do subject = conn.assigns.subject preload = [:memberships] - filter = [deleted?: false, editable?: true] + filter = [editable?: true] with {:ok, group} <- Actors.fetch_group_by_id(actor_group_id, subject, preload: preload, filter: filter), @@ -105,7 +105,7 @@ defmodule API.ActorGroupMembershipController do remove = Map.get(params, "remove", []) subject = conn.assigns.subject preload = [:memberships] - filter = [deleted?: false, editable?: true] + filter = [editable?: true] with {:ok, group} <- Actors.fetch_group_by_id(actor_group_id, subject, preload: preload, filter: filter), diff --git a/elixir/apps/api/lib/api/controllers/policy_controller.ex b/elixir/apps/api/lib/api/controllers/policy_controller.ex index 516157a7e..db2dfffb6 100644 --- a/elixir/apps/api/lib/api/controllers/policy_controller.ex +++ b/elixir/apps/api/lib/api/controllers/policy_controller.ex @@ -43,7 +43,7 @@ defmodule API.PolicyController do # Show a specific Policy def show(conn, %{"id" => id}) do - with {:ok, policy} <- Policies.fetch_policy_by_id_or_persistent_id(id, conn.assigns.subject) do + with {:ok, policy} <- Policies.fetch_policy_by_id(id, conn.assigns.subject) do render(conn, :show, policy: policy) end end @@ -91,7 +91,7 @@ defmodule API.PolicyController do def update(conn, %{"id" => id, "policy" => params}) do subject = conn.assigns.subject - with {:ok, policy} <- Policies.fetch_policy_by_id_or_persistent_id(id, subject) do + with {:ok, policy} <- Policies.fetch_policy_by_id(id, subject) do case Policies.update_policy(policy, params, subject) do {:ok, policy} -> render(conn, :show, policy: policy) @@ -124,7 +124,7 @@ defmodule API.PolicyController do def delete(conn, %{"id" => id}) do subject = conn.assigns.subject - with {:ok, policy} <- Policies.fetch_policy_by_id_or_persistent_id(id, subject), + with {:ok, policy} <- Policies.fetch_policy_by_id(id, subject), {:ok, policy} <- Policies.delete_policy(policy, subject) do render(conn, :show, policy: policy) end diff --git a/elixir/apps/api/lib/api/controllers/resource_controller.ex b/elixir/apps/api/lib/api/controllers/resource_controller.ex index 06ac1d8d3..dc59305df 100644 --- a/elixir/apps/api/lib/api/controllers/resource_controller.ex +++ b/elixir/apps/api/lib/api/controllers/resource_controller.ex @@ -43,7 +43,7 @@ defmodule API.ResourceController do def show(conn, %{"id" => id}) do with {:ok, resource} <- - Resources.fetch_resource_by_id_or_persistent_id(id, conn.assigns.subject) do + Resources.fetch_resource_by_id(id, conn.assigns.subject) do render(conn, :show, resource: resource) end end @@ -92,7 +92,7 @@ defmodule API.ResourceController do subject = conn.assigns.subject attrs = set_param_defaults(params) - with {:ok, resource} <- Resources.fetch_active_resource_by_id_or_persistent_id(id, subject) do + with {:ok, resource} <- Resources.fetch_resource_by_id(id, subject) do case Resources.update_resource(resource, attrs, subject) do {:ok, updated_resource} -> render(conn, :show, resource: updated_resource) @@ -124,7 +124,7 @@ defmodule API.ResourceController do def delete(conn, %{"id" => id}) do subject = conn.assigns.subject - with {:ok, resource} <- Resources.fetch_resource_by_id_or_persistent_id(id, subject), + with {:ok, resource} <- Resources.fetch_resource_by_id(id, subject), {:ok, resource} <- Resources.delete_resource(resource, subject) do render(conn, :show, resource: resource) end diff --git a/elixir/apps/api/test/api/gateway/channel_test.exs b/elixir/apps/api/test/api/gateway/channel_test.exs index f503c773f..8a2fa4413 100644 --- a/elixir/apps/api/test/api/gateway/channel_test.exs +++ b/elixir/apps/api/test/api/gateway/channel_test.exs @@ -102,8 +102,9 @@ defmodule API.Gateway.ChannelTest do capture_log(fn -> send(socket.channel_pid, %Changes.Change{lsn: 50}) - # Wait for the channel to process and emit the log - Process.sleep(1) + # Force the channel to process the message before continuing + # :sys.get_state/1 is synchronous and will wait for all pending messages to be handled + :sys.get_state(socket.channel_pid) end) assert message =~ "[warning] Out of order or duplicate change received; ignoring" diff --git a/elixir/apps/api/test/api/relay/channel_test.exs b/elixir/apps/api/test/api/relay/channel_test.exs index eb1d85541..51e681755 100644 --- a/elixir/apps/api/test/api/relay/channel_test.exs +++ b/elixir/apps/api/test/api/relay/channel_test.exs @@ -60,7 +60,8 @@ defmodule API.Relay.ChannelTest do describe "handle_in/3 for unknown messages" do test "it doesn't crash", %{socket: socket} do ref = push(socket, "unknown_message", %{}) - assert_reply ref, :error, %{reason: :unknown_message} + + assert_reply ref, :error, %{reason: :unknown_message}, 1000 end end end diff --git a/elixir/apps/domain/lib/domain/accounts.ex b/elixir/apps/domain/lib/domain/accounts.ex index b66b4046a..75718eb01 100644 --- a/elixir/apps/domain/lib/domain/accounts.ex +++ b/elixir/apps/domain/lib/domain/accounts.ex @@ -11,7 +11,7 @@ defmodule Domain.Accounts do def all_accounts_by_ids!(ids) do if Enum.all?(ids, &Repo.valid_uuid?/1) do - Account.Query.not_deleted() + Account.Query.all() |> Account.Query.by_id({:in, ids}) |> Repo.all() else @@ -43,7 +43,7 @@ defmodule Domain.Accounts do def fetch_account_by_id(id, %Auth.Subject{} = subject, opts \\ []) do with :ok <- Auth.ensure_has_permissions(subject, Authorizer.manage_own_account_permission()), true <- Repo.valid_uuid?(id) do - Account.Query.not_deleted() + Account.Query.all() |> Account.Query.by_id(id) |> Authorizer.for_subject(subject) |> Repo.fetch(Account.Query, opts) @@ -58,13 +58,13 @@ defmodule Domain.Accounts do def fetch_account_by_id_or_slug("", _opts), do: {:error, :not_found} def fetch_account_by_id_or_slug(id_or_slug, opts) do - Account.Query.not_deleted() + Account.Query.all() |> Account.Query.by_id_or_slug(id_or_slug) |> Repo.fetch(Account.Query, opts) end def fetch_account_by_id!(id) do - Account.Query.not_deleted() + Account.Query.all() |> Account.Query.by_id(id) |> Repo.one!() end @@ -80,7 +80,7 @@ defmodule Domain.Accounts do def update_account(%Account{} = account, attrs, %Auth.Subject{} = subject) do with :ok <- Auth.ensure_has_permissions(subject, Authorizer.manage_own_account_permission()) do - Account.Query.not_deleted() + Account.Query.all() |> Account.Query.by_id(account.id) |> Authorizer.for_subject(subject) |> Repo.fetch_and_update(Account.Query, @@ -118,8 +118,7 @@ defmodule Domain.Accounts do Map.fetch!(account.features || %Features{}, feature) || false end - # TODO: HARD-DELETE - Update after `deleted_at` is removed from DB - def account_active?(%{deleted_at: nil, disabled_at: nil}), do: true + def account_active?(%{disabled_at: nil}), do: true def account_active?(_account), do: false def ensure_has_access_to(%Auth.Subject{} = subject, %Account{} = account) do @@ -134,7 +133,7 @@ defmodule Domain.Accounts do slug_candidate = Domain.NameGenerator.generate_slug() queryable = - Account.Query.not_deleted() + Account.Query.all() |> Account.Query.by_slug(slug_candidate) if Repo.exists?(queryable) do diff --git a/elixir/apps/domain/lib/domain/accounts/account.ex b/elixir/apps/domain/lib/domain/accounts/account.ex index 9d922049d..e9cd460a1 100644 --- a/elixir/apps/domain/lib/domain/accounts/account.ex +++ b/elixir/apps/domain/lib/domain/accounts/account.ex @@ -25,41 +25,31 @@ defmodule Domain.Accounts.Account do # We mention all schemas here to leverage Ecto compile-time reference checks, # because later we will have to shard data by account_id. - # TODO: HARD-DELETE - Remove `where` after `deleted_at` is removed from the DB - has_many :actors, Domain.Actors.Actor, where: [deleted_at: nil] - has_many :actor_group_memberships, Domain.Actors.Membership, where: [deleted_at: nil] - has_many :actor_groups, Domain.Actors.Group, where: [deleted_at: nil] + has_many :actors, Domain.Actors.Actor + has_many :actor_group_memberships, Domain.Actors.Membership + has_many :actor_groups, Domain.Actors.Group - # TODO: HARD-DELETE - Remove `where` after `deleted_at` is removed from the DB - has_many :auth_providers, Domain.Auth.Provider, where: [deleted_at: nil] - has_many :auth_identities, Domain.Auth.Identity, where: [deleted_at: nil] + has_many :auth_providers, Domain.Auth.Provider + has_many :auth_identities, Domain.Auth.Identity - # TODO: HARD-DELETE - Remove `where` after `deleted_at` is removed from the DB - has_many :network_addresses, Domain.Network.Address, where: [deleted_at: nil] + has_many :network_addresses, Domain.Network.Address - # TODO: HARD-DELETE - Remove `where` after `deleted_at` is removed from the DB - has_many :policies, Domain.Policies.Policy, where: [deleted_at: nil] + has_many :policies, Domain.Policies.Policy - # TODO: HARD-DELETE - Remove `where` after `deleted_at` is removed from the DB - has_many :flows, Domain.Flows.Flow, where: [deleted_at: nil] + has_many :flows, Domain.Flows.Flow - # TODO: HARD-DELETE - Remove `where` after `deleted_at` is removed from the DB - has_many :resources, Domain.Resources.Resource, where: [deleted_at: nil] - has_many :resource_connections, Domain.Resources.Connection, where: [deleted_at: nil] + has_many :resources, Domain.Resources.Resource + has_many :resource_connections, Domain.Resources.Connection - # TODO: HARD-DELETE - Remove `where` after `deleted_at` is removed from the DB - has_many :clients, Domain.Clients.Client, where: [deleted_at: nil] + has_many :clients, Domain.Clients.Client - # TODO: HARD-DELETE - Remove `where` after `deleted_at` is removed from the DB - has_many :gateways, Domain.Gateways.Gateway, where: [deleted_at: nil] - has_many :gateway_groups, Domain.Gateways.Group, where: [deleted_at: nil] + has_many :gateways, Domain.Gateways.Gateway + has_many :gateway_groups, Domain.Gateways.Group - # TODO: HARD-DELETE - Remove `where` after `deleted_at` is removed from the DB - has_many :relays, Domain.Relays.Relay, where: [deleted_at: nil] - has_many :relay_groups, Domain.Relays.Group, where: [deleted_at: nil] + has_many :relays, Domain.Relays.Relay + has_many :relay_groups, Domain.Relays.Group - # TODO: HARD-DELETE - Remove `where` after `deleted_at` is removed from the DB - has_many :tokens, Domain.Tokens.Token, where: [deleted_at: nil] + has_many :tokens, Domain.Tokens.Token field :warning, :string field :warning_delivery_attempts, :integer, default: 0 @@ -68,8 +58,6 @@ defmodule Domain.Accounts.Account do field :disabled_reason, :string field :disabled_at, :utc_datetime_usec - # TODO: HARD-DELETE - Remove field after soft deletion is removed - field :deleted_at, :utc_datetime_usec timestamps() end end diff --git a/elixir/apps/domain/lib/domain/accounts/account/query.ex b/elixir/apps/domain/lib/domain/accounts/account/query.ex index eb513243f..6b5e47de3 100644 --- a/elixir/apps/domain/lib/domain/accounts/account/query.ex +++ b/elixir/apps/domain/lib/domain/accounts/account/query.ex @@ -5,16 +5,11 @@ defmodule Domain.Accounts.Account.Query do from(accounts in Domain.Accounts.Account, as: :accounts) end - # TODO: HARD-DELETE - Remove after `deleted_at` column is removed from DB - def not_deleted(queryable \\ all()) do - where(queryable, [accounts: accounts], is_nil(accounts.deleted_at)) - end - def disabled(queryable \\ all()) do where(queryable, [accounts: accounts], not is_nil(accounts.disabled_at)) end - def not_disabled(queryable \\ not_deleted()) do + def not_disabled(queryable \\ all()) do where(queryable, [accounts: accounts], is_nil(accounts.disabled_at)) end @@ -100,7 +95,7 @@ defmodule Domain.Accounts.Account.Query do @impl Domain.Repo.Query def preloads, do: [ - clients: {Domain.Clients.Client.Query.not_deleted(), Domain.Clients.Client.Query.preloads()} + clients: {Domain.Clients.Client.Query.all(), Domain.Clients.Client.Query.preloads()} ] @impl Domain.Repo.Query diff --git a/elixir/apps/domain/lib/domain/actors.ex b/elixir/apps/domain/lib/domain/actors.ex index ad06b2aeb..91aabdf27 100644 --- a/elixir/apps/domain/lib/domain/actors.ex +++ b/elixir/apps/domain/lib/domain/actors.ex @@ -2,7 +2,7 @@ defmodule Domain.Actors do alias Domain.Actors.Membership alias Web.Clients alias Domain.Repo - alias Domain.{Accounts, Auth, Tokens, Clients, Policies, Billing} + alias Domain.{Accounts, Auth, Tokens, Clients, Billing} alias Domain.Actors.{Authorizer, Actor, Group} require Ecto.Query require Logger @@ -12,7 +12,7 @@ defmodule Domain.Actors do def fetch_groups_count_grouped_by_provider_id(%Auth.Subject{} = subject) do with :ok <- Auth.ensure_has_permissions(subject, Authorizer.manage_actors_permission()) do groups = - Group.Query.not_deleted() + Group.Query.all() |> Group.Query.group_by_provider_id() |> Authorizer.for_subject(subject) |> Repo.all() @@ -48,7 +48,7 @@ defmodule Domain.Actors do def list_groups(%Auth.Subject{} = subject, opts \\ []) do with :ok <- Auth.ensure_has_permissions(subject, Authorizer.manage_actors_permission()) do - Group.Query.not_deleted() + Group.Query.all() |> Authorizer.for_subject(subject) |> Repo.list(Group.Query, opts) end @@ -56,7 +56,7 @@ defmodule Domain.Actors do def list_groups_for(%Actor{} = actor, %Auth.Subject{} = subject, opts \\ []) do with :ok <- Auth.ensure_has_permissions(subject, Authorizer.manage_actors_permission()) do - Group.Query.not_deleted() + Group.Query.all() |> Group.Query.by_actor_id(actor.id) |> Authorizer.for_subject(subject) |> Repo.list(Group.Query, opts) @@ -66,7 +66,7 @@ defmodule Domain.Actors do def all_groups!(%Auth.Subject{} = subject, opts \\ []) do {preload, _opts} = Keyword.pop(opts, :preload, []) - Group.Query.not_deleted() + Group.Query.all() |> Authorizer.for_subject(subject) |> Repo.all() |> Repo.preload(preload) @@ -75,7 +75,7 @@ defmodule Domain.Actors do def all_editable_groups!(%Auth.Subject{} = subject, opts \\ []) do {preload, _opts} = Keyword.pop(opts, :preload, []) - Group.Query.not_deleted() + Group.Query.all() |> Group.Query.editable() |> Authorizer.for_subject(subject) |> Repo.all() @@ -90,7 +90,7 @@ defmodule Domain.Actors do def list_editable_groups(%Auth.Subject{} = subject, opts \\ []) do with :ok <- Auth.ensure_has_permissions(subject, Authorizer.manage_actors_permission()) do - Group.Query.not_deleted() + Group.Query.all() |> Group.Query.editable() |> Authorizer.for_subject(subject) |> Repo.list(Group.Query, opts) @@ -101,7 +101,7 @@ defmodule Domain.Actors do with :ok <- Auth.ensure_has_permissions(subject, Authorizer.manage_actors_permission()) do ids = groups |> Enum.map(& &1.id) |> Enum.uniq() - Group.Query.not_deleted() + Group.Query.all() |> Group.Query.by_id({:in, ids}) |> Group.Query.preload_few_actors_for_each_group(limit) |> Authorizer.for_subject(subject) @@ -114,7 +114,7 @@ defmodule Domain.Actors do ids = actors |> Enum.map(& &1.id) |> Enum.uniq() {:ok, peek} = - Actor.Query.not_deleted() + Actor.Query.all() |> Actor.Query.by_id({:in, ids}) |> Actor.Query.preload_few_groups_for_each_actor(limit) |> Authorizer.for_subject(subject) @@ -141,7 +141,7 @@ defmodule Domain.Actors do ids = actors |> Enum.map(& &1.id) |> Enum.uniq() {:ok, peek} = - Actor.Query.not_deleted() + Actor.Query.all() |> Actor.Query.by_id({:in, ids}) |> Actor.Query.preload_few_clients_for_each_actor(limit) |> Authorizer.for_subject(subject) @@ -224,7 +224,7 @@ defmodule Domain.Actors do def update_group(%Group{provider_id: nil} = group, attrs, %Auth.Subject{} = subject) do with :ok <- Auth.ensure_has_permissions(subject, Authorizer.manage_actors_permission()) do - Group.Query.not_deleted() + Group.Query.all() |> Group.Query.by_id(group.id) |> Authorizer.for_subject(subject) |> Repo.fetch_and_update(Group.Query, @@ -256,93 +256,6 @@ defmodule Domain.Actors do {:error, :synced_group} end - # TODO: HARD-DELETE - Remove this once the `deleted_at` field in the DB is gone - def soft_delete_group(%Group{provider_id: nil} = group, %Auth.Subject{} = subject) do - queryable = - Group.Query.not_deleted() - |> Group.Query.by_id(group.id) - - case soft_delete_groups(queryable, subject) do - {:ok, [group]} -> - {:ok, _policies} = Policies.soft_delete_policies_for(group, subject) - - # TODO: Hard delete - # Consider using a trigger or transaction to handle the side effects of soft-deletions to ensure consistency - {_count, _memberships} = - Membership.Query.all() - |> Membership.Query.by_group_id(group.id) - |> Repo.delete_all() - - {:ok, group} - - {:ok, []} -> - {:error, :not_found} - - {:error, reason} -> - {:error, reason} - end - end - - # TODO: HARD-DELETE - Remove this once the `deleted_at` field in the DB is gone - def soft_delete_group(%Group{}, %Auth.Subject{}) do - {:error, :synced_group} - end - - # TODO: HARD-DELETE - Remove this once the `deleted_at` field in the DB is gone - def soft_delete_groups_for(%Auth.Provider{} = provider, %Auth.Subject{} = subject) do - queryable = - Group.Query.not_deleted() - |> Group.Query.by_provider_id(provider.id) - |> Group.Query.by_account_id(provider.account_id) - - # TODO: Hard delete - # Consider using a trigger or transaction to handle the side effects of soft-deletions to ensure consistency - {_count, _memberships} = - Membership.Query.by_group_provider_id(provider.id) - |> Repo.delete_all() - - with {:ok, groups} <- soft_delete_groups(queryable, subject) do - {:ok, _policies} = Policies.soft_delete_policies_for(provider, subject) - {:ok, groups} - end - end - - # TODO: HARD-DELETE - Remove this once the `deleted_at` field in the DB is gone - defp soft_delete_groups(queryable, subject) do - with :ok <- Auth.ensure_has_permissions(subject, Authorizer.manage_actors_permission()) do - {_count, groups} = - queryable - |> Authorizer.for_subject(subject) - |> Group.Query.delete() - |> Repo.update_all([]) - - {:ok, groups} - end - end - - @doc false - # used in sync workers - # TODO: HARD-DELETE - Remove this once the `deleted_at` field in the DB is gone - def soft_delete_groups(queryable) do - {_count, groups} = - queryable - |> Group.Query.delete() - |> Repo.update_all([]) - - :ok = - Enum.each(groups, fn group -> - {:ok, _policies} = Domain.Policies.soft_delete_policies_for(group) - end) - - # TODO: Hard delete - # Consider using a trigger or transaction to handle the side effects of soft-deletions to ensure consistency - {_count, _memberships} = - Membership.Query.by_group_id({:in, Enum.map(groups, & &1.id)}) - |> Repo.delete_all() - - {:ok, groups} - end - def group_synced?(%Group{provider_id: nil}), do: false def group_synced?(%Group{}), do: true @@ -350,11 +263,7 @@ defmodule Domain.Actors do def group_managed?(%Group{}), do: false def group_editable?(%Group{} = group), - do: not group_soft_deleted?(group) and not group_synced?(group) and not group_managed?(group) - - # TODO: HARD-DELETE - Remove this once the `deleted_at` field in the DB is gone - def group_soft_deleted?(%Group{deleted_at: nil}), do: false - def group_soft_deleted?(%Group{}), do: true + do: not group_synced?(group) and not group_managed?(group) # Actors @@ -379,18 +288,6 @@ defmodule Domain.Actors do |> Repo.aggregate(:count) end - def count_synced_actors_for_provider(%Auth.Provider{} = provider) do - Actor.Query.not_deleted() - |> Actor.Query.by_deleted_identity_provider_id(provider.id) - |> Actor.Query.by_stale_for_provider(provider.id) - |> Repo.all() - - Actor.Query.not_deleted() - |> Actor.Query.by_deleted_identity_provider_id(provider.id) - |> Actor.Query.by_stale_for_provider(provider.id) - |> Repo.aggregate(:count) - end - def fetch_actor_by_id(id, %Auth.Subject{} = subject, opts \\ []) do with :ok <- Auth.ensure_has_permissions(subject, Authorizer.manage_actors_permission()), true <- Repo.valid_uuid?(id) do @@ -441,7 +338,7 @@ defmodule Domain.Actors do def list_actors(%Auth.Subject{} = subject, opts \\ []) do with :ok <- Auth.ensure_has_permissions(subject, Authorizer.manage_actors_permission()) do - Actor.Query.not_deleted() + Actor.Query.all() |> Authorizer.for_subject(subject) |> Repo.list(Actor.Query, opts) end @@ -520,7 +417,7 @@ defmodule Domain.Actors do def update_actor(%Actor{} = actor, attrs, %Auth.Subject{} = subject) do with :ok <- Auth.ensure_has_permissions(subject, Authorizer.manage_actors_permission()) do - Actor.Query.not_deleted() + Actor.Query.all() |> Actor.Query.by_id(actor.id) |> Authorizer.for_subject(subject) |> Repo.fetch_and_update(Actor.Query, @@ -569,7 +466,7 @@ defmodule Domain.Actors do [] group_ids -> - Group.Query.not_deleted() + Group.Query.all() |> Group.Query.not_editable() |> Group.Query.by_id({:in, group_ids}) |> Repo.all() @@ -578,7 +475,7 @@ defmodule Domain.Actors do def disable_actor(%Actor{} = actor, %Auth.Subject{} = subject) do with :ok <- Auth.ensure_has_permissions(subject, Authorizer.manage_actors_permission()) do - Actor.Query.not_deleted() + Actor.Query.all() |> Actor.Query.by_id(actor.id) |> Authorizer.for_subject(subject) |> Repo.fetch_and_update(Actor.Query, @@ -596,7 +493,7 @@ defmodule Domain.Actors do def enable_actor(%Actor{} = actor, %Auth.Subject{} = subject) do with :ok <- Auth.ensure_has_permissions(subject, Authorizer.manage_actors_permission()) do - Actor.Query.not_deleted() + Actor.Query.all() |> Actor.Query.by_id(actor.id) |> Authorizer.for_subject(subject) |> Repo.fetch_and_update(Actor.Query, with: &Actor.Changeset.enable_actor/1) @@ -616,35 +513,6 @@ defmodule Domain.Actors do end end - # TODO: HARD-DELETE - Remove this after `deleted_at` column is removed from DB - def soft_delete_actor(%Actor{} = actor, %Auth.Subject{} = subject) do - with :ok <- Auth.ensure_has_permissions(subject, Authorizer.manage_actors_permission()) do - Actor.Query.not_deleted() - |> Actor.Query.by_id(actor.id) - |> Authorizer.for_subject(subject) - |> Repo.fetch_and_update(Actor.Query, - with: fn actor -> - if actor.type != :account_admin_user or other_enabled_admins_exist?(actor) do - :ok = Auth.soft_delete_identities_for(actor, subject) - :ok = Clients.delete_clients_for(actor, subject) - - # TODO: Hard delete - # Consider using a trigger or transaction to handle the side effects of soft-deletions to ensure consistency - {_count, _memberships} = - Membership.Query.by_actor_id(actor.id) - |> Repo.delete_all() - - {:ok, _tokens} = Tokens.delete_tokens_for(actor, subject) - - Actor.Changeset.delete_actor(actor) - else - :cant_delete_the_last_admin - end - end - ) - end - end - def delete_unsynced_actors(%Auth.Provider{} = provider, synced_at) do {count, _deleted_actors} = Actor.Query.all() @@ -678,34 +546,13 @@ defmodule Domain.Actors do {:ok, %{deleted_memberships: count}} end - def delete_stale_synced_actors_for_provider( - %Auth.Provider{} = provider, - %Auth.Subject{} = subject - ) do - with :ok <- Auth.ensure_has_permissions(subject, Authorizer.manage_actors_permission()) do - Actor.Query.not_deleted() - |> Authorizer.for_subject(subject) - |> Actor.Query.by_deleted_identity_provider_id(provider.id) - |> Actor.Query.by_stale_for_provider(provider.id) - |> Repo.all() - |> Enum.each(fn actor -> - {:ok, _actor} = delete_actor(actor, subject) - end) - end - end - def actor_synced?(%Actor{last_synced_at: nil}), do: false def actor_synced?(%Actor{}), do: true - # TODO: HARD-DELETE - Remove this once the `deleted_at` field in the DB is gone - def actor_deleted?(%Actor{deleted_at: nil}), do: false - def actor_deleted?(%Actor{}), do: true - def actor_disabled?(%Actor{disabled_at: nil}), do: false def actor_disabled?(%Actor{}), do: true - # TODO: HARD-DELETE - Update this once the `deleted_at` field in the DB is gone - def actor_active?(%Actor{disabled_at: nil, deleted_at: nil}), do: true + def actor_active?(%Actor{disabled_at: nil}), do: true def actor_active?(%Actor{}), do: false defp other_enabled_admins_exist?(%Actor{ diff --git a/elixir/apps/domain/lib/domain/actors/actor.ex b/elixir/apps/domain/lib/domain/actors/actor.ex index 4b4b25a84..d631927cf 100644 --- a/elixir/apps/domain/lib/domain/actors/actor.ex +++ b/elixir/apps/domain/lib/domain/actors/actor.ex @@ -7,20 +7,13 @@ defmodule Domain.Actors.Actor do field :name, :string - # TODO: HARD-DELETE - Remove `where` after `deleted_at` is removed from DB - has_many :identities, Domain.Auth.Identity, where: [deleted_at: nil] + has_many :identities, Domain.Auth.Identity - # TODO: HARD-DELETE - Remove `where` after `deleted_at` is removed from DB - has_many :clients, Domain.Clients.Client, - where: [deleted_at: nil], - preload_order: [desc: :last_seen_at] + has_many :clients, Domain.Clients.Client, preload_order: [desc: :last_seen_at] - # TODO: HARD-DELETE - Remove `where` after `deleted_at` is removed from DB - has_many :tokens, Domain.Tokens.Token, where: [deleted_at: nil] + has_many :tokens, Domain.Tokens.Token has_many :memberships, Domain.Actors.Membership, on_replace: :delete - # TODO: where doesn't work on join tables so soft-deleted records will be preloaded, - # ref https://github.com/firezone/firezone/issues/2162 has_many :groups, through: [:memberships, :group] belongs_to :account, Domain.Accounts.Account @@ -29,8 +22,6 @@ defmodule Domain.Actors.Actor do field :last_synced_at, :utc_datetime_usec field :disabled_at, :utc_datetime_usec - # TODO: HARD-DELETE - Remove field after soft deletion is removed - field :deleted_at, :utc_datetime_usec timestamps() end end diff --git a/elixir/apps/domain/lib/domain/actors/actor/changeset.ex b/elixir/apps/domain/lib/domain/actors/actor/changeset.ex index c8ecc6b38..908ea717d 100644 --- a/elixir/apps/domain/lib/domain/actors/actor/changeset.ex +++ b/elixir/apps/domain/lib/domain/actors/actor/changeset.ex @@ -85,13 +85,6 @@ defmodule Domain.Actors.Actor.Changeset do |> put_change(:disabled_at, nil) end - # TODO: HARD-DELETE - Remove after `deleted_at` is removed from DB - def delete_actor(%Actor{} = actor) do - actor - |> change() - |> put_default_value(:deleted_at, DateTime.utc_now()) - end - defp validate_granted_permissions(changeset, subject) do validate_change(changeset, :type, fn :type, granted_actor_type -> if Auth.can_grant_role?(subject, granted_actor_type) do diff --git a/elixir/apps/domain/lib/domain/actors/actor/query.ex b/elixir/apps/domain/lib/domain/actors/actor/query.ex index fd2411c6c..28f785789 100644 --- a/elixir/apps/domain/lib/domain/actors/actor/query.ex +++ b/elixir/apps/domain/lib/domain/actors/actor/query.ex @@ -5,13 +5,7 @@ defmodule Domain.Actors.Actor.Query do from(actors in Domain.Actors.Actor, as: :actors) end - # TODO: HARD-DELETE - Remove after `deleted_at` column is removed from DB - def not_deleted do - all() - |> where([actors: actors], is_nil(actors.deleted_at)) - end - - def not_disabled(queryable \\ not_deleted()) do + def not_disabled(queryable \\ all()) do where(queryable, [actors: actors], is_nil(actors.disabled_at)) end @@ -47,34 +41,6 @@ defmodule Domain.Actors.Actor.Query do where(queryable, [actors: actors], actors.last_synced_at != ^synced_at) end - # TODO: HARD-DELETE - Remove after `deleted_at` column is removed in DB - def by_deleted_identity_provider_id(queryable, provider_id) do - queryable - |> join(:inner, [actors: actors], identities in ^Domain.Auth.Identity.Query.deleted(), - on: identities.actor_id == actors.id, - as: :deleted_identities - ) - |> where( - [deleted_identities: deleted_identities], - deleted_identities.provider_id == ^provider_id - ) - end - - # TODO: HARD-DELETE - Update after `deleted_at` column is removed in DB - def by_stale_for_provider(queryable, provider_id) do - subquery = - Domain.Auth.Identity.Query.all() - |> where( - [identities: identities], - identities.actor_id == parent_as(:actors).id and - (identities.provider_id != ^provider_id or - is_nil(identities.deleted_at)) - ) - - queryable - |> where([actors: actors], not exists(subquery)) - end - def by_type(queryable, {:in, types}) do where(queryable, [actors: actors], actors.type in ^types) end @@ -98,7 +64,7 @@ defmodule Domain.Actors.Actor.Query do def with_joined_clients(queryable, limit) do subquery = - Domain.Clients.Client.Query.not_deleted() + Domain.Clients.Client.Query.all() |> where([clients: clients], clients.actor_id == parent_as(:actors).id) |> order_by([clients: clients], desc: clients.last_seen_at) |> limit(^limit) @@ -138,13 +104,6 @@ defmodule Domain.Actors.Actor.Query do subquery = 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.not_deleted(), - on: groups.id == memberships.group_id - ) |> select([memberships: memberships], memberships.group_id) |> limit(^limit) @@ -168,7 +127,7 @@ defmodule Domain.Actors.Actor.Query do queryable, :left, [memberships: memberships], - groups in ^Domain.Actors.Group.Query.not_deleted(), + groups in ^Domain.Actors.Group.Query.all(), on: groups.id == memberships.group_id, as: :groups ) @@ -179,7 +138,7 @@ defmodule Domain.Actors.Actor.Query do queryable, :left, [actors: actors], - clients in ^Domain.Clients.Client.Query.not_deleted(), + clients in ^Domain.Clients.Client.Query.all(), on: clients.actor_id == actors.id, as: :clients ) @@ -191,7 +150,7 @@ defmodule Domain.Actors.Actor.Query do queryable, :left, [actors: actors], - identities in ^Domain.Auth.Identity.Query.not_deleted(), + identities in ^Domain.Auth.Identity.Query.all(), on: identities.actor_id == actors.id, as: ^binding ) @@ -277,11 +236,6 @@ defmodule Domain.Actors.Actor.Query do name: :group_id, type: {:string, :uuid}, fun: &filter_by_group_id/2 - }, - %Domain.Repo.Filter{ - name: :deleted?, - type: :boolean, - fun: &filter_deleted/1 } ] @@ -347,9 +301,4 @@ defmodule Domain.Actors.Actor.Query do {queryable, dynamic(exists(subquery))} end - - # TODO: HARD-DELETE - Remove after `deleted_at` column is removed in DB - def filter_deleted(queryable) do - {queryable, dynamic([actors: actors], not is_nil(actors.deleted_at))} - end end diff --git a/elixir/apps/domain/lib/domain/actors/group.ex b/elixir/apps/domain/lib/domain/actors/group.ex index 83a7fb0fb..3e1712b17 100644 --- a/elixir/apps/domain/lib/domain/actors/group.ex +++ b/elixir/apps/domain/lib/domain/actors/group.ex @@ -11,15 +11,10 @@ defmodule Domain.Actors.Group do field :last_synced_at, :utc_datetime_usec - # TODO: HARD-DELETE - Remove `where` after `deleted_at` column is removed from DB - has_many :policies, Domain.Policies.Policy, - foreign_key: :actor_group_id, - where: [deleted_at: nil] + has_many :policies, Domain.Policies.Policy, foreign_key: :actor_group_id has_many :memberships, Domain.Actors.Membership, on_replace: :delete - # TODO: where doesn't work on join tables so soft-deleted records will be preloaded, - # ref https://github.com/firezone/firezone/issues/2162 has_many :actors, through: [:memberships, :actor] field :created_by, Ecto.Enum, values: ~w[actor identity provider system]a @@ -27,8 +22,6 @@ defmodule Domain.Actors.Group do belongs_to :account, Domain.Accounts.Account - # TODO: HARD-DELETE - Remove field after soft deletion is removed - field :deleted_at, :utc_datetime_usec timestamps() end end diff --git a/elixir/apps/domain/lib/domain/actors/group/changeset.ex b/elixir/apps/domain/lib/domain/actors/group/changeset.ex index 715475180..1aa43b4a3 100644 --- a/elixir/apps/domain/lib/domain/actors/group/changeset.ex +++ b/elixir/apps/domain/lib/domain/actors/group/changeset.ex @@ -11,8 +11,7 @@ defmodule Domain.Actors.Group.Changeset do "WHERE provider_id IS NOT NULL AND provider_identifier IS NOT NULL"} end - # TODO: Update after `deleted_at` is removed from the DB - def upsert_on_conflict, do: {:replace, ~w[name updated_at deleted_at]a} + def upsert_on_conflict, do: {:replace, ~w[name updated_at]a} def create(%Accounts.Account{} = account, attrs, %Auth.Subject{} = subject) do %Actors.Group{memberships: []} @@ -36,7 +35,6 @@ defmodule Domain.Actors.Group.Changeset do |> put_subject_trail(:created_by, :system) end - # TODO: Update after `deleted_at` is removed from the DB def create(%Auth.Provider{} = provider, attrs) do %Actors.Group{memberships: []} |> cast(attrs, ~w[name provider_identifier last_synced_at]a) @@ -45,8 +43,6 @@ defmodule Domain.Actors.Group.Changeset do |> changeset() |> put_change(:provider_id, provider.id) |> put_change(:account_id, provider.account_id) - # resurrect synced groups - |> put_change(:deleted_at, nil) |> put_subject_trail(:created_by, :provider) end diff --git a/elixir/apps/domain/lib/domain/actors/group/query.ex b/elixir/apps/domain/lib/domain/actors/group/query.ex index 558b014f5..5148ce766 100644 --- a/elixir/apps/domain/lib/domain/actors/group/query.ex +++ b/elixir/apps/domain/lib/domain/actors/group/query.ex @@ -6,12 +6,6 @@ defmodule Domain.Actors.Group.Query do from(groups in Domain.Actors.Group, as: :groups) end - # TODO: HARD-DELETE - Remove after `deleted_at` is removed from DB - def not_deleted do - all() - |> where([groups: groups], is_nil(groups.deleted_at)) - end - def not_editable(queryable) do where(queryable, [groups: groups], not is_nil(groups.provider_id) or groups.type != :static) end @@ -69,17 +63,6 @@ defmodule Domain.Actors.Group.Query do where(queryable, [groups: groups], groups.last_synced_at != ^synced_at) end - # TODO: HARD-DELETE - Remove after `deleted_at` is removed from DB - def delete(queryable) do - queryable - |> Ecto.Query.select([groups: groups], groups) - |> Ecto.Query.update([groups: groups], - set: [ - deleted_at: fragment("COALESCE(?, timezone('UTC', NOW()))", groups.deleted_at) - ] - ) - end - def group_by_provider_id(queryable) do queryable |> group_by([groups: groups], groups.provider_id) @@ -112,13 +95,6 @@ defmodule Domain.Actors.Group.Query do subquery = 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.not_deleted(), - on: actors.id == memberships.actor_id - ) |> select([memberships: memberships], memberships.actor_id) |> limit(^limit) @@ -142,7 +118,7 @@ defmodule Domain.Actors.Group.Query do queryable, :left, [memberships: memberships], - actors in ^Domain.Actors.Actor.Query.not_deleted(), + actors in ^Domain.Actors.Actor.Query.all(), on: actors.id == memberships.actor_id, as: :actors ) @@ -180,43 +156,21 @@ defmodule Domain.Actors.Group.Query do {:ok, %{upserted_groups: count}} end - # TODO: Update after `deleted_at` is removed from DB # TODO: IDP Sync # See: https://github.com/firezone/firezone/issues/8750 - # We use CTE here which should be very performant even for very large inserts and deletions + # We use CTE here which should be very performant even for very large inserts def update_everyone_group_memberships(account_id) do - # Delete memberships for actors and groups that are soft-deleted - delete_memberships = - from( - agm in Domain.Actors.Membership, - where: - agm.account_id == ^account_id and - (exists( - from(a in Domain.Actors.Actor, - where: a.id == parent_as(:agm).actor_id and not is_nil(a.deleted_at) - ) - ) or - exists( - from(g in Domain.Actors.Group, - where: g.id == parent_as(:agm).group_id and not is_nil(g.deleted_at) - ) - )) - ) - |> from(as: :agm) - - # Insert memberships for the cross join of non-deleted user actors and managed groups + # Insert memberships for the cross join of user actors and managed groups insert_with_cte_fn = fn repo, _changes -> current_memberships_cte = from( a in Domain.Actors.Actor, cross_join: g in Domain.Actors.Group, where: - is_nil(a.deleted_at) and - a.account_id == ^account_id and + a.account_id == ^account_id and a.type in [:account_user, :account_admin_user] and g.type == :managed and - g.account_id == ^account_id and - is_nil(g.deleted_at), + g.account_id == ^account_id, select: %{ actor_id: a.id, group_id: g.id @@ -244,7 +198,6 @@ defmodule Domain.Actors.Group.Query do end Ecto.Multi.new() - |> Ecto.Multi.delete_all(:delete_memberships, delete_memberships) |> Ecto.Multi.run(:insert_memberships, insert_with_cte_fn) end @@ -273,11 +226,6 @@ defmodule Domain.Actors.Group.Query do values: &Domain.Auth.all_third_party_providers!/1, fun: &filter_by_provider_id/2 }, - %Domain.Repo.Filter{ - name: :deleted?, - type: :boolean, - fun: &filter_deleted/1 - }, %Domain.Repo.Filter{ name: :editable?, type: :boolean, @@ -293,19 +241,11 @@ defmodule Domain.Actors.Group.Query do {queryable, dynamic([groups: groups], groups.provider_id == ^provider_id)} end - # TODO: HARD-DELETE - Remove after `deleted_at` is removed from DB - def filter_deleted(queryable) do - {queryable, dynamic([groups: groups], not is_nil(groups.deleted_at))} - end - - # TODO: Update after `deleted_at` is removed from DB def filter_editable(queryable) do {queryable, dynamic( [groups: groups], - is_nil(groups.provider_id) and - is_nil(groups.deleted_at) and - groups.type == :static + is_nil(groups.provider_id) and groups.type == :static )} end end diff --git a/elixir/apps/domain/lib/domain/actors/group/sync.ex b/elixir/apps/domain/lib/domain/actors/group/sync.ex index d871f53fa..ab33f4151 100644 --- a/elixir/apps/domain/lib/domain/actors/group/sync.ex +++ b/elixir/apps/domain/lib/domain/actors/group/sync.ex @@ -45,21 +45,15 @@ defmodule Domain.Actors.Group.Sync do {:ok, groups} end - # TODO: Update after `deleted_at` is removed from DB defp plan_groups_update(groups, provider_identifiers) do identifiers_set = MapSet.new(provider_identifiers) {upsert, delete} = Enum.reduce(groups, {provider_identifiers, []}, fn group, {upsert, delete} -> - cond do - MapSet.member?(identifiers_set, group.provider_identifier) -> - {upsert, delete} - - !is_nil(group.deleted_at) -> - {upsert, delete} - - true -> - {upsert -- [group.provider_identifier], [group.provider_identifier] ++ delete} + if MapSet.member?(identifiers_set, group.provider_identifier) do + {upsert, delete} + else + {upsert -- [group.provider_identifier], [group.provider_identifier] ++ delete} 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 03c776019..a14b9c070 100644 --- a/elixir/apps/domain/lib/domain/actors/membership/query.ex +++ b/elixir/apps/domain/lib/domain/actors/membership/query.ex @@ -84,14 +84,14 @@ defmodule Domain.Actors.Membership.Query do end def with_joined_actors(queryable \\ all()) do - join(queryable, :inner, [memberships: memberships], actors in ^Actor.Query.not_deleted(), + join(queryable, :inner, [memberships: memberships], actors in ^Actor.Query.all(), 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.not_deleted(), + join(queryable, :inner, [memberships: memberships], groups in ^Group.Query.all(), on: groups.id == memberships.group_id, as: :groups ) @@ -139,13 +139,11 @@ defmodule Domain.Actors.Membership.Query do ai.provider_identifier = mi.user_provider_identifier AND ai.account_id = $#{account_id} AND ai.provider_id = $#{provider_id} - AND ai.deleted_at IS NULL ) JOIN actor_groups ag ON ( ag.provider_identifier = mi.group_provider_identifier AND ag.account_id = $#{account_id} AND ag.provider_id = $#{provider_id} - AND ag.deleted_at IS NULL ) ) INSERT INTO actor_group_memberships (id, actor_id, group_id, account_id, last_synced_at) diff --git a/elixir/apps/domain/lib/domain/auth.ex b/elixir/apps/domain/lib/domain/auth.ex index 257ac6cc1..c5e69127c 100644 --- a/elixir/apps/domain/lib/domain/auth.ex +++ b/elixir/apps/domain/lib/domain/auth.ex @@ -163,7 +163,7 @@ defmodule Domain.Auth do def list_providers(%Subject{} = subject, opts \\ []) do with :ok <- ensure_has_permissions(subject, Authorizer.manage_providers_permission()) do - Provider.Query.not_deleted() + Provider.Query.all() |> Authorizer.for_subject(Provider, subject) |> Repo.list(Provider.Query, opts) end @@ -177,7 +177,7 @@ defmodule Domain.Auth do end def all_third_party_providers!(%Subject{} = subject) do - Provider.Query.not_deleted() + Provider.Query.all() |> Provider.Query.by_account_id(subject.account.id) |> Provider.Query.by_adapter({:not_in, [:email, :userpass]}) |> Authorizer.for_subject(Provider, subject) @@ -185,7 +185,7 @@ defmodule Domain.Auth do end def all_providers!(%Subject{} = subject) do - Provider.Query.not_deleted() + Provider.Query.all() |> Provider.Query.by_account_id(subject.account.id) |> Authorizer.for_subject(Provider, subject) |> Repo.all() @@ -314,30 +314,10 @@ defmodule Domain.Auth do end end - def soft_delete_provider(%Provider{} = provider, %Subject{} = subject) do - provider - |> mutate_provider(subject, fn provider -> - if other_active_providers_exist?(provider) do - :ok = soft_delete_identities_for(provider, subject) - {:ok, _groups} = Actors.soft_delete_groups_for(provider, subject) - Provider.Changeset.soft_delete_provider(provider) - else - :cant_delete_the_last_provider - end - end) - |> case do - {:ok, provider} -> - Adapters.ensure_deprovisioned(provider) - - {:error, reason} -> - {:error, reason} - end - end - defp mutate_provider(%Provider{} = provider, %Subject{} = subject, callback) when is_function(callback, 1) do with :ok <- ensure_has_permissions(subject, Authorizer.manage_providers_permission()) do - Provider.Query.not_deleted() + Provider.Query.all() |> Provider.Query.by_id(provider.id) |> Authorizer.for_subject(Provider, subject) |> Repo.fetch_and_update(Provider.Query, with: callback) @@ -367,7 +347,7 @@ defmodule Domain.Auth do # Identities def max_last_seen_at_by_actor_ids(actor_ids) do - Identity.Query.not_deleted() + Identity.Query.all() |> Identity.Query.by_actor_id({:in, actor_ids}) |> Identity.Query.max_last_seen_at_grouped_by_actor_id() |> Repo.all() @@ -392,7 +372,7 @@ defmodule Domain.Auth do def fetch_identity_by_id(id, %Subject{} = subject, opts \\ []) do with :ok <- ensure_has_permissions(subject, Authorizer.manage_identities_permission()), true <- Repo.valid_uuid?(id) do - Identity.Query.not_deleted() + Identity.Query.all() |> Identity.Query.by_id(id) |> Authorizer.for_subject(Identity, subject) |> Repo.fetch(Identity.Query, opts) @@ -406,7 +386,7 @@ defmodule Domain.Auth do def fetch_identities_count_grouped_by_provider_id(%Subject{} = subject) do with :ok <- ensure_has_permissions(subject, Authorizer.manage_identities_permission()) do identities = - Identity.Query.not_deleted() + Identity.Query.all() |> Identity.Query.group_by_provider_id() |> Authorizer.for_subject(Identity, subject) |> Repo.all() @@ -419,14 +399,14 @@ defmodule Domain.Auth do end def all_identities_for(%Actors.Actor{} = actor, opts \\ []) do - Identity.Query.not_deleted() + Identity.Query.all() |> Identity.Query.by_actor_id(actor.id) |> Repo.all(opts) end def list_identities_for(%Actors.Actor{} = actor, %Subject{} = subject, opts \\ []) do with :ok <- ensure_has_permissions(subject, Authorizer.manage_identities_permission()) do - Identity.Query.not_deleted() + Identity.Query.all() |> Identity.Query.by_actor_id(actor.id) |> Authorizer.for_subject(Identity, subject) |> Repo.list(Identity.Query, opts) @@ -451,14 +431,11 @@ defmodule Domain.Auth do end # used by IdP adapters - # TODO: HARD-DELETE - Remove `unsafe_fragment` after `deleted_at` column is removed from DB def upsert_identity(%Actors.Actor{} = actor, %Provider{} = provider, attrs) do Identity.Changeset.create_identity(actor, provider, attrs) |> Adapters.identity_changeset(provider) |> Repo.insert( - conflict_target: - {:unsafe_fragment, - ~s/(account_id, provider_id, provider_identifier) WHERE deleted_at IS NULL/}, + conflict_target: {:unsafe_fragment, "(account_id, provider_id, provider_identifier)"}, on_conflict: {:replace, [:provider_state]}, returning: true ) @@ -516,78 +493,6 @@ defmodule Domain.Auth do end end - # TODO: HARD-DELETE - # This function should not be necessary after hard delete because deleting a provider - # will delete all of it's identities using a cascading delete in the DB - def delete_identities_for(%Provider{} = provider, %Subject{} = subject) do - with :ok <- ensure_has_permissions(subject, Authorizer.manage_identities_permission()) do - {num_deleted, _} = - Identity.Query.all() - |> Identity.Query.by_provider_id(provider.id) - |> Identity.Query.by_account_id(provider.account_id) - |> Authorizer.for_subject(Identity, subject) - |> Repo.delete_all() - - {:ok, num_deleted} - end - end - - # TODO: HARD-DELETE - Remove after `deleted_at` column is removed in DB - def soft_delete_identity(%Identity{} = identity, %Subject{} = subject) do - required_permissions = - {:one_of, - [ - Authorizer.manage_identities_permission(), - Authorizer.manage_own_identities_permission() - ]} - - with :ok <- ensure_has_permissions(subject, required_permissions) do - Identity.Query.not_deleted() - |> Identity.Query.by_id(identity.id) - |> Authorizer.for_subject(Identity, subject) - |> Repo.fetch_and_update(Identity.Query, - with: fn identity -> - {:ok, _tokens} = Tokens.soft_delete_tokens_for(identity, subject) - Identity.Changeset.delete_identity(identity) - end - ) - end - end - - # TODO: HARD-DELETE - Remove after `deleted_at` column is removed in DB - def soft_delete_identities_for(%Actors.Actor{} = actor, %Subject{} = subject) do - Identity.Query.not_deleted() - |> Identity.Query.by_actor_id(actor.id) - |> Identity.Query.by_account_id(actor.account_id) - |> soft_delete_identities(actor, subject) - end - - # TODO: HARD-DELETE - Remove after `deleted_at` column is removed in DB - def soft_delete_identities_for(%Provider{} = provider, %Subject{} = subject) do - Identity.Query.not_deleted() - |> Identity.Query.by_provider_id(provider.id) - |> Identity.Query.by_account_id(provider.account_id) - |> soft_delete_identities(provider, subject) - end - - # TODO: HARD-DELETE - Remove after `deleted_at` column is removed in DB - defp soft_delete_identities(queryable, assoc, subject) do - with :ok <- ensure_has_permissions(subject, Authorizer.manage_identities_permission()) do - {:ok, _tokens} = Tokens.soft_delete_tokens_for(assoc, subject) - - {_count, nil} = - queryable - |> Authorizer.for_subject(Identity, subject) - |> Repo.update_all(set: [deleted_at: DateTime.utc_now(), provider_state: %{}]) - - :ok - end - end - - # TODO: HARD-DELETE - Remove after `deleted_at` column is removed in DB - def identity_soft_deleted?(%{deleted_at: nil}), do: false - def identity_soft_deleted?(_identity), do: true - # Sign Up / In / Off @doc """ @@ -604,18 +509,6 @@ defmodule Domain.Auth do {:error, :unauthorized} end - # TODO: HARD-DELETE - Remove after `deleted_at` column is removed in DB - def sign_in( - %Provider{deleted_at: deleted_at}, - _id_or_provider_identifier, - _token_nonce, - _secret, - %Context{} - ) - when not is_nil(deleted_at) do - {:error, :unauthorized} - end - def sign_in( %Provider{} = provider, id_or_provider_identifier, @@ -648,12 +541,6 @@ defmodule Domain.Auth do {:error, :unauthorized} end - # TODO: HARD-DELETE - Remove after `deleted_at` column is removed in DB - def sign_in(%Provider{deleted_at: deleted_at}, _token_nonce, _payload, %Context{}) - when not is_nil(deleted_at) do - {:error, :unauthorized} - end - def sign_in(%Provider{} = provider, token_nonce, payload, %Context{} = context) do with {:ok, identity, expires_at} <- Adapters.verify_and_update_identity(provider, payload), identity = Repo.preload(identity, :actor), diff --git a/elixir/apps/domain/lib/domain/auth/adapters/openid_connect.ex b/elixir/apps/domain/lib/domain/auth/adapters/openid_connect.ex index 796f5b0cc..e46f8426a 100644 --- a/elixir/apps/domain/lib/domain/auth/adapters/openid_connect.ex +++ b/elixir/apps/domain/lib/domain/auth/adapters/openid_connect.ex @@ -201,7 +201,7 @@ defmodule Domain.Auth.Adapters.OpenIDConnect do with {:ok, _provider_identifier, _email, adapter_state} <- fetch_state(provider, token_params, identifier_claim) do - Provider.Query.not_deleted() + Provider.Query.all() |> Provider.Query.by_id(provider.id) |> Repo.fetch_and_update(Provider.Query, with: fn provider -> @@ -215,7 +215,7 @@ defmodule Domain.Auth.Adapters.OpenIDConnect do ) else {:error, :expired_token} -> - Provider.Query.not_deleted() + Provider.Query.all() |> Provider.Query.by_id(provider.id) |> Repo.fetch_and_update(Provider.Query, with: fn provider -> @@ -228,7 +228,7 @@ defmodule Domain.Auth.Adapters.OpenIDConnect do {:error, :expired} {:error, :invalid_token} -> - Provider.Query.not_deleted() + Provider.Query.all() |> Provider.Query.by_id(provider.id) |> Repo.fetch_and_update(Provider.Query, with: fn provider -> @@ -253,7 +253,7 @@ defmodule Domain.Auth.Adapters.OpenIDConnect do with {:ok, _provider_identifier, _email, identity_state} <- fetch_state(identity.provider, token_params, identifier_claim) do - Identity.Query.not_deleted() + Identity.Query.all() |> Identity.Query.by_id(identity.id) |> Repo.fetch_and_update(Identity.Query, with: &Identity.Changeset.update_identity_provider_state(&1, identity_state) diff --git a/elixir/apps/domain/lib/domain/auth/identity.ex b/elixir/apps/domain/lib/domain/auth/identity.ex index e7d1fe349..ac74a4f8c 100644 --- a/elixir/apps/domain/lib/domain/auth/identity.ex +++ b/elixir/apps/domain/lib/domain/auth/identity.ex @@ -23,14 +23,10 @@ defmodule Domain.Auth.Identity do field :created_by, Ecto.Enum, values: ~w[system provider identity]a field :created_by_subject, :map - # TODO: HARD-DELETE - Remove `where` after `deleted_at` is removed from the DB - has_many :clients, Domain.Clients.Client, where: [deleted_at: nil] + has_many :clients, Domain.Clients.Client - # TODO: HARD-DELETE - Remove `where` after `deleted_at` is removed from the DB - has_many :tokens, Domain.Tokens.Token, foreign_key: :identity_id, where: [deleted_at: nil] + has_many :tokens, Domain.Tokens.Token, foreign_key: :identity_id - # TODO: HARD-DELETE - Remove field after soft deletion is removed - field :deleted_at, :utc_datetime_usec timestamps(updated_at: false) end end diff --git a/elixir/apps/domain/lib/domain/auth/identity/changeset.ex b/elixir/apps/domain/lib/domain/auth/identity/changeset.ex index b11496f2d..6d9e53a6a 100644 --- a/elixir/apps/domain/lib/domain/auth/identity/changeset.ex +++ b/elixir/apps/domain/lib/domain/auth/identity/changeset.ex @@ -60,7 +60,6 @@ defmodule Domain.Auth.Identity.Changeset do Actors.Actor.Changeset.sync(actor, attrs) end ) - |> put_change(:deleted_at, nil) |> changeset() end @@ -82,15 +81,6 @@ defmodule Domain.Auth.Identity.Changeset do |> put_change(:provider_virtual_state, virtual_state) end - # TODO: HARD-DELETE - Remove after `deleted_at` is removed from DB - def delete_identity(%Identity{} = identity) do - identity - |> change() - |> put_change(:provider_state, %{}) - |> put_change(:provider_virtual_state, %{}) - |> put_default_value(:deleted_at, DateTime.utc_now()) - end - defp maybe_put_email_from_identifier(changeset) do identifier = get_field(changeset, :provider_identifier) email = get_field(changeset, :email) diff --git a/elixir/apps/domain/lib/domain/auth/identity/query.ex b/elixir/apps/domain/lib/domain/auth/identity/query.ex index 420136217..7acf712ce 100644 --- a/elixir/apps/domain/lib/domain/auth/identity/query.ex +++ b/elixir/apps/domain/lib/domain/auth/identity/query.ex @@ -6,26 +6,11 @@ defmodule Domain.Auth.Identity.Query do from(identities in Domain.Auth.Identity, as: :identities) end - # TODO: HARD-DELETE - Remove after `deleted_at` is removed from DB - def not_deleted do - all() - |> where([identities: identities], is_nil(identities.deleted_at)) - end - - # TODO: HARD-DELETE - Remove after `deleted_at` is removed from DB - def deleted do - all() - |> where([identities: identities], not is_nil(identities.deleted_at)) - end - - # TODO: Update after `deleted_at` is removed from DB - def not_disabled(queryable \\ not_deleted()) do + def not_disabled(queryable \\ all()) do queryable |> with_assoc(:inner, :actor) - |> where([actor: actor], is_nil(actor.deleted_at)) |> where([actor: actor], is_nil(actor.disabled_at)) |> with_assoc(:inner, :provider) - |> where([provider: provider], is_nil(provider.deleted_at)) |> where([provider: provider], is_nil(provider.disabled_at)) end @@ -152,18 +137,6 @@ defmodule Domain.Auth.Identity.Query do }) end - # TODO: HARD-DELETE - Remove after `deleted_at` is removed from DB - def delete(queryable) do - queryable - |> Ecto.Query.select([identities: identities], identities) - |> Ecto.Query.update([identities: identities], - set: [ - deleted_at: fragment("COALESCE(?, timezone('UTC', NOW()))", identities.deleted_at), - provider_state: ^%{} - ] - ) - end - def with_preloaded_assoc(queryable, type \\ :left, assoc) do queryable |> with_assoc(type, assoc) @@ -211,7 +184,6 @@ defmodule Domain.Auth.Identity.Query do WHERE ai.account_id = $#{account_id} AND ai.provider_id = $#{provider_id} AND ai.provider_identifier IN (SELECT provider_identifier FROM input_data) - AND ai.deleted_at IS NULL ), actors_to_create AS ( SELECT @@ -271,7 +243,6 @@ defmodule Domain.Auth.Identity.Query do FROM all_actor_mappings aam LEFT JOIN existing_identities ei ON ei.provider_identifier = aam.provider_identifier ON CONFLICT (account_id, provider_id, provider_identifier) - WHERE deleted_at IS NULL DO UPDATE SET email = EXCLUDED.email, provider_state = COALESCE(auth_identities.provider_state, '{}'::jsonb) || diff --git a/elixir/apps/domain/lib/domain/auth/identity/sync.ex b/elixir/apps/domain/lib/domain/auth/identity/sync.ex index b2cbe496e..5209429bf 100644 --- a/elixir/apps/domain/lib/domain/auth/identity/sync.ex +++ b/elixir/apps/domain/lib/domain/auth/identity/sync.ex @@ -50,7 +50,6 @@ defmodule Domain.Auth.Identity.Sync do {:ok, identities} end - # TODO: Update after `deleted_at` is removed from DB defp plan_identities_update(identities, provider_identifiers) do {insert, update, delete} = Enum.reduce( @@ -59,15 +58,10 @@ defmodule Domain.Auth.Identity.Sync do fn identity, {insert, update, delete} -> insert = insert -- [identity.provider_identifier] - cond do - identity.provider_identifier in provider_identifiers -> - {insert, [identity.provider_identifier] ++ update, delete} - - not is_nil(identity.deleted_at) -> - {insert, update, delete} - - true -> - {insert, update, [identity.provider_identifier] ++ delete} + if identity.provider_identifier in provider_identifiers do + {insert, [identity.provider_identifier] ++ update, delete} + else + {insert, update, [identity.provider_identifier] ++ delete} end end ) @@ -146,7 +140,6 @@ defmodule Domain.Auth.Identity.Sync do end) end - # TODO: Update after `deleted_at` is removed from DB defp update_identities_and_actors( identities, attrs_by_provider_identifier, @@ -159,19 +152,7 @@ defmodule Domain.Auth.Identity.Sync do end) |> Repo.preload(:actor) |> Enum.reduce(%{}, fn identity, acc -> - acc_identity = Map.get(acc, identity.provider_identifier) - - # make sure that deleted identities have the least priority in case of conflicts - cond do - is_nil(acc_identity) -> - Map.put(acc, identity.provider_identifier, identity) - - is_nil(acc_identity.deleted_at) -> - acc - - true -> - Map.put(acc, identity.provider_identifier, identity) - end + Map.put(acc, identity.provider_identifier, identity) end) provider_identifiers_to_update diff --git a/elixir/apps/domain/lib/domain/auth/provider.ex b/elixir/apps/domain/lib/domain/auth/provider.ex index 41e739677..619184bbf 100644 --- a/elixir/apps/domain/lib/domain/auth/provider.ex +++ b/elixir/apps/domain/lib/domain/auth/provider.ex @@ -14,9 +14,8 @@ defmodule Domain.Auth.Provider do belongs_to :account, Domain.Accounts.Account - # TODO: HARD-DELETE - Remove `where` after `deleted_at` is removed from DB - has_many :actor_groups, Domain.Actors.Group, where: [deleted_at: nil] - has_many :identities, Domain.Auth.Identity, where: [deleted_at: nil] + has_many :actor_groups, Domain.Actors.Group + has_many :identities, Domain.Auth.Identity field :created_by, Ecto.Enum, values: ~w[system identity actor]a field :created_by_subject, :map @@ -29,8 +28,6 @@ defmodule Domain.Auth.Provider do field :disabled_at, :utc_datetime_usec - # TODO: HARD-DELETE - Remove field after soft deletion is removed - field :deleted_at, :utc_datetime_usec field :assigned_default_at, :utc_datetime_usec timestamps() end diff --git a/elixir/apps/domain/lib/domain/auth/provider/changeset.ex b/elixir/apps/domain/lib/domain/auth/provider/changeset.ex index ef365c904..b79f7b232 100644 --- a/elixir/apps/domain/lib/domain/auth/provider/changeset.ex +++ b/elixir/apps/domain/lib/domain/auth/provider/changeset.ex @@ -4,10 +4,9 @@ defmodule Domain.Auth.Provider.Changeset do alias Domain.Auth.{Subject, Provider, Adapters} @create_fields ~w[id name adapter provisioner adapter_config adapter_state disabled_at assigned_default_at]a - # TODO: HARD-DELETE - Update after `deleted_at` is removed from DB @update_fields ~w[name adapter_config last_syncs_failed last_sync_error sync_disabled_at sync_error_emailed_at - adapter_state provisioner disabled_at deleted_at]a + adapter_state provisioner disabled_at]a @required_fields ~w[name adapter adapter_config provisioner]a def create(account, attrs, %Subject{} = subject) do @@ -131,11 +130,4 @@ defmodule Domain.Auth.Provider.Changeset do |> change() |> put_change(:disabled_at, nil) end - - # TODO: HARD-DELETE - Remove after `deleted_at` is removed from DB - def soft_delete_provider(%Provider{} = provider) do - provider - |> change() - |> put_default_value(:deleted_at, DateTime.utc_now()) - end end diff --git a/elixir/apps/domain/lib/domain/auth/provider/query.ex b/elixir/apps/domain/lib/domain/auth/provider/query.ex index c0b4a2711..922121943 100644 --- a/elixir/apps/domain/lib/domain/auth/provider/query.ex +++ b/elixir/apps/domain/lib/domain/auth/provider/query.ex @@ -5,13 +5,7 @@ defmodule Domain.Auth.Provider.Query do from(provider in Domain.Auth.Provider, as: :providers) end - # TODO: HARD-DELETE - Remove after `deleted_at` is removed from the DB - def not_deleted do - all() - |> where([providers: providers], is_nil(providers.deleted_at)) - end - - def not_disabled(queryable \\ not_deleted()) do + def not_disabled(queryable \\ all()) do where(queryable, [providers: providers], is_nil(providers.disabled_at)) end diff --git a/elixir/apps/domain/lib/domain/clients.ex b/elixir/apps/domain/lib/domain/clients.ex index 4b88a6569..744326164 100644 --- a/elixir/apps/domain/lib/domain/clients.ex +++ b/elixir/apps/domain/lib/domain/clients.ex @@ -18,13 +18,13 @@ defmodule Domain.Clients do end def count_by_account_id(account_id) do - Client.Query.not_deleted() + Client.Query.all() |> Client.Query.by_account_id(account_id) |> Repo.aggregate(:count) end def count_1m_active_users_for_account(%Accounts.Account{} = account) do - Client.Query.not_deleted() + Client.Query.all() |> Client.Query.by_account_id(account.id) |> Client.Query.by_last_seen_within(1, "month") |> Client.Query.select_distinct_actor_id() @@ -34,13 +34,13 @@ defmodule Domain.Clients do end def count_by_actor_id(actor_id) do - Client.Query.not_deleted() + Client.Query.all() |> Client.Query.by_actor_id(actor_id) |> Repo.aggregate(:count) end def count_incompatible_for(account, gateway_version) do - Client.Query.not_deleted() + Client.Query.all() |> Client.Query.by_account_id(account.id) |> Client.Query.by_last_seen_within(1, "week") |> Client.Query.by_incompatible_for(gateway_version) @@ -49,7 +49,7 @@ defmodule Domain.Clients do end def fetch_client_by_id(id, preload: :identity) do - Client.Query.not_deleted() + Client.Query.all() |> Client.Query.by_id(id) |> Repo.fetch(Client.Query, preload: :identity) end @@ -75,7 +75,7 @@ defmodule Domain.Clients do end def fetch_client_by_id!(id, opts \\ []) do - Client.Query.not_deleted() + Client.Query.all() |> Client.Query.by_id(id) |> Repo.fetch!(Client.Query, opts) end @@ -89,7 +89,7 @@ defmodule Domain.Clients do ]} with :ok <- Auth.ensure_has_permissions(subject, required_permissions) do - Client.Query.not_deleted() + Client.Query.all() |> Authorizer.for_subject(subject) |> Repo.list(Client.Query, opts) end @@ -109,7 +109,7 @@ defmodule Domain.Clients do with :ok <- Auth.ensure_has_permissions(subject, required_permissions), true <- Repo.valid_uuid?(actor_id) do - Client.Query.not_deleted() + Client.Query.all() |> Client.Query.by_actor_id(actor_id) |> Authorizer.for_subject(subject) |> Repo.list(Client.Query, opts) @@ -196,7 +196,7 @@ defmodule Domain.Clients do def update_client(%Client{} = client, attrs, %Auth.Subject{} = subject) do with :ok <- Authorizer.ensure_has_access_to(client, subject) do - Client.Query.not_deleted() + Client.Query.all() |> Client.Query.by_id(client.id) |> Authorizer.for_subject(subject) |> Repo.fetch_and_update(Client.Query, @@ -209,7 +209,7 @@ defmodule Domain.Clients do def verify_client(%Client{} = client, %Auth.Subject{} = subject) do with :ok <- Authorizer.ensure_has_access_to(client, subject), :ok <- Auth.ensure_has_permissions(subject, Authorizer.verify_clients_permission()) do - Client.Query.not_deleted() + Client.Query.all() |> Client.Query.by_id(client.id) |> Authorizer.for_subject(subject) |> Repo.fetch_and_update(Client.Query, @@ -222,7 +222,7 @@ defmodule Domain.Clients do def remove_client_verification(%Client{} = client, %Auth.Subject{} = subject) do with :ok <- Authorizer.ensure_has_access_to(client, subject), :ok <- Auth.ensure_has_permissions(subject, Authorizer.verify_clients_permission()) do - Client.Query.not_deleted() + Client.Query.all() |> Client.Query.by_id(client.id) |> Authorizer.for_subject(subject) |> Repo.fetch_and_update(Client.Query, @@ -240,7 +240,7 @@ defmodule Domain.Clients do def delete_clients_for(%Actors.Actor{} = actor, %Auth.Subject{} = subject) do queryable = - Client.Query.not_deleted() + Client.Query.all() |> Client.Query.by_actor_id(actor.id) |> Client.Query.by_account_id(actor.account_id) @@ -252,7 +252,6 @@ defmodule Domain.Clients do end end - # TODO: HARD-DELETE # We don't necessarily want to delete associated tokens when deleting a client because # that token could be a multi-owner token in the case of a headless client. # Instead we need to introduce the concept of ephemeral clients/gateways and permanent ones. diff --git a/elixir/apps/domain/lib/domain/clients/client.ex b/elixir/apps/domain/lib/domain/clients/client.ex index 74ce9e034..3c26298da 100644 --- a/elixir/apps/domain/lib/domain/clients/client.ex +++ b/elixir/apps/domain/lib/domain/clients/client.ex @@ -28,7 +28,6 @@ defmodule Domain.Clients.Client do verified_at: DateTime.t() | nil, verified_by: :system | :actor | :identity | nil, verified_by_subject: map() | nil, - deleted_at: DateTime.t() | nil, inserted_at: DateTime.t(), updated_at: DateTime.t() } @@ -70,8 +69,6 @@ defmodule Domain.Clients.Client do field :verified_by, Ecto.Enum, values: [:system, :actor, :identity] field :verified_by_subject, :map - # TODO: HARD-DELETE - Remove field after soft deletion is removed - field :deleted_at, :utc_datetime_usec timestamps() end end diff --git a/elixir/apps/domain/lib/domain/clients/client/changeset.ex b/elixir/apps/domain/lib/domain/clients/client/changeset.ex index 76d0dffcb..9b6d4dcde 100644 --- a/elixir/apps/domain/lib/domain/clients/client/changeset.ex +++ b/elixir/apps/domain/lib/domain/clients/client/changeset.ex @@ -12,9 +12,8 @@ defmodule Domain.Clients.Client.Changeset do # WireGuard base64-encoded string length @key_length 44 - # TODO: Update or remove after `deleted_at` is removed from DB def upsert_conflict_target, - do: {:unsafe_fragment, ~s/(account_id, actor_id, external_id) WHERE deleted_at IS NULL/} + do: {:unsafe_fragment, ~s/(account_id, actor_id, external_id)/} def upsert_on_conflict do Clients.Client.Query.all() diff --git a/elixir/apps/domain/lib/domain/clients/client/query.ex b/elixir/apps/domain/lib/domain/clients/client/query.ex index f5de0782b..d6290233a 100644 --- a/elixir/apps/domain/lib/domain/clients/client/query.ex +++ b/elixir/apps/domain/lib/domain/clients/client/query.ex @@ -5,12 +5,6 @@ defmodule Domain.Clients.Client.Query do from(clients in Domain.Clients.Client, as: :clients) end - # TODO: HARD-DELETE - Remove after `deleted_at` column is removed from DB - def not_deleted do - all() - |> where([clients: clients], is_nil(clients.deleted_at)) - end - def by_id(queryable, id) do where(queryable, [clients: clients], clients.id == ^id) end @@ -45,7 +39,7 @@ defmodule Domain.Clients.Client.Query do |> distinct(true) end - def count_clients_by_actor_id(queryable \\ not_deleted()) do + def count_clients_by_actor_id(queryable \\ all()) do queryable |> group_by([clients: clients], clients.actor_id) |> select([clients: clients], %{ @@ -67,28 +61,13 @@ defmodule Domain.Clients.Client.Query do ) end - def returning_not_deleted(queryable) do - select(queryable, [clients: clients], clients) - end - - # TODO: HARD-DELETE - Remove after `deleted_at` is removed from the DB - def soft_delete(queryable) do - queryable - |> Ecto.Query.select([clients: clients], clients) - |> Ecto.Query.update([clients: clients], - set: [ - deleted_at: fragment("COALESCE(?, timezone('UTC', NOW()))", clients.deleted_at) - ] - ) - end - def with_joined_actor(queryable) do with_named_binding(queryable, :actor, fn queryable, binding -> join( queryable, :inner, [clients: clients], - actor in ^Domain.Actors.Actor.Query.not_deleted(), + actor in ^Domain.Actors.Actor.Query.all(), on: clients.actor_id == actor.id, as: ^binding ) diff --git a/elixir/apps/domain/lib/domain/gateways.ex b/elixir/apps/domain/lib/domain/gateways.ex index d7fd9d583..5f75969c1 100644 --- a/elixir/apps/domain/lib/domain/gateways.ex +++ b/elixir/apps/domain/lib/domain/gateways.ex @@ -21,14 +21,14 @@ defmodule Domain.Gateways do end def count_groups_for_account(%Accounts.Account{} = account) do - Group.Query.not_deleted() + Group.Query.all() |> Group.Query.by_account_id(account.id) |> Group.Query.by_managed_by(:account) |> Repo.aggregate(:count) end def fetch_gateway_by_id(id) do - Gateway.Query.not_deleted() + Gateway.Query.all() |> Gateway.Query.by_id(id) |> Repo.fetch(Gateway.Query, []) end @@ -54,7 +54,7 @@ defmodule Domain.Gateways do end def fetch_internet_group(%Accounts.Account{} = account) do - Group.Query.not_deleted() + Group.Query.all() |> Group.Query.by_managed_by(:system) |> Group.Query.by_account_id(account.id) |> Group.Query.by_name("Internet") @@ -63,21 +63,21 @@ defmodule Domain.Gateways do def list_groups(%Auth.Subject{} = subject, opts \\ []) do with :ok <- Auth.ensure_has_permissions(subject, Authorizer.manage_gateways_permission()) do - Group.Query.not_deleted() + Group.Query.all() |> Authorizer.for_subject(subject) |> Repo.list(Group.Query, opts) end end def all_groups!(%Auth.Subject{} = subject) do - Group.Query.not_deleted() + Group.Query.all() |> Group.Query.by_managed_by(:account) |> Authorizer.for_subject(subject) |> Repo.all() end def all_groups_for_account!(%Accounts.Account{} = account) do - Group.Query.not_deleted() + Group.Query.all() |> Group.Query.by_managed_by(:account) |> Group.Query.by_account_id(account.id) |> Repo.all() @@ -124,7 +124,7 @@ defmodule Domain.Gateways do def update_group(%Group{managed_by: :account} = group, attrs, %Auth.Subject{} = subject) do with :ok <- Auth.ensure_has_permissions(subject, Authorizer.manage_gateways_permission()) do - Group.Query.not_deleted() + Group.Query.all() |> Group.Query.by_id(group.id) |> Authorizer.for_subject(subject) |> Repo.fetch_and_update( @@ -167,7 +167,7 @@ defmodule Domain.Gateways do def authenticate(encoded_token, %Auth.Context{} = context) when is_binary(encoded_token) do with {:ok, token} <- Tokens.use_token(encoded_token, context), - queryable = Group.Query.not_deleted() |> Group.Query.by_id(token.gateway_group_id), + queryable = Group.Query.all() |> Group.Query.by_id(token.gateway_group_id), {:ok, group} <- Repo.fetch(queryable, Group.Query, []) do {:ok, group, token} else @@ -197,14 +197,14 @@ defmodule Domain.Gateways do end def fetch_gateway_by_id!(id, opts \\ []) do - Gateway.Query.not_deleted() + Gateway.Query.all() |> Gateway.Query.by_id(id) |> Repo.fetch!(Gateway.Query, opts) end def list_gateways(%Auth.Subject{} = subject, opts \\ []) do with :ok <- Auth.ensure_has_permissions(subject, Authorizer.manage_gateways_permission()) do - Gateway.Query.not_deleted() + Gateway.Query.all() |> Authorizer.for_subject(subject) |> Repo.list(Gateway.Query, opts) end @@ -213,7 +213,7 @@ defmodule Domain.Gateways do def all_gateways_for_account!(%Account{} = account, opts \\ []) do {preload, _opts} = Keyword.pop(opts, :preload, []) - Gateway.Query.not_deleted() + Gateway.Query.all() |> Gateway.Query.by_account_id(account.id) |> Repo.all() |> Repo.preload(preload) @@ -265,7 +265,7 @@ defmodule Domain.Gateways do |> Map.keys() gateways = - Gateway.Query.not_deleted() + Gateway.Query.all() |> Gateway.Query.by_ids(connected_gateway_ids) |> Gateway.Query.by_account_id(subject.account.id) |> Gateway.Query.by_resource_id(resource_id) @@ -314,7 +314,7 @@ defmodule Domain.Gateways do def update_gateway(%Gateway{} = gateway, attrs, %Auth.Subject{} = subject) do with :ok <- Auth.ensure_has_permissions(subject, Authorizer.manage_gateways_permission()) do - Gateway.Query.not_deleted() + Gateway.Query.all() |> Gateway.Query.by_id(gateway.id) |> Authorizer.for_subject(subject) |> Repo.fetch_and_update(Gateway.Query, @@ -324,19 +324,6 @@ defmodule Domain.Gateways do end end - # TODO: HARD-DELETE - Remove this once deleted_at field is gone - def soft_delete_gateway(%Gateway{} = gateway, %Auth.Subject{} = subject) do - with :ok <- Auth.ensure_has_permissions(subject, Authorizer.manage_gateways_permission()) do - Gateway.Query.not_deleted() - |> Gateway.Query.by_id(gateway.id) - |> Authorizer.for_subject(subject) - |> Repo.fetch_and_update(Gateway.Query, - with: &Gateway.Changeset.soft_delete/1, - preload: [:online?] - ) - end - end - def delete_gateway(%Gateway{} = gateway, %Auth.Subject{} = subject) do with :ok <- Authorizer.ensure_has_access_to(gateway, subject) do Repo.delete(gateway) diff --git a/elixir/apps/domain/lib/domain/gateways/gateway.ex b/elixir/apps/domain/lib/domain/gateways/gateway.ex index 47bdf4189..0a04eb222 100644 --- a/elixir/apps/domain/lib/domain/gateways/gateway.ex +++ b/elixir/apps/domain/lib/domain/gateways/gateway.ex @@ -20,7 +20,6 @@ defmodule Domain.Gateways.Gateway do online?: boolean(), account_id: Ecto.UUID.t(), group_id: Ecto.UUID.t(), - deleted_at: DateTime.t(), inserted_at: DateTime.t(), updated_at: DateTime.t() } @@ -50,8 +49,6 @@ defmodule Domain.Gateways.Gateway do belongs_to :account, Domain.Accounts.Account belongs_to :group, Domain.Gateways.Group - # TODO: HARD-DELETE - Remove field after soft deletion is removed - field :deleted_at, :utc_datetime_usec timestamps() end end diff --git a/elixir/apps/domain/lib/domain/gateways/gateway/changeset.ex b/elixir/apps/domain/lib/domain/gateways/gateway/changeset.ex index e352ba372..96a475aed 100644 --- a/elixir/apps/domain/lib/domain/gateways/gateway/changeset.ex +++ b/elixir/apps/domain/lib/domain/gateways/gateway/changeset.ex @@ -27,9 +27,8 @@ defmodule Domain.Gateways.Gateway.Changeset do # WireGuard base64-encoded string length @key_length 44 - # TODO: Update or remove after `deleted_at` is removed from DB def upsert_conflict_target, - do: {:unsafe_fragment, ~s/(account_id, group_id, external_id) WHERE deleted_at IS NULL/} + do: {:unsafe_fragment, ~s/(account_id, group_id, external_id)/} def upsert_on_conflict, do: {:replace, @conflict_replace_fields} @@ -72,13 +71,6 @@ defmodule Domain.Gateways.Gateway.Changeset do |> validate_required(@required_fields) end - # TODO: HARD-DELETE - Remove after `deleted_at` is removed from DB - def soft_delete(%Gateways.Gateway{} = gateway) do - gateway - |> change() - |> put_default_value(:deleted_at, DateTime.utc_now()) - end - defp changeset(changeset) do changeset |> trim_change(:name) diff --git a/elixir/apps/domain/lib/domain/gateways/gateway/query.ex b/elixir/apps/domain/lib/domain/gateways/gateway/query.ex index cbbfb224a..5066f73e9 100644 --- a/elixir/apps/domain/lib/domain/gateways/gateway/query.ex +++ b/elixir/apps/domain/lib/domain/gateways/gateway/query.ex @@ -5,12 +5,6 @@ defmodule Domain.Gateways.Gateway.Query do from(gateways in Domain.Gateways.Gateway, as: :gateways) end - # TODO: HARD-DELETE - Remove after `deleted_at` column is removed from DB - def not_deleted do - all() - |> where([gateways: gateways], is_nil(gateways.deleted_at)) - end - def by_id(queryable, id) do where(queryable, [gateways: gateways], gateways.id == ^id) end @@ -37,10 +31,6 @@ defmodule Domain.Gateways.Gateway.Query do |> where([connections: connections], connections.resource_id == ^resource_id) end - def returning_not_deleted(queryable) do - select(queryable, [gateways: gateways], gateways) - end - def with_joined_connections(queryable) do with_named_binding(queryable, :connections, fn queryable, binding -> queryable @@ -92,11 +82,6 @@ defmodule Domain.Gateways.Gateway.Query do name: :ids, type: {:list, {:string, :uuid}}, fun: &filter_by_ids/2 - }, - %Domain.Repo.Filter{ - name: :deleted?, - type: :boolean, - fun: &filter_deleted/1 } ] @@ -107,9 +92,4 @@ defmodule Domain.Gateways.Gateway.Query do def filter_by_ids(queryable, ids) do {queryable, dynamic([gateways: gateways], gateways.id in ^ids)} end - - # TODO: HARD-DELETE - Remove after `deleted_at` column is removed from DB - def filter_deleted(queryable) do - {queryable, dynamic([gateways: gateways], not is_nil(gateways.deleted_at))} - end end diff --git a/elixir/apps/domain/lib/domain/gateways/group.ex b/elixir/apps/domain/lib/domain/gateways/group.ex index fb069045d..00748cd97 100644 --- a/elixir/apps/domain/lib/domain/gateways/group.ex +++ b/elixir/apps/domain/lib/domain/gateways/group.ex @@ -8,7 +8,6 @@ defmodule Domain.Gateways.Group do account_id: Ecto.UUID.t(), created_by: :actor | :identity | :system, created_by_subject: map(), - deleted_at: DateTime.t() | nil, inserted_at: DateTime.t(), updated_at: DateTime.t() } @@ -19,21 +18,15 @@ defmodule Domain.Gateways.Group do field :managed_by, Ecto.Enum, values: ~w[account system]a belongs_to :account, Domain.Accounts.Account - # TODO: HARD-DELETE - Remove `where` after `deleted_at` column is remove - has_many :gateways, Domain.Gateways.Gateway, foreign_key: :group_id, where: [deleted_at: nil] + has_many :gateways, Domain.Gateways.Gateway, foreign_key: :group_id - # TODO: HARD-DELETE - Remove `where` after `deleted_at` column is remove - has_many :tokens, Domain.Tokens.Token, - foreign_key: :gateway_group_id, - where: [deleted_at: nil] + has_many :tokens, Domain.Tokens.Token, foreign_key: :gateway_group_id has_many :connections, Domain.Resources.Connection, foreign_key: :gateway_group_id field :created_by, Ecto.Enum, values: ~w[actor identity system]a field :created_by_subject, :map - # TODO: HARD-DELETE - Remove field after soft deletion is removed - field :deleted_at, :utc_datetime_usec timestamps() end end diff --git a/elixir/apps/domain/lib/domain/gateways/group/changeset.ex b/elixir/apps/domain/lib/domain/gateways/group/changeset.ex index b689e6185..870071b0d 100644 --- a/elixir/apps/domain/lib/domain/gateways/group/changeset.ex +++ b/elixir/apps/domain/lib/domain/gateways/group/changeset.ex @@ -39,11 +39,4 @@ defmodule Domain.Gateways.Group.Changeset do |> validate_length(:name, min: 1, max: 64) |> unique_constraint(:name, name: :gateway_groups_account_id_name_managed_by_index) end - - # TODO: HARD-DELETE - Remove after `deleted_at` is removed from the DB - def delete(%Gateways.Group{} = group) do - group - |> change() - |> put_default_value(:deleted_at, DateTime.utc_now()) - end end diff --git a/elixir/apps/domain/lib/domain/gateways/group/query.ex b/elixir/apps/domain/lib/domain/gateways/group/query.ex index 2f52b9ed3..b7a449d66 100644 --- a/elixir/apps/domain/lib/domain/gateways/group/query.ex +++ b/elixir/apps/domain/lib/domain/gateways/group/query.ex @@ -5,12 +5,6 @@ defmodule Domain.Gateways.Group.Query do from(groups in Domain.Gateways.Group, as: :groups) end - # TODO: HARD-DELETE - Remove after `deleted_at` is removed from DB - def not_deleted do - all() - |> where([groups: groups], is_nil(groups.deleted_at)) - end - def by_id(queryable, id) do where(queryable, [groups: groups], groups.id == ^id) end @@ -45,11 +39,6 @@ defmodule Domain.Gateways.Group.Query do @impl Domain.Repo.Query def filters, do: [ - %Domain.Repo.Filter{ - name: :deleted?, - type: :boolean, - fun: &filter_deleted/1 - }, %Domain.Repo.Filter{ name: :managed_by, type: :string, @@ -57,11 +46,6 @@ defmodule Domain.Gateways.Group.Query do } ] - # TODO: HARD-DELETE - Remove after `deleted_at` is removed from DB - def filter_deleted(queryable) do - {queryable, dynamic([groups: groups], not is_nil(groups.deleted_at))} - end - def filter_managed_by(queryable, managed_by) do {queryable, dynamic([groups: groups], groups.managed_by == ^managed_by)} end diff --git a/elixir/apps/domain/lib/domain/ops.ex b/elixir/apps/domain/lib/domain/ops.ex index 15c2f6b43..baae8edfe 100644 --- a/elixir/apps/domain/lib/domain/ops.ex +++ b/elixir/apps/domain/lib/domain/ops.ex @@ -109,7 +109,7 @@ defmodule Domain.Ops do To delete an account you need to disable it first by cancelling its subscription in Stripe. """ def delete_disabled_account(id) do - Domain.Accounts.Account.Query.not_deleted() + Domain.Accounts.Account.Query.all() |> Domain.Accounts.Account.Query.disabled() |> Domain.Accounts.Account.Query.by_id(id) |> Domain.Repo.one!() diff --git a/elixir/apps/domain/lib/domain/policies.ex b/elixir/apps/domain/lib/domain/policies.ex index 648d270db..1298be625 100644 --- a/elixir/apps/domain/lib/domain/policies.ex +++ b/elixir/apps/domain/lib/domain/policies.ex @@ -1,6 +1,6 @@ defmodule Domain.Policies do alias Domain.Repo - alias Domain.{Auth, Actors, Cache.Cacheable, Clients, Resources} + alias Domain.{Auth, Cache.Cacheable, Clients} alias Domain.Policies.{Authorizer, Policy, Condition} require Logger @@ -24,26 +24,6 @@ defmodule Domain.Policies do end end - def fetch_policy_by_id_or_persistent_id(id, %Auth.Subject{} = subject, opts \\ []) do - required_permissions = - {:one_of, - [ - Authorizer.manage_policies_permission(), - Authorizer.view_available_policies_permission() - ]} - - with :ok <- Auth.ensure_has_permissions(subject, required_permissions), - true <- Repo.valid_uuid?(id) do - Policy.Query.all() - |> Policy.Query.by_id_or_persistent_id(id) - |> Authorizer.for_subject(subject) - |> Repo.fetch(Policy.Query, opts) - else - false -> {:error, :not_found} - other -> other - end - end - def list_policies(%Auth.Subject{} = subject, opts \\ []) do required_permissions = {:one_of, @@ -53,7 +33,7 @@ defmodule Domain.Policies do ]} with :ok <- Auth.ensure_has_permissions(subject, required_permissions) do - Policy.Query.not_deleted() + Policy.Query.all() |> Authorizer.for_subject(subject) |> Repo.list(Policy.Query, opts) end @@ -108,7 +88,7 @@ defmodule Domain.Policies do def update_policy(%Policy{} = policy, attrs, %Auth.Subject{} = subject) do with :ok <- Auth.ensure_has_permissions(subject, Authorizer.manage_policies_permission()), :ok <- ensure_has_access_to(subject, policy) do - Policy.Query.not_deleted() + Policy.Query.all() |> Policy.Query.by_id(policy.id) |> Authorizer.for_subject(subject) |> Repo.fetch_and_update(Policy.Query, @@ -119,7 +99,7 @@ defmodule Domain.Policies do def disable_policy(%Policy{} = policy, %Auth.Subject{} = subject) do with :ok <- Auth.ensure_has_permissions(subject, Authorizer.manage_policies_permission()) do - Policy.Query.not_deleted() + Policy.Query.all() |> Policy.Query.by_id(policy.id) |> Authorizer.for_subject(subject) |> Repo.fetch_and_update(Policy.Query, @@ -130,7 +110,7 @@ defmodule Domain.Policies do def enable_policy(%Policy{} = policy, %Auth.Subject{} = subject) do with :ok <- Auth.ensure_has_permissions(subject, Authorizer.manage_policies_permission()) do - Policy.Query.not_deleted() + Policy.Query.all() |> Policy.Query.by_id(policy.id) |> Authorizer.for_subject(subject) |> Repo.fetch_and_update(Policy.Query, @@ -139,120 +119,12 @@ defmodule Domain.Policies do end end - # TODO: HARD-DELETE - Remove after `deleted_at` column is removed from DB - def soft_delete_policy(%Policy{} = policy, %Auth.Subject{} = subject) do - Policy.Query.not_deleted() - |> Policy.Query.by_id(policy.id) - |> soft_delete_policies(subject) - |> case do - {:ok, [policy]} -> {:ok, policy} - {:ok, []} -> {:error, :not_found} - {:error, reason} -> {:error, reason} - end - end - def delete_policy(%Policy{} = policy, %Auth.Subject{} = subject) do with :ok <- Authorizer.ensure_has_access_to(policy, subject) do Repo.delete(policy) end end - # TODO: HARD-DELETE - Should not be needed after hard delete is implemented - def delete_policies_for(%Resources.Resource{} = resource, %Auth.Subject{} = subject) do - with :ok <- Auth.ensure_has_permissions(subject, Authorizer.manage_policies_permission()) do - {count, nil} = - Policy.Query.all() - |> Policy.Query.by_resource_id(resource.id) - |> Authorizer.for_subject(subject) - |> Repo.delete_all() - - {:ok, count} - end - end - - # TODO: HARD-DELETE - Should not be needed after hard delete is implemented - def delete_policies_for(%Actors.Group{} = actor_group, %Auth.Subject{} = subject) do - with :ok <- Auth.ensure_has_permissions(subject, Authorizer.manage_policies_permission()) do - {count, nil} = - Policy.Query.all() - |> Policy.Query.by_actor_group_id(actor_group.id) - |> Authorizer.for_subject(subject) - |> Repo.delete_all() - - {:ok, count} - end - end - - # TODO: HARD-DELETE - Should not be needed after hard delete is implemented - def delete_policies_for(%Auth.Provider{} = provider, %Auth.Subject{} = subject) do - with :ok <- Auth.ensure_has_permissions(subject, Authorizer.manage_policies_permission()) do - {count, nil} = - Policy.Query.all() - |> Policy.Query.by_actor_group_provider_id(provider.id) - |> Authorizer.for_subject(subject) - |> Repo.delete_all() - - {:ok, count} - end - end - - # TODO: HARD-DELETE - Should not be needed after hard delete is implemented - def delete_policies_for(%Actors.Group{} = actor_group) do - {count, nil} = - Policy.Query.all() - |> Policy.Query.by_actor_group_id(actor_group.id) - |> Repo.delete_all() - - {:ok, count} - end - - # TODO: HARD-DELETE - Remove after `deleted_at` column is removed from DB - def soft_delete_policies_for(%Resources.Resource{} = resource, %Auth.Subject{} = subject) do - Policy.Query.not_deleted() - |> Policy.Query.by_resource_id(resource.id) - |> soft_delete_policies(subject) - end - - # TODO: HARD-DELETE - Remove after `deleted_at` column is removed from DB - def soft_delete_policies_for(%Actors.Group{} = actor_group, %Auth.Subject{} = subject) do - Policy.Query.not_deleted() - |> Policy.Query.by_actor_group_id(actor_group.id) - |> soft_delete_policies(subject) - end - - # TODO: HARD-DELETE - Remove after `deleted_at` column is removed from DB - def soft_delete_policies_for(%Auth.Provider{} = provider, %Auth.Subject{} = subject) do - Policy.Query.not_deleted() - |> Policy.Query.by_actor_group_provider_id(provider.id) - |> soft_delete_policies(subject) - end - - # TODO: HARD-DELETE - Remove after `deleted_at` column is removed from DB - def soft_delete_policies_for(%Actors.Group{} = actor_group) do - Policy.Query.not_deleted() - |> Policy.Query.by_actor_group_id(actor_group.id) - |> soft_delete_policies() - end - - # TODO: HARD-DELETE - Remove after `deleted_at` column is removed from DB - defp soft_delete_policies(queryable, subject) do - with :ok <- Auth.ensure_has_permissions(subject, Authorizer.manage_policies_permission()) do - queryable - |> Authorizer.for_subject(subject) - |> soft_delete_policies() - end - end - - # TODO: HARD-DELETE - Remove after `deleted_at` column is removed from DB - defp soft_delete_policies(queryable) do - {_count, policies} = - queryable - |> Policy.Query.delete() - |> Repo.update_all([]) - - {:ok, policies} - end - def filter_by_conforming_policies_for_client(policies, %Clients.Client{} = client) do Enum.filter(policies, fn policy -> policy.conditions diff --git a/elixir/apps/domain/lib/domain/policies/policy.ex b/elixir/apps/domain/lib/domain/policies/policy.ex index d76ad77d4..ae53d4de6 100644 --- a/elixir/apps/domain/lib/domain/policies/policy.ex +++ b/elixir/apps/domain/lib/domain/policies/policy.ex @@ -3,7 +3,6 @@ defmodule Domain.Policies.Policy do @type t :: %__MODULE__{ id: Ecto.UUID.t(), - persistent_id: Ecto.UUID.t(), description: String.t() | nil, conditions: [Domain.Policies.Condition.t()], actor_group_id: Ecto.UUID.t(), @@ -11,16 +10,12 @@ defmodule Domain.Policies.Policy do account_id: Ecto.UUID.t(), created_by: :actor | :identity, created_by_subject: map(), - replaced_by_policy_id: Ecto.UUID.t() | nil, disabled_at: DateTime.t() | nil, - deleted_at: DateTime.t() | nil, inserted_at: DateTime.t(), updated_at: DateTime.t() } schema "policies" do - field :persistent_id, Ecto.UUID - field :description, :string embeds_many :conditions, Domain.Policies.Condition, on_replace: :delete @@ -32,13 +27,8 @@ defmodule Domain.Policies.Policy do field :created_by, Ecto.Enum, values: ~w[actor identity]a field :created_by_subject, :map - belongs_to :replaced_by_policy, Domain.Policies.Policy - has_one :replaces_policy, Domain.Policies.Policy, foreign_key: :replaced_by_policy_id - field :disabled_at, :utc_datetime_usec - # TODO: HARD-DELETE - Remove field after soft deletion is removed - field :deleted_at, :utc_datetime_usec timestamps() end end diff --git a/elixir/apps/domain/lib/domain/policies/policy/changeset.ex b/elixir/apps/domain/lib/domain/policies/policy/changeset.ex index af21366da..a9bf303a1 100644 --- a/elixir/apps/domain/lib/domain/policies/policy/changeset.ex +++ b/elixir/apps/domain/lib/domain/policies/policy/changeset.ex @@ -15,7 +15,6 @@ defmodule Domain.Policies.Policy.Changeset do |> changeset() |> put_change(:account_id, subject.account.id) |> put_subject_trail(:created_by, subject) - |> put_change(:persistent_id, Ecto.UUID.generate()) end def update(%Policy{} = policy, attrs) do diff --git a/elixir/apps/domain/lib/domain/policies/policy/query.ex b/elixir/apps/domain/lib/domain/policies/policy/query.ex index 15b43bff9..defa87d3e 100644 --- a/elixir/apps/domain/lib/domain/policies/policy/query.ex +++ b/elixir/apps/domain/lib/domain/policies/policy/query.ex @@ -5,17 +5,11 @@ defmodule Domain.Policies.Policy.Query do from(policies in Domain.Policies.Policy, as: :policies) end - # TODO: HARD-DELETE - Remove after `deleted_at` column is removed from DB - def not_deleted do - all() - |> where([policies: policies], is_nil(policies.deleted_at)) - end - - def not_disabled(queryable \\ not_deleted()) do + def not_disabled(queryable \\ all()) do where(queryable, [policies: policies], is_nil(policies.disabled_at)) end - def disabled(queryable \\ not_deleted()) do + def disabled(queryable \\ all()) do where(queryable, [policies: policies], not is_nil(policies.disabled_at)) end @@ -23,14 +17,6 @@ defmodule Domain.Policies.Policy.Query do where(queryable, [policies: policies], policies.id == ^id) end - def by_id_or_persistent_id(queryable, id) do - where(queryable, [policies: policies], policies.id == ^id) - |> or_where( - [policies: policies], - policies.persistent_id == ^id and is_nil(policies.replaced_by_policy_id) - ) - end - def by_account_id(queryable, account_id) do where(queryable, [policies: policies], policies.account_id == ^account_id) end @@ -85,17 +71,6 @@ defmodule Domain.Policies.Policy.Query do }) end - # TODO: HARD-DELETE - Remove after `deleted_at` column is removed from DB - def delete(queryable) do - queryable - |> Ecto.Query.select([policies: policies], policies) - |> Ecto.Query.update([policies: policies], - set: [ - deleted_at: fragment("COALESCE(?, timezone('UTC', NOW()))", policies.deleted_at) - ] - ) - end - def with_joined_actor_group(queryable) do with_named_binding(queryable, :actor_group, fn queryable, binding -> join(queryable, :inner, [policies: policies], actor_group in assoc(policies, ^binding), @@ -192,11 +167,6 @@ defmodule Domain.Policies.Policy.Query do {"Disabled", "disabled"} ], fun: &filter_by_status/2 - }, - %Domain.Repo.Filter{ - name: :deleted?, - type: :boolean, - fun: &filter_deleted/1 } ] @@ -252,9 +222,4 @@ defmodule Domain.Policies.Policy.Query do def filter_by_status(queryable, "disabled") do {queryable, dynamic([policies: policies], not is_nil(policies.disabled_at))} end - - # TODO: HARD-DELETE - Remove after `deleted_at` column is removed from DB - def filter_deleted(queryable) do - {queryable, dynamic([policies: policies], not is_nil(policies.deleted_at))} - end end diff --git a/elixir/apps/domain/lib/domain/relays.ex b/elixir/apps/domain/lib/domain/relays.ex index 2e9c4759d..9c1df4995 100644 --- a/elixir/apps/domain/lib/domain/relays.ex +++ b/elixir/apps/domain/lib/domain/relays.ex @@ -39,7 +39,7 @@ defmodule Domain.Relays do def list_groups(%Auth.Subject{} = subject, opts \\ []) do with :ok <- Auth.ensure_has_permissions(subject, Authorizer.manage_relays_permission()) do - Group.Query.not_deleted() + Group.Query.all() |> Authorizer.for_subject(subject) |> Repo.list(Group.Query, opts) end @@ -93,30 +93,6 @@ defmodule Domain.Relays do end end - # TODO: HARD-DELETE - Remove after `deleted_at` column is removed from DB - def soft_delete_group(%Group{} = group, %Auth.Subject{} = subject) do - with :ok <- Auth.ensure_has_permissions(subject, Authorizer.manage_relays_permission()) do - Group.Query.not_deleted() - |> Group.Query.by_id(group.id) - |> Authorizer.for_subject(subject) - |> Group.Query.by_account_id(subject.account.id) - |> Repo.fetch_and_update(Group.Query, - with: fn group -> - {:ok, _tokens} = Tokens.soft_delete_tokens_for(group, subject) - - {_count, _} = - Relay.Query.not_deleted() - |> Relay.Query.by_group_id(group.id) - |> Repo.update_all(set: [deleted_at: DateTime.utc_now()]) - - Group.Changeset.delete(group) - end, - # TODO: Remove self-hosted relays - after_commit: &disconnect_relays_in_group/1 - ) - end - end - def create_token(%Group{account_id: nil} = group, attrs) do attrs = Map.merge(attrs, %{ @@ -153,7 +129,7 @@ defmodule Domain.Relays do def authenticate(encoded_token, %Auth.Context{} = context) when is_binary(encoded_token) do with {:ok, token} <- Tokens.use_token(encoded_token, context), - queryable = Group.Query.not_deleted() |> Group.Query.by_id(token.relay_group_id), + queryable = Group.Query.all() |> Group.Query.by_id(token.relay_group_id), {:ok, group} <- Repo.fetch(queryable, Group.Query, []) do {:ok, group, token} else @@ -176,14 +152,14 @@ defmodule Domain.Relays do end def fetch_relay_by_id!(id, opts \\ []) do - Relay.Query.not_deleted() + Relay.Query.all() |> Relay.Query.by_id(id) |> Repo.fetch!(Relay.Query, opts) end def list_relays(%Auth.Subject{} = subject, opts \\ []) do with :ok <- Auth.ensure_has_permissions(subject, Authorizer.manage_relays_permission()) do - Relay.Query.not_deleted() + Relay.Query.all() |> Authorizer.for_subject(subject) |> Repo.list(Relay.Query, opts) end @@ -257,7 +233,7 @@ defmodule Domain.Relays do connected_relay_ids = Map.keys(connected_relays) -- except_ids relays = - Relay.Query.not_deleted() + Relay.Query.all() |> Relay.Query.by_ids(connected_relay_ids) |> Relay.Query.global_or_by_account_id(account_id) # |> Relay.Query.by_last_seen_at_greater_than(5, "second", :ago) @@ -315,20 +291,6 @@ defmodule Domain.Relays do end end - # TODO: HARD-DELETE - Remove after `deleted_at` is removed from DB - def soft_delete_relay(%Relay{} = relay, %Auth.Subject{} = subject) do - with :ok <- Auth.ensure_has_permissions(subject, Authorizer.manage_relays_permission()) do - Relay.Query.not_deleted() - |> Relay.Query.by_id(relay.id) - |> Authorizer.for_subject(subject) - |> Repo.fetch_and_update(Relay.Query, - with: &Relay.Changeset.delete/1, - # TODO: Remove self-hosted relays - after_commit: &disconnect_relay/1 - ) - end - end - @doc """ Selects 3 nearest relays to the given location and then picks one of them randomly. """ diff --git a/elixir/apps/domain/lib/domain/relays/group.ex b/elixir/apps/domain/lib/domain/relays/group.ex index d4d82ba01..cc73f5268 100644 --- a/elixir/apps/domain/lib/domain/relays/group.ex +++ b/elixir/apps/domain/lib/domain/relays/group.ex @@ -5,15 +5,12 @@ defmodule Domain.Relays.Group do field :name, :string belongs_to :account, Domain.Accounts.Account - # TODO: HARD-DELETE - Remove `where` after `deleted_at` is removed from the DB - has_many :relays, Domain.Relays.Relay, foreign_key: :group_id, where: [deleted_at: nil] - has_many :tokens, Domain.Tokens.Token, foreign_key: :relay_group_id, where: [deleted_at: nil] + has_many :relays, Domain.Relays.Relay, foreign_key: :group_id + has_many :tokens, Domain.Tokens.Token, foreign_key: :relay_group_id field :created_by, Ecto.Enum, values: ~w[system identity]a field :created_by_subject, :map - # TODO: HARD-DELETE - Remove field after soft deletion is removed - field :deleted_at, :utc_datetime_usec timestamps() end end diff --git a/elixir/apps/domain/lib/domain/relays/group/changeset.ex b/elixir/apps/domain/lib/domain/relays/group/changeset.ex index 0d7c8da2c..aad4d0f69 100644 --- a/elixir/apps/domain/lib/domain/relays/group/changeset.ex +++ b/elixir/apps/domain/lib/domain/relays/group/changeset.ex @@ -36,11 +36,4 @@ defmodule Domain.Relays.Group.Changeset do |> unique_constraint(:name, name: :relay_groups_name_index) |> unique_constraint(:name, name: :relay_groups_account_id_name_index) end - - # TODO: HARD-DELETE - Remove after `deleted_at` is removed from the DB - def delete(%Relays.Group{} = group) do - group - |> change() - |> put_default_value(:deleted_at, DateTime.utc_now()) - end end diff --git a/elixir/apps/domain/lib/domain/relays/group/query.ex b/elixir/apps/domain/lib/domain/relays/group/query.ex index 4dfda8fc9..e167a53ce 100644 --- a/elixir/apps/domain/lib/domain/relays/group/query.ex +++ b/elixir/apps/domain/lib/domain/relays/group/query.ex @@ -5,12 +5,6 @@ defmodule Domain.Relays.Group.Query do from(groups in Domain.Relays.Group, as: :groups) end - # TODO: HARD-DELETE - Remove after `deleted_at` is removed from the DB - def not_deleted do - all() - |> where([groups: groups], is_nil(groups.deleted_at)) - end - def by_id(queryable, id) do where(queryable, [groups: groups], groups.id == ^id) end @@ -47,17 +41,5 @@ defmodule Domain.Relays.Group.Query do ] @impl Domain.Repo.Query - def filters, - do: [ - %Domain.Repo.Filter{ - name: :deleted?, - type: :boolean, - fun: &filter_deleted/1 - } - ] - - # TODO: HARD-DELETE - Remove after `deleted_at` is removed from the DB - def filter_deleted(queryable) do - {queryable, dynamic([groups: groups], not is_nil(groups.deleted_at))} - end + def filters, do: [] end diff --git a/elixir/apps/domain/lib/domain/relays/relay.ex b/elixir/apps/domain/lib/domain/relays/relay.ex index a600f3142..31c2d8820 100644 --- a/elixir/apps/domain/lib/domain/relays/relay.ex +++ b/elixir/apps/domain/lib/domain/relays/relay.ex @@ -25,8 +25,6 @@ defmodule Domain.Relays.Relay do belongs_to :account, Domain.Accounts.Account belongs_to :group, Domain.Relays.Group - # TODO: HARD-DELETE - Remove field after soft deletion is removed - field :deleted_at, :utc_datetime_usec timestamps() end end diff --git a/elixir/apps/domain/lib/domain/relays/relay/changeset.ex b/elixir/apps/domain/lib/domain/relays/relay/changeset.ex index faf271ae2..5bc7f1339 100644 --- a/elixir/apps/domain/lib/domain/relays/relay/changeset.ex +++ b/elixir/apps/domain/lib/domain/relays/relay/changeset.ex @@ -21,16 +21,12 @@ defmodule Domain.Relays.Relay.Changeset do last_seen_at updated_at]a - # TODO: HARD-DELETE - Update or remove after `deleted_at` is removed from DB def upsert_conflict_target(%{account_id: nil}) do - {:unsafe_fragment, - ~s/(COALESCE(ipv4, ipv6), port) WHERE deleted_at IS NULL AND account_id IS NULL/} + {:unsafe_fragment, ~s/(COALESCE(ipv4, ipv6), port) WHERE account_id IS NULL/} end - # TODO: HARD-DELETE - Update or remove after `deleted_at` is removed from DB def upsert_conflict_target(%{account_id: _account_id}) do - {:unsafe_fragment, - ~s/(account_id, COALESCE(ipv4, ipv6), port) WHERE deleted_at IS NULL AND account_id IS NOT NULL/} + {:unsafe_fragment, ~s/(account_id, COALESCE(ipv4, ipv6), port) WHERE account_id IS NOT NULL/} end def upsert_on_conflict, do: {:replace, @conflict_replace_fields} @@ -59,13 +55,6 @@ defmodule Domain.Relays.Relay.Changeset do |> put_change(:group_id, group.id) end - # TODO: HARD-DELETE - Remove after `deleted_at` is removed from DB - def delete(%Relays.Relay{} = relay) do - relay - |> change() - |> put_default_value(:deleted_at, DateTime.utc_now()) - end - def put_relay_version(changeset) do with {_data_or_changes, user_agent} when not is_nil(user_agent) <- fetch_field(changeset, :last_seen_user_agent), diff --git a/elixir/apps/domain/lib/domain/relays/relay/query.ex b/elixir/apps/domain/lib/domain/relays/relay/query.ex index b06a8d795..68851dad5 100644 --- a/elixir/apps/domain/lib/domain/relays/relay/query.ex +++ b/elixir/apps/domain/lib/domain/relays/relay/query.ex @@ -5,12 +5,6 @@ defmodule Domain.Relays.Relay.Query do from(relays in Domain.Relays.Relay, as: :relays) end - # TODO: HARD-DELETE - Remove after `deleted_at` is removed from DB - def not_deleted do - all() - |> where([relays: relays], is_nil(relays.deleted_at)) - end - def by_id(queryable, id) do where(queryable, [relays: relays], relays.id == ^id) end @@ -55,11 +49,6 @@ defmodule Domain.Relays.Relay.Query do order_by(queryable, [relays: relays], asc_nulls_first: relays.account_id) end - # TODO: HARD-DELETE - Remove or possibly rename after `deleted_at` is removed from DB - def returning_not_deleted(queryable) do - select(queryable, [relays: relays], relays) - end - def with_preloaded_user(queryable) do with_named_binding(queryable, :user, fn queryable, binding -> queryable diff --git a/elixir/apps/domain/lib/domain/resources.ex b/elixir/apps/domain/lib/domain/resources.ex index 860b28447..a4304762a 100644 --- a/elixir/apps/domain/lib/domain/resources.ex +++ b/elixir/apps/domain/lib/domain/resources.ex @@ -24,6 +24,16 @@ defmodule Domain.Resources do end end + def fetch_resource_by_id!(id) do + if Repo.valid_uuid?(id) do + Resource.Query.all() + |> Resource.Query.by_id(id) + |> Repo.one!() + else + {:error, :not_found} + end + end + def fetch_internet_resource(%Accounts.Account{} = account) do Resource.Query.all() |> Resource.Query.by_account_id(account.id) @@ -41,80 +51,20 @@ defmodule Domain.Resources do end end - def fetch_resource_by_id_or_persistent_id(id, %Auth.Subject{} = subject, opts \\ []) do - required_permissions = - {:one_of, - [ - Authorizer.manage_resources_permission(), - Authorizer.view_available_resources_permission() - ]} - - with :ok <- Auth.ensure_has_permissions(subject, required_permissions), - true <- Repo.valid_uuid?(id) do - Resource.Query.all() - |> Resource.Query.by_id_or_persistent_id(id) - |> Authorizer.for_subject(Resource, subject) - |> Repo.fetch(Resource.Query, opts) - else - false -> {:error, :not_found} - other -> other - end - end - - def fetch_active_resource_by_id_or_persistent_id(id, %Auth.Subject{} = subject, opts \\ []) do - required_permissions = - {:one_of, - [ - Authorizer.manage_resources_permission(), - Authorizer.view_available_resources_permission() - ]} - - with :ok <- Auth.ensure_has_permissions(subject, required_permissions), - true <- Repo.valid_uuid?(id) do - Resource.Query.not_deleted() - |> Resource.Query.by_id_or_persistent_id(id) - |> Authorizer.for_subject(Resource, subject) - |> Repo.fetch(Resource.Query, opts) - else - false -> {:error, :not_found} - other -> other - end - end - - def fetch_resource_by_id!(id) do - if Repo.valid_uuid?(id) do - Resource.Query.not_deleted() - |> Resource.Query.by_id(id) - |> Repo.one!() - else - {:error, :not_found} - end - end - def fetch_all_resources_by_ids(ids) do - Resource.Query.not_deleted() + Resource.Query.all() |> Resource.Query.by_id({:in, ids}) |> Repo.all() |> Repo.preload(:gateway_groups) end - def fetch_resource_by_id_or_persistent_id!(id) do - if Repo.valid_uuid?(id) do - Resource.Query.not_deleted() - |> Resource.Query.by_id_or_persistent_id(id) - |> Repo.one!() - else - {:error, :not_found} - end - end - def all_authorized_resources(%Auth.Subject{} = subject, opts \\ []) do with :ok <- Auth.ensure_has_permissions(subject, Authorizer.view_available_resources_permission()) do {preload, opts} = Keyword.pop(opts, :preload, []) resources = - Resource.Query.not_deleted() + Resource.Query.all() |> Resource.Query.by_account_id(subject.account.id) |> Resource.Query.by_authorized_actor_id(subject.actor.id) |> Resource.Query.with_at_least_one_gateway_group() @@ -126,32 +76,32 @@ defmodule Domain.Resources do end def all_resources!(%Auth.Subject{} = subject) do - Resource.Query.not_deleted() + Resource.Query.all() |> Resource.Query.by_account_id(subject.account.id) |> Resource.Query.filter_features(subject.account) |> Authorizer.for_subject(Resource, subject) |> Repo.all() end - def list_resources(%Auth.Subject{} = subject, opts \\ []) do - with :ok <- Auth.ensure_has_permissions(subject, Authorizer.manage_resources_permission()) do - Resource.Query.not_deleted() - |> Resource.Query.filter_features(subject.account) - |> Authorizer.for_subject(Resource, subject) - |> Repo.list(Resource.Query, opts) - end - end - def all_resources!(%Auth.Subject{} = subject, opts \\ []) do {preload, _opts} = Keyword.pop(opts, :preload, []) - Resource.Query.not_deleted() + Resource.Query.all() |> Resource.Query.filter_features(subject.account) |> Authorizer.for_subject(Resource, subject) |> Repo.all() |> Repo.preload(preload) end + def list_resources(%Auth.Subject{} = subject, opts \\ []) do + with :ok <- Auth.ensure_has_permissions(subject, Authorizer.manage_resources_permission()) do + Resource.Query.all() + |> Resource.Query.filter_features(subject.account) + |> Authorizer.for_subject(Resource, subject) + |> Repo.list(Resource.Query, opts) + end + end + def count_resources_for_gateway(%Gateways.Gateway{} = gateway, %Auth.Subject{} = subject) do required_permissions = {:one_of, @@ -162,7 +112,7 @@ defmodule Domain.Resources do with :ok <- Auth.ensure_has_permissions(subject, required_permissions) do count = - Resource.Query.not_deleted() + Resource.Query.all() |> Authorizer.for_subject(Resource, subject) |> Resource.Query.by_gateway_group_id(gateway.group_id) |> Repo.aggregate(:count) @@ -181,7 +131,7 @@ defmodule Domain.Resources do with :ok <- Auth.ensure_has_permissions(subject, required_permissions) do resources = - Resource.Query.not_deleted() + Resource.Query.all() |> Resource.Query.by_account_id(subject.account.id) |> Resource.Query.by_gateway_group_id(gateway.group_id) |> Repo.all() @@ -195,7 +145,7 @@ defmodule Domain.Resources do ids = resources |> Enum.map(& &1.id) |> Enum.uniq() {:ok, peek} = - Resource.Query.not_deleted() + Resource.Query.all() |> Resource.Query.by_id({:in, ids}) |> Authorizer.for_subject(Resource, subject) |> Resource.Query.preload_few_actor_groups_for_each_resource(limit) @@ -249,7 +199,7 @@ defmodule Domain.Resources do def update_resource(%Resource{} = resource, attrs, %Auth.Subject{} = subject) do with :ok <- Auth.ensure_has_permissions(subject, Authorizer.manage_resources_permission()) do - Resource.Query.not_deleted() + Resource.Query.all() |> Resource.Query.by_id(resource.id) |> Authorizer.for_subject(Resource, subject) |> Repo.fetch_and_update(Resource.Query, @@ -272,30 +222,6 @@ defmodule Domain.Resources do end end - # TODO: HARD-DELETE (shouldn't be needed) - def delete_connections_for(%Gateways.Group{} = gateway_group, %Auth.Subject{} = subject) do - Connection.Query.by_gateway_group_id(gateway_group.id) - |> delete_connections(subject) - end - - # TODO: HARD-DELETE (shouldn't be needed) - def delete_connections_for(%Resource{} = resource, %Auth.Subject{} = subject) do - Connection.Query.by_resource_id(resource.id) - |> delete_connections(subject) - end - - # TODO: HARD-DELETE (shouldn't be needed) - defp delete_connections(queryable, subject) do - with :ok <- Auth.ensure_has_permissions(subject, Authorizer.manage_resources_permission()) do - {count, nil} = - queryable - |> Authorizer.for_subject(Connection, subject) - |> Repo.delete_all() - - {:ok, count} - end - end - def connected?( resource_id, %Gateways.Gateway{} = gateway diff --git a/elixir/apps/domain/lib/domain/resources/resource.ex b/elixir/apps/domain/lib/domain/resources/resource.ex index 714f33ee7..0be85d7e6 100644 --- a/elixir/apps/domain/lib/domain/resources/resource.ex +++ b/elixir/apps/domain/lib/domain/resources/resource.ex @@ -8,7 +8,6 @@ defmodule Domain.Resources.Resource do @type t :: %__MODULE__{ id: Ecto.UUID.t(), - persistent_id: Ecto.UUID.t() | nil, address: String.t(), address_description: String.t() | nil, name: String.t(), @@ -18,15 +17,11 @@ defmodule Domain.Resources.Resource do account_id: Ecto.UUID.t(), created_by: String.t(), created_by_subject: map(), - replaced_by_resource_id: Ecto.UUID.t() | nil, - deleted_at: DateTime.t() | nil, inserted_at: DateTime.t(), updated_at: DateTime.t() } schema "resources" do - field :persistent_id, Ecto.UUID - field :address, :string field :address_description, :string field :name, :string @@ -41,12 +36,9 @@ defmodule Domain.Resources.Resource do belongs_to :account, Domain.Accounts.Account has_many :connections, Domain.Resources.Connection, on_replace: :delete - # TODO: where doesn't work on join tables so soft-deleted records will be preloaded, - # ref https://github.com/firezone/firezone/issues/2162 has_many :gateway_groups, through: [:connections, :gateway_group] - # TODO: HARD-DELETE - Remove `where` after `deleted_at` is removed from the DB - has_many :policies, Domain.Policies.Policy, where: [deleted_at: nil] + has_many :policies, Domain.Policies.Policy has_many :actor_groups, through: [:policies, :actor_group] # Warning: do not do Repo.preload/2 for this field, it will not work intentionally, @@ -56,11 +48,6 @@ defmodule Domain.Resources.Resource do field :created_by, Ecto.Enum, values: ~w[identity actor system]a field :created_by_subject, :map - belongs_to :replaced_by_resource, Domain.Resources.Resource - has_one :replaces_resource, Domain.Resources.Resource, foreign_key: :replaced_by_resource_id - - # TODO: HARD-DELETE - Remove field after soft deletion is removed - field :deleted_at, :utc_datetime_usec timestamps() end end diff --git a/elixir/apps/domain/lib/domain/resources/resource/changeset.ex b/elixir/apps/domain/lib/domain/resources/resource/changeset.ex index cc57fd145..a4ae62ba4 100644 --- a/elixir/apps/domain/lib/domain/resources/resource/changeset.ex +++ b/elixir/apps/domain/lib/domain/resources/resource/changeset.ex @@ -31,7 +31,6 @@ defmodule Domain.Resources.Resource.Changeset do |> cast(attrs, @fields) |> changeset() |> validate_required(@required_fields) - |> put_change(:persistent_id, Ecto.UUID.generate()) |> put_change(:account_id, account.id) |> validate_address(account) |> cast_assoc(:connections, @@ -47,7 +46,6 @@ defmodule Domain.Resources.Resource.Changeset do |> changeset() |> validate_required(@required_fields) |> validate_address(account) - |> put_change(:persistent_id, Ecto.UUID.generate()) |> put_change(:account_id, account.id) |> put_subject_trail(:created_by, :system) |> cast_assoc(:connections, @@ -67,13 +65,6 @@ defmodule Domain.Resources.Resource.Changeset do ) end - # TODO: HARD-DELETE - Remove after `deleted_at` column is removed from DB - def delete(%Resource{} = resource) do - resource - |> change() - |> put_default_value(:deleted_at, DateTime.utc_now()) - end - defp validate_address(changeset, account) do if has_errors?(changeset, :type) do changeset diff --git a/elixir/apps/domain/lib/domain/resources/resource/query.ex b/elixir/apps/domain/lib/domain/resources/resource/query.ex index 2dce043bf..25bd3b642 100644 --- a/elixir/apps/domain/lib/domain/resources/resource/query.ex +++ b/elixir/apps/domain/lib/domain/resources/resource/query.ex @@ -5,12 +5,6 @@ defmodule Domain.Resources.Resource.Query do from(resources in Domain.Resources.Resource, as: :resources) end - # TODO: HARD-DELETE - Remove after `deleted_at` column is removed from DB - def not_deleted do - all() - |> where([resources: resources], is_nil(resources.deleted_at)) - end - def filter_features(queryable, %Domain.Accounts.Account{} = account) do if Domain.Accounts.internet_resource_enabled?(account) do queryable @@ -31,14 +25,6 @@ defmodule Domain.Resources.Resource.Query do where(queryable, [resources: resources], resources.type == ^type) end - def by_id_or_persistent_id(queryable, id) do - where(queryable, [resources: resources], resources.id == ^id) - |> or_where( - [resources: resources], - resources.persistent_id == ^id and is_nil(resources.replaced_by_resource_id) - ) - end - def by_account_id(queryable, account_id) do where(queryable, [resources: resources], resources.account_id == ^account_id) end @@ -85,7 +71,7 @@ defmodule Domain.Resources.Resource.Query do |> limit(^limit) actor_groups_subquery = - Domain.Actors.Group.Query.not_deleted() + Domain.Actors.Group.Query.all() |> where([groups: groups], groups.id in subquery(policies_subquery)) join( @@ -135,7 +121,7 @@ defmodule Domain.Resources.Resource.Query do |> join( :inner, [connections: connections], - gateway_group in ^Domain.Gateways.Group.Query.not_deleted(), + gateway_group in ^Domain.Gateways.Group.Query.all(), on: gateway_group.id == connections.gateway_group_id, as: ^binding ) @@ -167,11 +153,6 @@ defmodule Domain.Resources.Resource.Query do values: [], fun: &filter_by_gateway_group_id/2 }, - %Domain.Repo.Filter{ - name: :deleted?, - type: :boolean, - fun: &filter_deleted/1 - }, %Domain.Repo.Filter{ name: :type, type: {:list, :string}, @@ -193,11 +174,6 @@ defmodule Domain.Resources.Resource.Query do dynamic([connections: connections], connections.gateway_group_id == ^gateway_group_id)} end - # TODO: HARD-DELETE - Remove after `deleted_at` column is removed from DB - def filter_deleted(queryable) do - {queryable, dynamic([resources: resources], not is_nil(resources.deleted_at))} - end - def filter_by_type(queryable, {:not_in, types}) do {queryable, dynamic([resources: resources], resources.type not in ^types)} end diff --git a/elixir/apps/domain/lib/domain/tokens.ex b/elixir/apps/domain/lib/domain/tokens.ex index ac8731064..14f8fc989 100644 --- a/elixir/apps/domain/lib/domain/tokens.ex +++ b/elixir/apps/domain/lib/domain/tokens.ex @@ -21,7 +21,7 @@ defmodule Domain.Tokens do end def fetch_token_by_id(id) do - Token.Query.not_deleted() + Token.Query.all() |> Token.Query.not_expired() |> Token.Query.by_id(id) |> Repo.fetch(Token.Query, []) @@ -48,7 +48,7 @@ defmodule Domain.Tokens do end def all_active_browser_session_tokens! do - Token.Query.not_deleted() + Token.Query.all() |> Token.Query.expires_in(15, :minute) |> Token.Query.by_type(:browser) |> Repo.all() @@ -56,7 +56,7 @@ defmodule Domain.Tokens do def list_subject_tokens(%Auth.Subject{} = subject, opts \\ []) do with :ok <- Auth.ensure_has_permissions(subject, Authorizer.manage_own_tokens_permission()) do - Token.Query.not_deleted() + Token.Query.all() |> Token.Query.by_actor_id(subject.actor.id) |> list_tokens(subject, opts) end @@ -64,7 +64,7 @@ defmodule Domain.Tokens do def list_tokens_for(%Actors.Actor{} = actor, %Auth.Subject{} = subject, opts \\ []) do with :ok <- Auth.ensure_has_permissions(subject, Authorizer.manage_tokens_permission()) do - Token.Query.not_deleted() + Token.Query.all() |> Token.Query.by_actor_id(actor.id) |> list_tokens(subject, opts) end @@ -93,7 +93,7 @@ defmodule Domain.Tokens do (hardcoded token duration for Okta and Google Workspace). """ def update_token(%Token{} = token, attrs) do - Token.Query.not_deleted() + Token.Query.all() |> Token.Query.not_expired() |> Token.Query.by_id(token.id) |> Repo.fetch_and_update(Token.Query, with: &Token.Changeset.update(&1, attrs)) @@ -136,7 +136,7 @@ defmodule Domain.Tokens do end defp fetch_token_for_use(id, account_id, context_type) do - Token.Query.not_deleted() + Token.Query.all() |> Token.Query.not_expired() |> Token.Query.by_id(id) |> Token.Query.by_account_id(account_id) @@ -270,7 +270,7 @@ defmodule Domain.Tokens do def delete_all_tokens_by_type_and_assoc(:email, %Auth.Identity{} = identity) do {num_deleted, _} = - Token.Query.not_deleted() + Token.Query.all() |> Token.Query.by_type(:email) |> Token.Query.by_account_id(identity.account_id) |> Token.Query.by_identity_id(identity.id) @@ -288,118 +288,6 @@ defmodule Domain.Tokens do {:ok, num_deleted} end - # TODO: HARD-DELETE - Remove after `deleted_at` is remove from DB - def soft_delete_token(%Token{} = token, %Auth.Subject{} = subject) do - required_permissions = - {:one_of, - [ - Authorizer.manage_tokens_permission(), - Authorizer.manage_own_tokens_permission() - ]} - - with :ok <- Auth.ensure_has_permissions(subject, required_permissions) do - Token.Query.not_deleted() - |> Token.Query.by_id(token.id) - |> Authorizer.for_subject(subject) - |> soft_delete_tokens() - |> case do - {:ok, [token]} -> {:ok, token} - {:ok, []} -> {:error, :not_found} - end - end - end - - # TODO: HARD-DELETE - Remove after `deleted_at` is remove from DB - def soft_delete_token_for(%Auth.Subject{} = subject) do - Token.Query.not_deleted() - |> Token.Query.by_id(subject.token_id) - |> Authorizer.for_subject(subject) - |> soft_delete_tokens() - end - - # TODO: HARD-DELETE - Remove after `deleted_at` is remove from DB - def soft_delete_tokens_for(%Auth.Identity{} = identity) do - Token.Query.not_deleted() - |> Token.Query.by_identity_id(identity.id) - |> soft_delete_tokens() - end - - # TODO: HARD-DELETE - Remove after `deleted_at` is remove from DB - def soft_delete_tokens_for(%Actors.Actor{} = actor, %Auth.Subject{} = subject) do - with :ok <- Auth.ensure_has_permissions(subject, Authorizer.manage_tokens_permission()) do - Token.Query.not_deleted() - |> Token.Query.by_actor_id(actor.id) - |> Authorizer.for_subject(subject) - |> soft_delete_tokens() - end - end - - # TODO: HARD-DELETE - Remove after `deleted_at` is remove from DB - def soft_delete_tokens_for(%Auth.Identity{} = identity, %Auth.Subject{} = subject) do - with :ok <- Auth.ensure_has_permissions(subject, Authorizer.manage_tokens_permission()) do - Token.Query.not_deleted() - |> Token.Query.by_identity_id(identity.id) - |> Authorizer.for_subject(subject) - |> soft_delete_tokens() - end - end - - # TODO: HARD-DELETE - Remove after `deleted_at` is remove from DB - def soft_delete_tokens_for(%Auth.Provider{} = provider, %Auth.Subject{} = subject) do - with :ok <- Auth.ensure_has_permissions(subject, Authorizer.manage_tokens_permission()) do - Token.Query.not_deleted() - |> Token.Query.by_provider_id(provider.id) - |> Authorizer.for_subject(subject) - |> soft_delete_tokens() - end - end - - # TODO: HARD-DELETE - Remove after `deleted_at` is remove from DB - def soft_delete_tokens_for(%Relays.Group{} = group, %Auth.Subject{} = subject) do - with :ok <- Auth.ensure_has_permissions(subject, Authorizer.manage_tokens_permission()) do - Token.Query.not_deleted() - |> Token.Query.by_relay_group_id(group.id) - |> Authorizer.for_subject(subject) - |> soft_delete_tokens() - end - end - - # TODO: HARD-DELETE - Remove after `deleted_at` is remove from DB - def soft_delete_tokens_for(%Gateways.Group{} = group, %Auth.Subject{} = subject) do - with :ok <- Auth.ensure_has_permissions(subject, Authorizer.manage_tokens_permission()) do - Token.Query.not_deleted() - |> Token.Query.by_gateway_group_id(group.id) - |> Authorizer.for_subject(subject) - |> soft_delete_tokens() - end - end - - # TODO: HARD-DELETE - Remove after `deleted_at` is remove from DB - def soft_delete_all_tokens_by_type_and_assoc(:email, %Auth.Identity{} = identity) do - Token.Query.not_deleted() - |> Token.Query.by_type(:email) - |> Token.Query.by_account_id(identity.account_id) - |> Token.Query.by_identity_id(identity.id) - |> soft_delete_tokens() - end - - # TODO: HARD-DELETE - Remove after `deleted_at` is remove from DB - def soft_delete_expired_tokens do - Token.Query.not_deleted() - |> Token.Query.expired() - |> soft_delete_tokens() - end - - # TODO: HARD-DELETE - Remove after `deleted_at` is remove from DB - defp soft_delete_tokens(queryable) do - {_count, tokens} = - queryable - |> Token.Query.delete() - |> Repo.update_all([]) - - {:ok, tokens} - end - defp fetch_config! do Domain.Config.fetch_env!(:domain, __MODULE__) end diff --git a/elixir/apps/domain/lib/domain/tokens/token.ex b/elixir/apps/domain/lib/domain/tokens/token.ex index 36c1bca53..f3f0e8f33 100644 --- a/elixir/apps/domain/lib/domain/tokens/token.ex +++ b/elixir/apps/domain/lib/domain/tokens/token.ex @@ -50,8 +50,6 @@ defmodule Domain.Tokens.Token do field :expires_at, :utc_datetime_usec - # TODO: HARD-DELETE - Remove field after soft deletion is removed - field :deleted_at, :utc_datetime_usec timestamps() end end diff --git a/elixir/apps/domain/lib/domain/tokens/token/changeset.ex b/elixir/apps/domain/lib/domain/tokens/token/changeset.ex index 7a60f7a06..b2a6e8f17 100644 --- a/elixir/apps/domain/lib/domain/tokens/token/changeset.ex +++ b/elixir/apps/domain/lib/domain/tokens/token/changeset.ex @@ -124,11 +124,4 @@ defmodule Domain.Tokens.Token.Changeset do |> put_change(:last_seen_at, DateTime.utc_now()) |> validate_required(~w[last_seen_user_agent last_seen_remote_ip]a) end - - # TODO: HARD-DELETE - Remove after `deleted_at` is removed from DB - def delete(%Token{} = token) do - token - |> change() - |> put_default_value(:deleted_at, DateTime.utc_now()) - end end diff --git a/elixir/apps/domain/lib/domain/tokens/token/query.ex b/elixir/apps/domain/lib/domain/tokens/token/query.ex index 87c0ebeeb..2d4724f3f 100644 --- a/elixir/apps/domain/lib/domain/tokens/token/query.ex +++ b/elixir/apps/domain/lib/domain/tokens/token/query.ex @@ -5,12 +5,6 @@ defmodule Domain.Tokens.Token.Query do from(tokens in Domain.Tokens.Token, as: :tokens) end - # TODO: HARD-DELETE - Remove after `deleted_at` column is removed from DB - def not_deleted do - all() - |> where([tokens: tokens], is_nil(tokens.deleted_at)) - end - def not_expired(queryable) do where( queryable, @@ -79,17 +73,6 @@ defmodule Domain.Tokens.Token.Query do where(queryable, [tokens: tokens], tokens.gateway_group_id == ^gateway_group_id) end - # TODO: HARD-DELETE - Remove after `deleted_at` column is removed from DB - def delete(queryable) do - queryable - |> Ecto.Query.select([tokens: tokens], tokens) - |> Ecto.Query.update([tokens: tokens], - set: [ - deleted_at: fragment("COALESCE(?, timezone('UTC', NOW()))", tokens.deleted_at) - ] - ) - end - def with_joined_account(queryable) do with_named_binding(queryable, :account, fn queryable, binding -> join(queryable, :inner, [tokens: tokens], account in assoc(tokens, ^binding), as: ^binding) diff --git a/elixir/apps/domain/priv/repo/migrations/20251013204955_remove_soft_deleted_data.exs b/elixir/apps/domain/priv/repo/migrations/20251013204955_remove_soft_deleted_data.exs new file mode 100644 index 000000000..0cb9f434c --- /dev/null +++ b/elixir/apps/domain/priv/repo/migrations/20251013204955_remove_soft_deleted_data.exs @@ -0,0 +1,66 @@ +defmodule Domain.Repo.Migrations.RemoveSoftDeletedData do + use Ecto.Migration + + def up do + # Delete all soft-deleted records from tables that have deleted_at column + # This is a data cleanup migration before removing the soft delete functionality + + # The order of execution was chosen to try and minimize ON DELETE CASCADE deletions + + execute(""" + DELETE FROM tokens WHERE deleted_at IS NOT NULL + """) + + execute(""" + DELETE FROM resources WHERE deleted_at IS NOT NULL + """) + + execute(""" + DELETE FROM auth_identities WHERE deleted_at IS NOT NULL + """) + + execute(""" + DELETE FROM clients WHERE deleted_at IS NOT NULL + """) + + execute(""" + DELETE FROM gateways WHERE deleted_at IS NOT NULL + """) + + execute(""" + DELETE FROM actors WHERE deleted_at IS NOT NULL + """) + + execute(""" + DELETE FROM actor_groups WHERE deleted_at IS NOT NULL + """) + + execute(""" + DELETE FROM auth_providers WHERE deleted_at IS NOT NULL + """) + + execute(""" + DELETE FROM gateway_groups WHERE deleted_at IS NOT NULL + """) + + execute(""" + DELETE FROM policies WHERE deleted_at IS NOT NULL + """) + + execute(""" + DELETE FROM relays WHERE deleted_at IS NOT NULL + """) + + execute(""" + DELETE FROM relay_groups WHERE deleted_at IS NOT NULL + """) + + execute(""" + DELETE FROM accounts WHERE deleted_at IS NOT NULL + """) + end + + def down do + # no-op Deleted data cannot be restored + end +end diff --git a/elixir/apps/domain/priv/repo/migrations/20251016183541_add_default_persistent_id.exs b/elixir/apps/domain/priv/repo/migrations/20251016183541_add_default_persistent_id.exs new file mode 100644 index 000000000..958b428ae --- /dev/null +++ b/elixir/apps/domain/priv/repo/migrations/20251016183541_add_default_persistent_id.exs @@ -0,0 +1,31 @@ +defmodule Domain.Repo.Migrations.AddDefaultPersistentId do + use Ecto.Migration + + def up do + # Add default UUID generation for resources.persistent_id + execute(""" + ALTER TABLE resources + ALTER COLUMN persistent_id SET DEFAULT gen_random_uuid() + """) + + # Add default UUID generation for policies.persistent_id + execute(""" + ALTER TABLE policies + ALTER COLUMN persistent_id SET DEFAULT gen_random_uuid() + """) + end + + def down do + # Remove default for resources.persistent_id + execute(""" + ALTER TABLE resources + ALTER COLUMN persistent_id DROP DEFAULT + """) + + # Remove default for policies.persistent_id + execute(""" + ALTER TABLE policies + ALTER COLUMN persistent_id DROP DEFAULT + """) + end +end diff --git a/elixir/apps/domain/priv/repo/migrations/20251016220755_recreate_unique_indexes_without_deleted_at.exs b/elixir/apps/domain/priv/repo/migrations/20251016220755_recreate_unique_indexes_without_deleted_at.exs new file mode 100644 index 000000000..640fcd8a7 --- /dev/null +++ b/elixir/apps/domain/priv/repo/migrations/20251016220755_recreate_unique_indexes_without_deleted_at.exs @@ -0,0 +1,169 @@ +defmodule Domain.Repo.Migrations.RecreateUniqueIndexesWithoutDeletedAt do + use Ecto.Migration + + @disable_ddl_transaction true + + def up do + # Clients + drop_if_exists( + index(:clients, [:account_id, :actor_id, :external_id], + name: :clients_account_id_actor_id_external_id_index, + concurrently: true + ) + ) + + create_if_not_exists( + unique_index(:clients, [:account_id, :actor_id, :external_id], + name: :clients_account_id_actor_id_external_id_index, + concurrently: true + ) + ) + + # Gateways + drop_if_exists( + index(:gateways, [:account_id, :group_id, :external_id], + name: :gateways_account_id_group_id_external_id_index, + concurrently: true + ) + ) + + create_if_not_exists( + unique_index(:gateways, [:account_id, :group_id, :external_id], + name: :gateways_account_id_group_id_external_id_index, + concurrently: true + ) + ) + + # Global Relays (requires raw SQL due to COALESCE) + execute("DROP INDEX CONCURRENTLY IF EXISTS global_relays_unique_address_index") + + execute(""" + CREATE UNIQUE INDEX CONCURRENTLY IF NOT EXISTS global_relays_unique_address_index + ON relays (COALESCE(ipv4, ipv6), port) + WHERE account_id IS NULL + """) + + # Account Relays (requires raw SQL due to COALESCE) + execute("DROP INDEX CONCURRENTLY IF EXISTS relays_unique_address_index") + + execute(""" + CREATE UNIQUE INDEX CONCURRENTLY IF NOT EXISTS relays_unique_address_index + ON relays (account_id, COALESCE(ipv4, ipv6), port) + WHERE account_id IS NOT NULL + """) + + # Auth Identities - provider_identifier unique index + drop_if_exists( + index(:auth_identities, [:account_id, :provider_id, :provider_identifier], + name: :auth_identities_account_id_provider_id_provider_identifier_idx, + concurrently: true + ) + ) + + create_if_not_exists( + unique_index(:auth_identities, [:account_id, :provider_id, :provider_identifier], + name: :auth_identities_account_id_provider_id_provider_identifier_idx, + concurrently: true + ) + ) + + # Auth Identities - email unique index + drop_if_exists( + index(:auth_identities, [:account_id, :provider_id, :email, :provider_identifier], + name: :auth_identities_acct_id_provider_id_email_prov_ident_unique_idx, + concurrently: true + ) + ) + + create_if_not_exists( + unique_index(:auth_identities, [:account_id, :provider_id, :email, :provider_identifier], + name: :auth_identities_acct_id_provider_id_email_prov_ident_unique_idx, + concurrently: true + ) + ) + end + + def down do + # Clients + drop_if_exists( + index(:clients, [:account_id, :actor_id, :external_id], + name: :clients_account_id_actor_id_external_id_index, + concurrently: true + ) + ) + + create_if_not_exists( + unique_index(:clients, [:account_id, :actor_id, :external_id], + name: :clients_account_id_actor_id_external_id_index, + where: "deleted_at IS NULL", + concurrently: true + ) + ) + + # Gateways + drop_if_exists( + index(:gateways, [:account_id, :group_id, :external_id], + name: :gateways_account_id_group_id_external_id_index, + concurrently: true + ) + ) + + create_if_not_exists( + unique_index(:gateways, [:account_id, :group_id, :external_id], + name: :gateways_account_id_group_id_external_id_index, + where: "deleted_at IS NULL", + concurrently: true + ) + ) + + # Global Relays (requires raw SQL due to COALESCE) + execute("DROP INDEX IF EXISTS global_relays_unique_address_index") + + execute(""" + CREATE UNIQUE INDEX IF NOT EXISTS global_relays_unique_address_index + ON relays (COALESCE(ipv4, ipv6), port) + WHERE deleted_at IS NULL AND account_id IS NULL + """) + + # Account Relays (requires raw SQL due to COALESCE) + execute("DROP INDEX IF EXISTS relays_unique_address_index") + + execute(""" + CREATE UNIQUE INDEX IF NOT EXISTS relays_unique_address_index + ON relays (account_id, COALESCE(ipv4, ipv6), port) + WHERE deleted_at IS NULL AND account_id IS NOT NULL + """) + + # Auth Identities - provider_identifier unique index + drop_if_exists( + index(:auth_identities, [:account_id, :provider_id, :provider_identifier], + name: :auth_identities_account_id_provider_id_provider_identifier_idx, + concurrently: true + ) + ) + + create_if_not_exists( + unique_index(:auth_identities, [:account_id, :provider_id, :provider_identifier], + name: :auth_identities_account_id_provider_id_provider_identifier_idx, + where: "deleted_at IS NULL", + concurrently: true + ) + ) + + # Auth Identities - email unique index + drop_if_exists( + index(:auth_identities, [:account_id, :provider_id, :email, :provider_identifier], + name: :auth_identities_acct_id_provider_id_email_prov_ident_unique_idx, + concurrently: true + ) + ) + + create_if_not_exists( + unique_index(:auth_identities, [:account_id, :provider_id, :email, :provider_identifier], + name: :auth_identities_acct_id_provider_id_email_prov_ident_unique_idx, + where: "deleted_at IS NULL", + concurrently: true + ) + ) + end +end diff --git a/elixir/apps/domain/test/domain/accounts_test.exs b/elixir/apps/domain/test/domain/accounts_test.exs index 96f42a43c..e7f660092 100644 --- a/elixir/apps/domain/test/domain/accounts_test.exs +++ b/elixir/apps/domain/test/domain/accounts_test.exs @@ -35,7 +35,7 @@ defmodule Domain.AccountsTest do end test "does not return deleted accounts" do - account = Fixtures.Accounts.create_account() |> Fixtures.Accounts.delete_account() + {:ok, account} = Fixtures.Accounts.create_account() |> Fixtures.Accounts.delete_account() accounts = all_accounts_by_ids!([account.id]) assert length(accounts) == 0 end @@ -783,11 +783,6 @@ defmodule Domain.AccountsTest do assert account_active?(account) == true end - test "returns false when account is deleted" do - account = Fixtures.Accounts.create_account() |> Fixtures.Accounts.delete_account() - assert account_active?(account) == false - end - test "returns false when account is disabled" do account = Fixtures.Accounts.create_account() |> Fixtures.Accounts.disable_account() assert account_active?(account) == false diff --git a/elixir/apps/domain/test/domain/actors_test.exs b/elixir/apps/domain/test/domain/actors_test.exs index 35bdf1364..776f6f048 100644 --- a/elixir/apps/domain/test/domain/actors_test.exs +++ b/elixir/apps/domain/test/domain/actors_test.exs @@ -84,19 +84,6 @@ defmodule Domain.ActorsTest do assert fetch_group_by_id(group.id, subject) == {:error, :not_found} end - # TODO: HARD-DELETE - This test is no longer relevant - # test "returns deleted groups", %{ - # account: account, - # subject: subject - # } do - # group = - # Fixtures.Actors.create_group(account: account) - # |> Fixtures.Actors.delete_group() - - # 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 group = Fixtures.Actors.create_group(account: account) assert {:ok, fetched_group} = fetch_group_by_id(group.id, subject) @@ -156,17 +143,6 @@ defmodule Domain.ActorsTest do assert {:ok, [], _metadata} = list_groups(subject) end - # TODO: HARD-DELETE - Is this test needed any more? - test "does not list deleted groups", %{ - account: account, - subject: subject - } do - Fixtures.Actors.create_group(account: account) - |> Fixtures.Actors.delete_group() - - assert {:ok, [], _metadata} = list_groups(subject) - end - test "returns all groups", %{ account: account, subject: subject @@ -218,17 +194,6 @@ defmodule Domain.ActorsTest do assert {:ok, [], _metadata} = list_editable_groups(subject) end - # TODO: HARD-DELETE - Is this test needed any more? - test "does not list deleted groups", %{ - account: account, - subject: subject - } do - Fixtures.Actors.create_group(account: account) - |> Fixtures.Actors.delete_group() - - assert {:ok, [], _metadata} = list_editable_groups(subject) - end - test "returns all editable groups", %{ account: account, subject: subject @@ -291,16 +256,6 @@ defmodule Domain.ActorsTest do assert {:ok, [], _metadata} = list_groups_for(actor, subject) end - # TODO: HARD-DELETE - Is this test needed any more? - test "does not list deleted groups", %{account: account, actor: actor, subject: subject} do - group = Fixtures.Actors.create_group(account: account) - Fixtures.Actors.create_membership(account: account, actor: actor, group: group) - - Fixtures.Actors.delete_group(group) - - assert {:ok, [], _metadata} = list_groups_for(actor, subject) - end - test "returns all groups for actor", %{ account: account, actor: actor, @@ -894,7 +849,7 @@ defmodule Domain.ActorsTest do sync_provider_groups(provider, attrs_list) assert Repo.aggregate(Actors.Group, :count) == 5 - assert Repo.aggregate(Actors.Group.Query.not_deleted(), :count) == 5 + assert Repo.aggregate(Actors.Group.Query.all(), :count) == 5 end test "ignores groups that are not synced from the provider", %{ @@ -927,53 +882,6 @@ defmodule Domain.ActorsTest do group_ids_by_provider_identifier: %{} }} end - - # TODO: HARD-DELETE - This test is no longer relevant - - # test "ignores synced groups that are soft deleted", %{ - # account: account, - # provider: provider - # } do - # deleted_group = - # Fixtures.Actors.create_group( - # account: account, - # provider: provider, - # provider_identifier: "G:GROUP_ID1", - # name: "ALREADY_DELETED" - # ) - - # Domain.Actors.Group.Query.not_deleted() - # |> Domain.Actors.Group.Query.by_account_id(account.id) - # |> Domain.Actors.Group.Query.by_provider_id(provider.id) - # |> Domain.Actors.Group.Query.by_provider_identifier( - # {:in, [deleted_group.provider_identifier]} - # ) - # |> Domain.Actors.delete_groups() - - # group2 = - # Fixtures.Actors.create_group( - # account: account, - # provider: provider, - # provider_identifier: "G:GROUP_ID2", - # name: "TO_BE_UPDATED" - # ) - - # attrs_list = [ - # %{"name" => "Group:Infrastructure", "provider_identifier" => "G:GROUP_ID2"}, - # %{"name" => "Group:Security", "provider_identifier" => "G:GROUP_ID3"}, - # %{"name" => "Group:Finance", "provider_identifier" => "G:GROUP_ID4"} - # ] - - # provider_identifiers = Enum.map(attrs_list, & &1["provider_identifier"]) - - # assert {:ok, sync_data} = sync_provider_groups(provider, attrs_list) - - # assert Enum.sort(Enum.map(sync_data.groups, & &1.name)) == - # Enum.sort([deleted_group.name, group2.name]) - - # assert sync_data.deleted == [] - # assert sync_data.plan == {provider_identifiers, []} - # end end describe "sync_provider_memberships/2" do @@ -1780,7 +1688,9 @@ defmodule Domain.ActorsTest do assert membership.actor_id == actor.id end - # TODO: HARD-DELETE - Is this test needed any more? + # This test isn't strictly necessary when using ON DELETE CASCADE, however + # leaving this test allows us to know if there is ever a change in the + # foreign key effects test "removes memberships when managed group is deleted", %{ account: account, actor: actor, @@ -1999,7 +1909,8 @@ defmodule Domain.ActorsTest do assert Repo.aggregate(Actors.Membership, :count) == 0 end - # TODO: HARD-DELETE - Should this test be put in policies? + # Leaving this test here for now. May want to consider moving this test + # to the policy tests rather than the actor group tests. test "cascade deletes policies that use this group", %{ account: account, subject: subject @@ -2053,22 +1964,6 @@ defmodule Domain.ActorsTest do subject: subject } end - - # TODO: HARD-DELETE - Is this test needed any more? - test "delete groups when provider is deleted", %{ - account: account, - provider: provider, - subject: subject - } do - group1 = Fixtures.Actors.create_group(account: account, provider: provider) - group2 = Fixtures.Actors.create_group(account: account, provider: provider) - - assert {:ok, _provider} = Auth.delete_provider(provider, subject) - - refute Repo.get(Domain.Auth.Provider, provider.id) - refute Repo.get(Actors.Group, group1.id) - refute Repo.get(Actors.Group, group2.id) - end end describe "group_synced?/1" do @@ -2118,23 +2013,6 @@ defmodule Domain.ActorsTest do end end - # TODO: HARD-DELETE - Remove after soft delete functionality is gone - describe "group_soft_deleted?/1" do - test "returns true for soft deleted groups" do - account = Fixtures.Accounts.create_account() - - group = - Fixtures.Actors.create_group(account: account) |> Fixtures.Actors.soft_delete_group() - - assert group_soft_deleted?(group) == true - end - - test "returns false for manually created groups" do - group = Fixtures.Actors.create_group() - assert group_soft_deleted?(group) == false - end - end - describe "count_users_for_account/1" do test "returns 0 when actors are in another account", %{} do account = Fixtures.Accounts.create_account() @@ -2237,77 +2115,6 @@ defmodule Domain.ActorsTest do end end - describe "count_synced_actors_for_provider/1" do - test "returns 0 when there are no actors" do - account = Fixtures.Accounts.create_account() - provider = Fixtures.Auth.create_userpass_provider(account: account) - assert count_synced_actors_for_provider(provider) == 0 - end - - test "returns 0 when there are no synced actors" do - account = Fixtures.Accounts.create_account() - provider = Fixtures.Auth.create_userpass_provider(account: account) - Fixtures.Actors.create_actor(type: :account_admin_user, account: account) - assert count_synced_actors_for_provider(provider) == 0 - end - - test "returns count of synced actors owned only by the given provider" do - account = Fixtures.Accounts.create_account() - - {provider, _bypass} = - Fixtures.Auth.start_and_create_openid_connect_provider(account: account) - - actor1 = - Fixtures.Actors.create_actor( - type: :account_admin_user, - account: account - ) - - Fixtures.Auth.create_identity(account: account, actor: actor1, provider: provider) - |> Fixtures.Auth.delete_identity() - - actor2 = - Fixtures.Actors.create_actor( - type: :account_admin_user, - account: account - ) - - Fixtures.Auth.create_identity(account: account, actor: actor2, provider: provider) - |> Fixtures.Auth.delete_identity() - - actor3 = - Fixtures.Actors.create_actor( - type: :account_admin_user, - account: account - ) - - Fixtures.Auth.create_identity(account: account, actor: actor3) - |> Fixtures.Auth.delete_identity() - - actor4 = - Fixtures.Actors.create_actor( - type: :account_admin_user, - account: account - ) - - Fixtures.Auth.create_identity(account: account, actor: actor4, provider: provider) - |> Fixtures.Auth.delete_identity() - - Fixtures.Auth.create_identity(account: account, actor: actor4) - |> Fixtures.Auth.delete_identity() - - actor5 = - Fixtures.Actors.create_actor( - type: :account_admin_user, - account: account - ) - - Fixtures.Auth.create_identity(account: account, actor: actor5, provider: provider) - - assert count_synced_actors_for_provider(provider) == 2 - end - end - describe "fetch_actor_by_id/3" do test "returns error when actor is not found" do subject = Fixtures.Auth.create_subject() @@ -2538,7 +2345,6 @@ defmodule Domain.ActorsTest do assert actor.name == attrs.name assert actor.type == attrs.type assert is_nil(actor.disabled_at) - assert is_nil(actor.deleted_at) end test "trims whitespace when creating an actor", %{ @@ -2551,7 +2357,6 @@ defmodule Domain.ActorsTest do assert actor.name == actor_name assert is_nil(actor.disabled_at) - assert is_nil(actor.deleted_at) end end @@ -2579,7 +2384,6 @@ defmodule Domain.ActorsTest do assert actor.name == attrs.name assert actor.type == attrs.type assert is_nil(actor.disabled_at) - assert is_nil(actor.deleted_at) end test "trims whitespace when creating an actor", %{ @@ -2593,7 +2397,6 @@ defmodule Domain.ActorsTest do assert actor.name == actor_name assert is_nil(actor.disabled_at) - assert is_nil(actor.deleted_at) end test "returns error when seats limit is exceeded (admins)", %{ @@ -3075,7 +2878,6 @@ defmodule Domain.ActorsTest do assert membership.actor_id == new_actor.id end - # TODO: HARD-DELETE - Move this test to Tokens since it has the FK constraint test "deletes token", %{ account: account, actor: actor, @@ -3087,7 +2889,6 @@ defmodule Domain.ActorsTest do refute Repo.get(Domain.Tokens.Token, subject.token_id) end - # TODO: HARD-DELETE - Move this test to AuthIdentities since it has the FK constraint test "deletes actor identities", %{ account: account, subject: subject @@ -3099,7 +2900,6 @@ defmodule Domain.ActorsTest do refute Repo.get(Domain.Auth.Identity, identity.id) end - # TODO: HARD-DELETE - Move this test to Clients since it has the FK constraint test "deletes actor clients", %{ account: account, subject: subject @@ -3109,7 +2909,7 @@ defmodule Domain.ActorsTest do assert {:ok, _actor} = delete_actor(actor_to_delete, subject) - assert Repo.aggregate(Domain.Clients.Client.Query.not_deleted(), :count) == 0 + assert Repo.aggregate(Domain.Clients.Client.Query.all(), :count) == 0 end test "deletes actor memberships", %{ @@ -3168,68 +2968,6 @@ defmodule Domain.ActorsTest do refute Repo.get(Domain.Actors.Actor, service_account_actor.id) end - # TODO: HARD-DELETE - Need to figure out if we care about this case - # test "returns error when trying to delete the last admin actor using a race condition" do - # for _ <- 0..50 do - # test_pid = self() - - # Task.async(fn -> - # allow_child_sandbox_access(test_pid) - - # Domain.Config.put_env_override(:outbound_email_adapter_configured?, true) - - # account = Fixtures.Accounts.create_account() - # provider = Fixtures.Auth.create_email_provider(account: account) - - # actor_one = - # Fixtures.Actors.create_actor( - # type: :account_admin_user, - # account: account, - # provider: provider - # ) - - # actor_two = - # Fixtures.Actors.create_actor( - # type: :account_admin_user, - # account: account, - # provider: provider - # ) - - # identity_one = - # Fixtures.Auth.create_identity( - # account: account, - # actor: actor_one, - # provider: provider - # ) - - # identity_two = - # Fixtures.Auth.create_identity( - # account: account, - # actor: actor_two, - # provider: provider - # ) - - # subject_one = Fixtures.Auth.create_subject(identity: identity_one) - # subject_two = Fixtures.Auth.create_subject(identity: identity_two) - - # for {actor, subject} <- [{actor_two, subject_one}, {actor_one, subject_two}] do - # Task.async(fn -> - # allow_child_sandbox_access(test_pid) - # delete_actor(actor, subject) - # end) - # end - # |> Task.await_many() - - # queryable = - # Actors.Actor.Query.not_deleted() - # |> Actors.Actor.Query.by_account_id(account.id) - - # assert Repo.aggregate(queryable, :count) == 1 - # end) - # end - # |> Task.await_many() - # end - test "does not allow to delete an actor twice", %{ account: account, subject: subject @@ -3271,78 +3009,6 @@ defmodule Domain.ActorsTest do end end - describe "delete_stale_synced_actors_for_provider/2" do - test "deletes actors synced with only the given provider" do - account = Fixtures.Accounts.create_account() - subject = Fixtures.Auth.create_subject(account: account) - - {provider, _bypass} = - Fixtures.Auth.start_and_create_openid_connect_provider(account: account) - - actor1 = - Fixtures.Actors.create_actor( - type: :account_admin_user, - account: account - ) - - Fixtures.Auth.create_identity(account: account, actor: actor1, provider: provider) - |> Fixtures.Auth.delete_identity() - - actor2 = - Fixtures.Actors.create_actor( - type: :account_admin_user, - account: account - ) - - Fixtures.Auth.create_identity(account: account, actor: actor2, provider: provider) - |> Fixtures.Auth.delete_identity() - - actor3 = - Fixtures.Actors.create_actor( - type: :account_admin_user, - account: account - ) - - Fixtures.Auth.create_identity(account: account, actor: actor3) - |> Fixtures.Auth.delete_identity() - - actor4 = - Fixtures.Actors.create_actor( - type: :account_admin_user, - account: account - ) - - Fixtures.Auth.create_identity(account: account, actor: actor4, provider: provider) - |> Fixtures.Auth.delete_identity() - - Fixtures.Auth.create_identity(account: account, actor: actor4) - |> Fixtures.Auth.delete_identity() - - assert delete_stale_synced_actors_for_provider(provider, subject) == :ok - not_deleted_actors = Repo.all(Actors.Actor.Query.not_deleted()) - not_deleted_actor_ids = not_deleted_actors |> Enum.map(& &1.id) |> Enum.sort() - - assert not_deleted_actor_ids == Enum.sort([actor4.id, actor3.id, subject.actor.id]) - end - - test "returns error when subject cannot delete actors" do - account = Fixtures.Accounts.create_account() - - {provider, _bypass} = - Fixtures.Auth.start_and_create_openid_connect_provider(account: account) - - subject = - Fixtures.Auth.create_subject(account: account) - |> Fixtures.Auth.remove_permissions() - - assert delete_stale_synced_actors_for_provider(provider, subject) == - {:error, - {:unauthorized, - reason: :missing_permissions, - missing_permissions: [Actors.Authorizer.manage_actors_permission()]}} - end - end - describe "actor_synced?/1" do test "returns true when actor is synced" do actor = Fixtures.Actors.create_actor() @@ -3359,23 +3025,6 @@ defmodule Domain.ActorsTest do end end - # TODO: HARD-DELETE - Remove after soft deletion functionality is removed - describe "actor_deleted?/1" do - test "returns true when actor is soft deleted" do - actor = - Fixtures.Actors.create_actor() - |> Fixtures.Actors.soft_delete() - - assert actor_deleted?(actor) == true - end - - test "returns false when actor is not deleted" do - actor = Fixtures.Actors.create_actor() - - assert actor_deleted?(actor) == false - end - end - describe "actor_disabled?/1" do test "returns true when actor is disabled" do actor = @@ -3662,12 +3311,4 @@ defmodule Domain.ActorsTest do {:ok, %{deleted_memberships: 0}} end end - - # TODO: HARD-DELETE - This may not be needed anymore - # defp allow_child_sandbox_access(parent_pid) do - # Ecto.Adapters.SQL.Sandbox.allow(Repo, parent_pid, self()) - # # Allow is async call we need to break current process execution - # # to allow sandbox to be enabled - # :timer.sleep(10) - # end end diff --git a/elixir/apps/domain/test/domain/auth/adapters/google_workspace/jobs/sync_directory_test.exs b/elixir/apps/domain/test/domain/auth/adapters/google_workspace/jobs/sync_directory_test.exs index 5baaf59a6..c0a452788 100644 --- a/elixir/apps/domain/test/domain/auth/adapters/google_workspace/jobs/sync_directory_test.exs +++ b/elixir/apps/domain/test/domain/auth/adapters/google_workspace/jobs/sync_directory_test.exs @@ -680,167 +680,6 @@ defmodule Domain.Auth.Adapters.GoogleWorkspace.Jobs.SyncDirectoryTest do refute Repo.reload(deleted_identity_token) end - test "resurrects deleted identities that reappear on the next sync", %{ - account: account, - provider: provider - } do - actor = Fixtures.Actors.create_actor(account: account) - provider_identifier = "USER_ID1" - - identity = - Fixtures.Auth.create_identity( - account: account, - provider: provider, - actor: actor, - provider_identifier: provider_identifier - ) - - inserted_at = identity.inserted_at - id = identity.id - - # Soft delete the identity - Repo.update_all(Domain.Auth.Identity, set: [deleted_at: DateTime.utc_now()]) - - assert Domain.Auth.all_identities_for(actor) == [] - - # Simulate a sync - bypass = Bypass.open() - - users = [ - %{ - "agreedToTerms" => true, - "archived" => false, - "creationTime" => "2023-06-10T17:32:06.000Z", - "id" => "USER_ID1", - "kind" => "admin#directory#user", - "lastLoginTime" => "2023-06-26T13:53:30.000Z", - "name" => %{ - "familyName" => "Manifold", - "fullName" => "Brian Manifold", - "givenName" => "Brian" - }, - "orgUnitPath" => "/Engineering", - "organizations" => [], - "phones" => [], - "primaryEmail" => "b@firez.xxx" - } - ] - - GoogleWorkspaceDirectory.override_endpoint_url("http://localhost:#{bypass.port}/") - - GoogleWorkspaceDirectory.mock_groups_list_endpoint( - bypass, - 200, - JSON.encode!(%{"groups" => []}) - ) - - GoogleWorkspaceDirectory.mock_organization_units_list_endpoint( - bypass, - 200, - JSON.encode!(%{"organizationUnits" => []}) - ) - - GoogleWorkspaceDirectory.mock_users_list_endpoint( - bypass, - 200, - JSON.encode!(%{"users" => users}) - ) - - GoogleWorkspaceDirectory.mock_token_endpoint(bypass) - - {:ok, pid} = Task.Supervisor.start_link() - assert execute(%{task_supervisor: pid}) == :ok - - # Assert that the identity has been resurrected - assert resurrected_identity = Repo.get(Domain.Auth.Identity, id) - assert resurrected_identity.inserted_at == inserted_at - assert resurrected_identity.id == id - assert resurrected_identity.deleted_at == nil - assert Domain.Auth.all_identities_for(actor) == [resurrected_identity] - end - - test "resurrects deleted groups that reappear on the next sync", %{ - account: account, - provider: provider - } do - actor_group = - Fixtures.Actors.create_group( - account: account, - provider: provider, - provider_identifier: "G:GROUP_ID1" - ) - - inserted_at = actor_group.inserted_at - id = actor_group.id - - # Soft delete the group - Repo.update_all(Domain.Actors.Group, set: [deleted_at: DateTime.utc_now()]) - - # Assert that the group and associated policy has been soft-deleted - assert Domain.Actors.Group.Query.not_deleted() |> Repo.all() == [] - - # Simulate a sync - bypass = Bypass.open() - - groups = [ - %{ - "kind" => "admin#directory#group", - "id" => "GROUP_ID1", - "etag" => "\"ET\"", - "email" => "i@fiez.xxx", - "name" => "Infrastructure", - "directMembersCount" => "5", - "description" => "Group to handle infrastructure alerts and management", - "adminCreated" => true, - "aliases" => [ - "pnr@firez.one" - ], - "nonEditableAliases" => [ - "i@ext.fiez.xxx" - ] - } - ] - - GoogleWorkspaceDirectory.override_endpoint_url("http://localhost:#{bypass.port}/") - - GoogleWorkspaceDirectory.mock_groups_list_endpoint( - bypass, - 200, - JSON.encode!(%{"groups" => groups}) - ) - - GoogleWorkspaceDirectory.mock_organization_units_list_endpoint( - bypass, - 200, - JSON.encode!(%{"organizationUnits" => []}) - ) - - GoogleWorkspaceDirectory.mock_users_list_endpoint( - bypass, - 200, - JSON.encode!(%{"users" => []}) - ) - - GoogleWorkspaceDirectory.mock_group_members_list_endpoint( - bypass, - "GROUP_ID1", - 200, - JSON.encode!(%{"members" => []}) - ) - - GoogleWorkspaceDirectory.mock_token_endpoint(bypass) - - {:ok, pid} = Task.Supervisor.start_link() - assert execute(%{task_supervisor: pid}) == :ok - - # Assert that the group has been resurrected - assert resurrected_group = Repo.get(Domain.Actors.Group, id) - assert resurrected_group.inserted_at == inserted_at - assert resurrected_group.id == id - assert resurrected_group.deleted_at == nil - assert Domain.Actors.Group.Query.not_deleted() |> Repo.all() == [resurrected_group] - end - test "persists the sync error on the provider", %{provider: provider} do error_message = "Admin SDK API has not been used in project XXXX before or it is disabled. " <> diff --git a/elixir/apps/domain/test/domain/auth/adapters/jumpcloud/jobs/sync_directory_test.exs b/elixir/apps/domain/test/domain/auth/adapters/jumpcloud/jobs/sync_directory_test.exs index 9cf1a9fa2..388627929 100644 --- a/elixir/apps/domain/test/domain/auth/adapters/jumpcloud/jobs/sync_directory_test.exs +++ b/elixir/apps/domain/test/domain/auth/adapters/jumpcloud/jobs/sync_directory_test.exs @@ -443,128 +443,6 @@ defmodule Domain.Auth.Adapters.JumpCloud.Jobs.SyncDirectoryTest do refute Repo.reload(deleted_identity_token) end - test "resurrects deleted identities that reappear on the next sync", %{ - bypass: bypass, - account: account, - provider: provider - } do - actor = Fixtures.Actors.create_actor(account: account) - provider_identifier = "USER_JDOE_ID" - - identity = - Fixtures.Auth.create_identity( - account: account, - provider: provider, - actor: actor, - provider_identifier: provider_identifier - ) - - inserted_at = identity.inserted_at - id = identity.id - - # Soft delete the identity - Repo.update_all(Domain.Auth.Identity, set: [deleted_at: DateTime.utc_now()]) - - assert Domain.Auth.all_identities_for(actor) == [] - - # Simulate a sync - - users = [ - %{ - "id" => "workos_user_jdoe_id", - "object" => "directory_user", - "custom_attributes" => %{}, - "directory_id" => "dir_123", - "organization_id" => "org_123", - "emails" => [ - %{ - "primary" => true, - "type" => "type", - "value" => "jdoe@example.local" - } - ], - "groups" => [], - "idp_id" => "USER_JDOE_ID", - "first_name" => "John", - "last_name" => "Doe", - "job_title" => "Software Eng", - "raw_attributes" => %{}, - "state" => "active", - "username" => "jdoe@example.local", - "created_at" => "2023-07-17T20:07:20.055Z", - "updated_at" => "2023-07-17T20:07:20.055Z" - } - ] - - WorkOSDirectory.override_base_url("http://localhost:#{bypass.port}/") - WorkOSDirectory.mock_list_directories_endpoint(bypass) - WorkOSDirectory.mock_list_groups_endpoint(bypass, []) - WorkOSDirectory.mock_list_users_endpoint(bypass, users) - - {:ok, pid} = Task.Supervisor.start_link() - assert execute(%{task_supervisor: pid}) == :ok - - # Assert that the identity has been resurrected - assert resurrected_identity = Repo.get(Domain.Auth.Identity, id) - assert resurrected_identity.inserted_at == inserted_at - assert resurrected_identity.id == id - assert resurrected_identity.deleted_at == nil - assert Domain.Auth.all_identities_for(actor) == [resurrected_identity] - end - - test "resurrects deleted groups that reappear on the next sync", %{ - bypass: bypass, - account: account, - provider: provider - } do - actor_group = - Fixtures.Actors.create_group( - account: account, - provider: provider, - provider_identifier: "G:GROUP_ENGINEERING_ID" - ) - - inserted_at = actor_group.inserted_at - id = actor_group.id - - # Soft delete the group - Repo.update_all(Domain.Actors.Group, set: [deleted_at: DateTime.utc_now()]) - - # Assert that the group and associated policy has been soft-deleted - assert Domain.Actors.Group.Query.not_deleted() |> Repo.all() == [] - - # Simulate a sync - - groups = [ - %{ - "id" => "GROUP_ENGINEERING_ID", - "object" => "directory_group", - "idp_id" => "engineering", - "directory_id" => "dir_123", - "organization_id" => "org_123", - "name" => "Engineering", - "created_at" => "2021-10-27 15:21:50.640958", - "updated_at" => "2021-12-13 12:15:45.531847", - "raw_attributes" => %{} - } - ] - - WorkOSDirectory.override_base_url("http://localhost:#{bypass.port}/") - WorkOSDirectory.mock_list_directories_endpoint(bypass) - WorkOSDirectory.mock_list_groups_endpoint(bypass, groups) - WorkOSDirectory.mock_list_users_endpoint(bypass, []) - - {:ok, pid} = Task.Supervisor.start_link() - assert execute(%{task_supervisor: pid}) == :ok - - # Assert that the group has been resurrected - assert resurrected_group = Repo.get(Domain.Actors.Group, id) - assert resurrected_group.inserted_at == inserted_at - assert resurrected_group.id == id - assert resurrected_group.deleted_at == nil - assert Domain.Actors.Group.Query.not_deleted() |> Repo.all() == [resurrected_group] - end - test "stops the sync retires on 401 error from WorkOS", %{provider: provider} do bypass = Bypass.open() WorkOSDirectory.override_base_url("http://localhost:#{bypass.port}") diff --git a/elixir/apps/domain/test/domain/auth/adapters/microsoft_entra/jobs/sync_directory_test.exs b/elixir/apps/domain/test/domain/auth/adapters/microsoft_entra/jobs/sync_directory_test.exs index a2b802789..8edf8e13e 100644 --- a/elixir/apps/domain/test/domain/auth/adapters/microsoft_entra/jobs/sync_directory_test.exs +++ b/elixir/apps/domain/test/domain/auth/adapters/microsoft_entra/jobs/sync_directory_test.exs @@ -141,128 +141,6 @@ defmodule Domain.Auth.Adapters.MicrosoftEntra.Jobs.SyncDirectoryTest do assert updated_provider.last_synced_at != provider.last_synced_at end - test "resurrects deleted identities that reappear on the next sync", %{ - account: account, - provider: provider - } do - actor = Fixtures.Actors.create_actor(account: account) - provider_identifier = "USER_JDOE_ID" - - identity = - Fixtures.Auth.create_identity( - account: account, - provider: provider, - actor: actor, - provider_identifier: provider_identifier - ) - - inserted_at = identity.inserted_at - id = identity.id - - # Soft delete the identity - Repo.update_all(Domain.Auth.Identity, set: [deleted_at: DateTime.utc_now()]) - - assert Domain.Auth.all_identities_for(actor) == [] - - # Simulate a sync - bypass = Bypass.open() - - users = [ - %{ - "id" => "USER_JDOE_ID", - "displayName" => "John Doe", - "givenName" => "John", - "surname" => "Doe", - "userPrincipalName" => "jdoe@example.local", - "mail" => "jdoe@example.local", - "accountEnabled" => true - } - ] - - MicrosoftEntraDirectory.override_endpoint_url("http://localhost:#{bypass.port}/") - - MicrosoftEntraDirectory.mock_groups_list_endpoint( - bypass, - 200, - JSON.encode!(%{"value" => []}) - ) - - MicrosoftEntraDirectory.mock_users_list_endpoint( - bypass, - 200, - JSON.encode!(%{"value" => users}) - ) - - {:ok, pid} = Task.Supervisor.start_link() - assert execute(%{task_supervisor: pid}) == :ok - - # Assert that the identity has been resurrected - assert resurrected_identity = Repo.get(Domain.Auth.Identity, id) - assert resurrected_identity.inserted_at == inserted_at - assert resurrected_identity.id == id - assert resurrected_identity.deleted_at == nil - assert Domain.Auth.all_identities_for(actor) == [resurrected_identity] - end - - test "resurrects deleted groups that reappear on the next sync", %{ - account: account, - provider: provider - } do - actor_group = - Fixtures.Actors.create_group( - account: account, - provider: provider, - provider_identifier: "G:GROUP_ALL_ID" - ) - - inserted_at = actor_group.inserted_at - id = actor_group.id - - # Soft delete the group - Repo.update_all(Domain.Actors.Group, set: [deleted_at: DateTime.utc_now()]) - - # Assert that the group and associated policy has been soft-deleted - assert Domain.Actors.Group.Query.not_deleted() |> Repo.all() == [] - - # Simulate a sync - bypass = Bypass.open() - - groups = [ - %{"id" => "GROUP_ALL_ID", "displayName" => "All"} - ] - - MicrosoftEntraDirectory.override_endpoint_url("http://localhost:#{bypass.port}/") - - MicrosoftEntraDirectory.mock_groups_list_endpoint( - bypass, - 200, - JSON.encode!(%{"value" => groups}) - ) - - MicrosoftEntraDirectory.mock_group_members_list_endpoint( - bypass, - "GROUP_ALL_ID", - 200, - JSON.encode!(%{"value" => []}) - ) - - MicrosoftEntraDirectory.mock_users_list_endpoint( - bypass, - 200, - JSON.encode!(%{"value" => []}) - ) - - {:ok, pid} = Task.Supervisor.start_link() - assert execute(%{task_supervisor: pid}) == :ok - - # Assert that the group has been resurrected - assert resurrected_group = Repo.get(Domain.Actors.Group, id) - assert resurrected_group.inserted_at == inserted_at - assert resurrected_group.id == id - assert resurrected_group.deleted_at == nil - assert Domain.Actors.Group.Query.not_deleted() |> Repo.all() == [resurrected_group] - end - test "does not crash on endpoint errors" do bypass = Bypass.open() Bypass.down(bypass) diff --git a/elixir/apps/domain/test/domain/auth/adapters/okta/jobs/sync_directory_test.exs b/elixir/apps/domain/test/domain/auth/adapters/okta/jobs/sync_directory_test.exs index 88758c185..a497e8129 100644 --- a/elixir/apps/domain/test/domain/auth/adapters/okta/jobs/sync_directory_test.exs +++ b/elixir/apps/domain/test/domain/auth/adapters/okta/jobs/sync_directory_test.exs @@ -745,154 +745,6 @@ defmodule Domain.Auth.Adapters.Okta.Jobs.SyncDirectoryTest do refute Repo.reload(deleted_identity_token) end - test "resurrects deleted identities that reappear on the next sync", %{ - bypass: bypass, - account: account, - provider: provider - } do - actor = Fixtures.Actors.create_actor(account: account) - provider_identifier = "USER_JDOE_ID" - - identity = - Fixtures.Auth.create_identity( - account: account, - provider: provider, - actor: actor, - provider_identifier: provider_identifier - ) - - inserted_at = identity.inserted_at - id = identity.id - - # Soft delete the identity - Repo.update_all(Domain.Auth.Identity, set: [deleted_at: DateTime.utc_now()]) - - assert Domain.Auth.all_identities_for(actor) == [] - - # Simulate a sync - - users = [ - %{ - "id" => "USER_JDOE_ID", - "status" => "ACTIVE", - "created" => "2023-12-21T18:30:05.000Z", - "activated" => nil, - "statusChanged" => "2023-12-21T20:04:06.000Z", - "lastLogin" => "2024-02-08T05:14:25.000Z", - "lastUpdated" => "2023-12-21T20:04:06.000Z", - "passwordChanged" => "2023-12-21T20:04:06.000Z", - "type" => %{"id" => "otye1rmouoEfu7KCV5d7"}, - "profile" => %{ - "firstName" => "John", - "lastName" => "Doe", - "mobilePhone" => nil, - "secondEmail" => nil, - "login" => "jdoe@example.com", - "email" => "jdoe@example.com" - }, - "_links" => %{ - "self" => %{ - "href" => "http://localhost:#{bypass.port}/api/v1/users/OT6AZkcmzkDXwkXcjTHY" - } - } - } - ] - - OktaDirectory.mock_groups_list_endpoint(bypass, 200, JSON.encode!([])) - OktaDirectory.mock_users_list_endpoint(bypass, 200, JSON.encode!(users)) - - {:ok, pid} = Task.Supervisor.start_link() - assert execute(%{task_supervisor: pid}) == :ok - - # Assert that the identity has been resurrected - assert resurrected_identity = Repo.get(Domain.Auth.Identity, id) - assert resurrected_identity.inserted_at == inserted_at - assert resurrected_identity.id == id - assert resurrected_identity.deleted_at == nil - assert Domain.Auth.all_identities_for(actor) == [resurrected_identity] - end - - test "resurrects deleted groups that reappear on the next sync", %{ - bypass: bypass, - account: account, - provider: provider - } do - actor_group = - Fixtures.Actors.create_group( - account: account, - provider: provider, - provider_identifier: "G:GROUP_DEVOPS_ID" - ) - - inserted_at = actor_group.inserted_at - id = actor_group.id - - # Soft delete the group - Repo.update_all(Domain.Actors.Group, set: [deleted_at: DateTime.utc_now()]) - - # Assert that the group and associated policy has been soft-deleted - assert Domain.Actors.Group.Query.not_deleted() |> Repo.all() == [] - - # Simulate a sync - - groups = [ - %{ - "id" => "GROUP_DEVOPS_ID", - "created" => "2024-02-07T04:32:03.000Z", - "lastUpdated" => "2024-02-07T04:32:03.000Z", - "lastMembershipUpdated" => "2024-02-07T04:32:38.000Z", - "objectClass" => [ - "okta:user_group" - ], - "type" => "OKTA_GROUP", - "profile" => %{ - "name" => "DevOps", - "description" => "" - }, - "_links" => %{ - "logo" => [ - %{ - "name" => "medium", - "href" => "http://localhost/md/image.png", - "type" => "image/png" - }, - %{ - "name" => "large", - "href" => "http://localhost/lg/image.png", - "type" => "image/png" - } - ], - "users" => %{ - "href" => "http://localhost:#{bypass.port}/api/v1/groups/00gezqhvv4IFj2Avg5d7/users" - }, - "apps" => %{ - "href" => "http://localhost:#{bypass.port}/api/v1/groups/00gezqhvv4IFj2Avg5d7/apps" - } - } - } - ] - - OktaDirectory.mock_users_list_endpoint(bypass, 200, JSON.encode!([])) - OktaDirectory.mock_groups_list_endpoint(bypass, 200, JSON.encode!(groups)) - - OktaDirectory.mock_group_members_list_endpoint( - bypass, - "GROUP_DEVOPS_ID", - 200, - JSON.encode!([]) - ) - - {:ok, pid} = Task.Supervisor.start_link() - assert execute(%{task_supervisor: pid}) == :ok - - # Assert that the group has been resurrected - assert resurrected_group = Repo.get(Domain.Actors.Group, id) - assert resurrected_group.inserted_at == inserted_at - assert resurrected_group.id == id - assert resurrected_group.deleted_at == nil - assert Domain.Actors.Group.Query.not_deleted() |> Repo.all() == [resurrected_group] - end - test "persists the sync error on the provider", %{provider: provider, bypass: bypass} do response = %{ "errorCode" => "E0000011", diff --git a/elixir/apps/domain/test/domain/auth_test.exs b/elixir/apps/domain/test/domain/auth_test.exs index 48fc8e2fa..61864ae3c 100644 --- a/elixir/apps/domain/test/domain/auth_test.exs +++ b/elixir/apps/domain/test/domain/auth_test.exs @@ -444,21 +444,6 @@ defmodule Domain.AuthTest do assert all_providers_pending_token_refresh_by_adapter!(:google_workspace) == [] end - test "ignores deleted providers" do - {provider, _bypass} = Fixtures.Auth.start_and_create_google_workspace_provider() - - Domain.Fixture.update!(provider, %{ - deleted_at: DateTime.utc_now(), - adapter_state: %{ - "access_token" => "OIDC_ACCESS_TOKEN", - "refresh_token" => "OIDC_REFRESH_TOKEN", - "expires_at" => DateTime.utc_now() - } - }) - - assert all_providers_pending_token_refresh_by_adapter!(:google_workspace) == [] - end - test "ignores non-custom provisioners" do {provider, _bypass} = Fixtures.Auth.start_and_create_google_workspace_provider() @@ -533,19 +518,6 @@ defmodule Domain.AuthTest do assert all_providers_pending_sync_by_adapter!(:google_workspace) == [] end - test "ignores deleted providers" do - {provider, _bypass} = Fixtures.Auth.start_and_create_google_workspace_provider() - - Domain.Fixture.update!(provider, %{ - deleted_at: DateTime.utc_now(), - adapter_state: %{ - "expires_at" => DateTime.utc_now() - } - }) - - assert all_providers_pending_sync_by_adapter!(:google_workspace) == [] - end - test "ignores non-custom provisioners" do {provider, _bypass} = Fixtures.Auth.start_and_create_google_workspace_provider() @@ -781,7 +753,6 @@ defmodule Domain.AuthTest do assert provider.created_by_subject == %{"email" => nil, "name" => "System"} assert is_nil(provider.disabled_at) - assert is_nil(provider.deleted_at) end test "trims whitespace when creating a provider", %{ @@ -961,7 +932,6 @@ defmodule Domain.AuthTest do assert provider.account_id == subject.account.id assert is_nil(provider.disabled_at) - assert is_nil(provider.deleted_at) end test "returns error when subject cannot manage providers", %{ @@ -1031,7 +1001,6 @@ defmodule Domain.AuthTest do assert is_nil(other_provider.disabled_at) end - # TODO: HARD-DELETE - This test should be moved to Tokens since it has the FK test "deletes tokens issued for provider identities", %{ account: account, subject: subject @@ -1209,8 +1178,7 @@ defmodule Domain.AuthTest do refute Repo.get(Auth.Provider, provider.id) - assert other_provider = Repo.get(Auth.Provider, other_provider.id) - assert is_nil(other_provider.deleted_at) + assert Repo.get(Auth.Provider, other_provider.id) end test "deletes provider identities and tokens", %{ @@ -1274,51 +1242,6 @@ defmodule Domain.AuthTest do assert delete_provider(provider, subject) == {:error, :cant_delete_the_last_provider} end - # TODO: HARD-DELETE - Need to figure out if we care about this case - # test "returns error when trying to delete the last provider using a race condition" do - # for _ <- 0..50 do - # test_pid = self() - - # Task.async(fn -> - # allow_child_sandbox_access(test_pid) - - # account = Fixtures.Accounts.create_account() - - # provider_one = Fixtures.Auth.create_email_provider(account: account) - # provider_two = Fixtures.Auth.create_userpass_provider(account: account) - - # actor = - # Fixtures.Actors.create_actor( - # type: :account_admin_user, - # account: account, - # provider: provider_one - # ) - - # identity = - # Fixtures.Auth.create_identity( - # account: account, - # actor: actor, - # provider: provider_one - # ) - - # subject = Fixtures.Auth.create_subject(identity: identity) - - # for provider <- [provider_two, provider_one] do - # Task.async(fn -> - # allow_child_sandbox_access(test_pid) - # delete_provider(provider, subject) - # end) - # end - # |> Task.await_many() - - # assert Auth.Provider.Query.not_deleted() - # |> Auth.Provider.Query.by_account_id(account.id) - # |> Repo.aggregate(:count) == 1 - # end) - # end - # |> Task.await_many() - # end - test "raises error when deleting stale provider structs", %{ subject: subject, account: account @@ -1740,162 +1663,87 @@ defmodule Domain.AuthTest do assert Enum.count(actor_ids_by_provider_identifier) == 2 end - test "does not re-create actors for deleted identities", %{ - account: account, - provider: provider - } do - identity = + test "deletes removed identities", %{account: account, provider: provider} do + provider_identifiers = ["USER_ID1", "USER_ID2", "USER_ID3", "USER_ID4", "USER_ID5"] + + deleted_identity_actor = Fixtures.Actors.create_actor(account: account) + + deleted_identity = Fixtures.Auth.create_identity( account: account, provider: provider, - provider_identifier: "USER_ID1", - actor: [type: :account_admin_user] + actor: deleted_identity_actor, + provider_identifier: Enum.at(provider_identifiers, 0) ) - |> Fixtures.Auth.delete_identity() + + deleted_identity_token = + Fixtures.Tokens.create_token( + account: account, + actor: deleted_identity_actor, + identity: deleted_identity + ) + + for n <- 1..4 do + Fixtures.Auth.create_identity( + account: account, + provider: provider, + provider_identifier: Enum.at(provider_identifiers, n) + ) + end attrs_list = [ %{ "actor" => %{ - "name" => "Brian Manifold", + "name" => "Joe Smith", "type" => "account_user" }, - "provider_identifier" => "USER_ID1" + "provider_identifier" => "USER_ID3" + }, + %{ + "actor" => %{ + "name" => "Jennie Smith", + "type" => "account_user" + }, + "provider_identifier" => "USER_ID4" + }, + %{ + "actor" => %{ + "name" => "Jane Doe", + "type" => "account_admin_user" + }, + "provider_identifier" => "USER_ID5" } ] assert {:ok, %{ - identities: [fetched_identity], - plan: {[], ["USER_ID1"], []}, - deleted_count: 0, + identities: [_id1, _id2, _id3, _id4, _id5], + plan: {[], upsert, delete}, + deleted_count: 2, inserted: [], actor_ids_by_provider_identifier: actor_ids_by_provider_identifier }} = sync_provider_identities(provider, attrs_list) - assert fetched_identity.actor_id == identity.actor_id - assert actor_ids_by_provider_identifier == %{"USER_ID1" => identity.actor_id} + assert Enum.sort(upsert) == ["USER_ID3", "USER_ID4", "USER_ID5"] - identity = Repo.get(Auth.Identity, identity.id) - assert identity.actor_id == identity.actor_id - refute identity.deleted_at + assert Enum.take(provider_identifiers, 2) + |> Enum.all?(&(&1 in delete)) - actor = Repo.get(Domain.Actors.Actor, identity.actor_id) - assert actor.name == "Brian Manifold" + refute Repo.get_by(Auth.Identity, provider_identifier: "USER_ID1") + refute Repo.get_by(Auth.Identity, provider_identifier: "USER_ID2") + + assert Auth.Identity.Query.all() + |> Auth.Identity.Query.by_provider_id(provider.id) + |> Repo.aggregate(:count) == 3 + + assert actor_ids_by_provider_identifier + |> Map.keys() + |> length() == 3 + + # Signs out users which identity has been deleted + refute Repo.reload(deleted_identity_token) end - test "does not attempt to delete identities that are already deleted", %{ - account: account, - provider: provider - } do - identity = - Fixtures.Auth.create_identity( - account: account, - provider: provider, - provider_identifier: "USER_ID1", - actor: [type: :account_admin_user] - ) - |> Fixtures.Auth.delete_identity() - - attrs_list = [] - - assert {:ok, - %{ - identities: [fetched_identity], - plan: {[], [], []}, - deleted_count: 0, - inserted: [], - actor_ids_by_provider_identifier: %{} - }} = sync_provider_identities(provider, attrs_list) - - assert fetched_identity.id == identity.id - - identity = Repo.get(Auth.Identity, identity.id) - assert identity.deleted_at - end - - # TODO: HARD-DELETE - Need to figure out if the flows message checking is necessary - # test "deletes removed identities", %{account: account, provider: provider} do - # provider_identifiers = ["USER_ID1", "USER_ID2", "USER_ID3", "USER_ID4", "USER_ID5"] - - # deleted_identity_actor = Fixtures.Actors.create_actor(account: account) - - # deleted_identity = - # Fixtures.Auth.create_identity( - # account: account, - # provider: provider, - # actor: deleted_identity_actor, - # provider_identifier: Enum.at(provider_identifiers, 0) - # ) - - # deleted_identity_token = - # Fixtures.Tokens.create_token( - # account: account, - # actor: deleted_identity_actor, - # identity: deleted_identity - # ) - - # for n <- 1..4 do - # Fixtures.Auth.create_identity( - # account: account, - # provider: provider, - # provider_identifier: Enum.at(provider_identifiers, n) - # ) - # end - - # attrs_list = [ - # %{ - # "actor" => %{ - # "name" => "Joe Smith", - # "type" => "account_user" - # }, - # "provider_identifier" => "USER_ID3" - # }, - # %{ - # "actor" => %{ - # "name" => "Jennie Smith", - # "type" => "account_user" - # }, - # "provider_identifier" => "USER_ID4" - # }, - # %{ - # "actor" => %{ - # "name" => "Jane Doe", - # "type" => "account_admin_user" - # }, - # "provider_identifier" => "USER_ID5" - # } - # ] - - # assert {:ok, - # %{ - # identities: [_id1, _id2, _id3, _id4, _id5], - # plan: {[], upsert, delete}, - # deleted: 2, - # inserted: [], - # actor_ids_by_provider_identifier: actor_ids_by_provider_identifier - # }} = sync_provider_identities(provider, attrs_list) - - # assert Enum.sort(upsert) == ["USER_ID3", "USER_ID4", "USER_ID5"] - - # assert Enum.take(provider_identifiers, 2) - # |> Enum.all?(&(&1 in delete)) - - # refute Repo.get_by(Auth.Identity, provider_identifier: "USER_ID1") - # refute Repo.get_by(Auth.Identity, provider_identifier: "USER_ID2") - - # assert Auth.Identity.Query.all() - # |> Auth.Identity.Query.by_provider_id(provider.id) - # |> Repo.aggregate(:count) == 3 - - # assert actor_ids_by_provider_identifier - # |> Map.keys() - # |> length() == 3 - - # # Signs out users which identity has been deleted - # deleted_identity_token = Repo.reload(deleted_identity_token) - # assert deleted_identity_token.deleted_at - # end - test "circuit breaker prevents mass deletions of identities", %{ account: account, provider: provider @@ -1919,7 +1767,7 @@ defmodule Domain.AuthTest do |> Auth.Identity.Query.by_provider_id(provider.id) |> Repo.aggregate(:count) == 5 - assert Auth.Identity.Query.not_deleted() + assert Auth.Identity.Query.all() |> Auth.Identity.Query.by_provider_id(provider.id) |> Repo.aggregate(:count) == 5 end @@ -1978,63 +1826,6 @@ defmodule Domain.AuthTest do assert Repo.aggregate(Auth.Identity, :count) == 0 assert Repo.aggregate(Domain.Actors.Actor, :count) == 0 end - - test "resolves provider identifier conflicts across actors", %{ - account: account, - provider: provider - } do - identity1 = - Fixtures.Auth.create_identity( - account: account, - provider: provider, - provider_identifier: "USER_ID1", - actor: [type: :account_admin_user] - ) - |> Fixtures.Auth.delete_identity() - - identity2 = - Fixtures.Auth.create_identity( - account: account, - provider: provider, - provider_identifier: "USER_ID1", - actor: [type: :account_admin_user] - ) - - attrs_list = [ - %{ - "actor" => %{ - "name" => "Brian Manifold", - "type" => "account_user" - }, - "provider_identifier" => "USER_ID1" - } - ] - - assert {:ok, - %{ - identities: [_identity1, _identity2], - plan: {[], update, []}, - deleted_count: 0, - inserted: [], - actor_ids_by_provider_identifier: actor_ids_by_provider_identifier - }} = sync_provider_identities(provider, attrs_list) - - assert length(update) == 2 - assert update == ["USER_ID1", "USER_ID1"] - - identity1 = Repo.get(Domain.Auth.Identity, identity1.id) |> Repo.preload(:actor) - assert identity1.deleted_at - assert identity1.actor.name != "Brian Manifold" - - identity2 = Repo.get(Domain.Auth.Identity, identity2.id) |> Repo.preload(:actor) - refute identity2.deleted_at - assert identity2.actor.name == "Brian Manifold" - - assert Map.get(actor_ids_by_provider_identifier, identity2.provider_identifier) == - identity2.actor.id - - assert Enum.count(actor_ids_by_provider_identifier) == 1 - end end describe "upsert_identity/3" do @@ -2087,7 +1878,6 @@ defmodule Domain.AuthTest do assert identity.provider_state == %{} assert identity.provider_virtual_state == %{} assert identity.account_id == provider.account_id - assert is_nil(identity.deleted_at) end test "trims whitespace when creating an identity", %{ @@ -2270,8 +2060,6 @@ defmodule Domain.AuthTest do "name" => subject.actor.name, "email" => subject.identity.email } - - assert is_nil(identity.deleted_at) end test "trims whitespace when creating an identity", %{ @@ -2389,7 +2177,6 @@ defmodule Domain.AuthTest do assert %{"password_hash" => _} = identity.provider_state assert %{password_hash: _} = identity.provider_virtual_state.changes assert identity.account_id == provider.account_id - assert is_nil(identity.deleted_at) end test "creates an identity when provider_identifier is an email address" do @@ -2423,7 +2210,6 @@ defmodule Domain.AuthTest do assert %{"password_hash" => _} = identity.provider_state assert %{password_hash: _} = identity.provider_virtual_state.changes assert identity.account_id == provider.account_id - assert is_nil(identity.deleted_at) end test "returns error when identifier is invalid" do @@ -2561,7 +2347,6 @@ defmodule Domain.AuthTest do refute Repo.get(Auth.Identity, identity.id) end - # TODO: HARD-DELETE - This test should be moved to tokens since it has the FK test "deletes token", %{ account: account, provider: provider, @@ -2682,29 +2467,6 @@ defmodule Domain.AuthTest do assert Repo.aggregate(by_actor_id_query, :count) == 0 end - test "removes all identities and flows that belong to a provider", %{ - account: account, - provider: provider, - subject: subject - } do - actor = Fixtures.Actors.create_actor(account: account, provider: provider) - Fixtures.Auth.create_identity(account: account, provider: provider, actor: actor) - Fixtures.Auth.create_identity(account: account, provider: provider, actor: actor) - Fixtures.Auth.create_identity(account: account, provider: provider, actor: actor) - - all_identities_query = Auth.Identity.Query.all() - assert Repo.aggregate(all_identities_query, :count) == 4 - assert {:ok, 4} = delete_identities_for(provider, subject) - - assert Repo.aggregate(all_identities_query, :count) == 0 - - by_provider_id_query = - Auth.Identity.Query.not_deleted() - |> Auth.Identity.Query.by_provider_id(provider.id) - - assert Repo.aggregate(by_provider_id_query, :count) == 0 - end - test "deletes tokens", %{ account: account, provider: provider, @@ -2753,22 +2515,6 @@ defmodule Domain.AuthTest do end end - # TODO: HARD-DELETE - Remove or update after soft deletion is removed - describe "identity_soft_deleted?/1" do - test "returns true when identity is deleted" do - identity = - Fixtures.Auth.create_identity() - |> Fixtures.Auth.delete_identity() - - assert identity_soft_deleted?(identity) == true - end - - test "returns false when identity is not deleted" do - identity = Fixtures.Auth.create_identity() - assert identity_soft_deleted?(identity) == false - end - end - # Authentication describe "sign_in/4" do @@ -3107,51 +2853,6 @@ defmodule Domain.AuthTest do assert sign_in(provider, identity.provider_identifier, nonce, secret, context) == {:error, :unauthorized} end - - # TODO: HARD-DELETE - Not sure this test is needed any more. I don't think this is a reachable state. - # test "returns error when actor is deleted", %{ - # account: account, - # provider: provider, - # user_agent: user_agent, - # remote_ip: remote_ip - # } do - # nonce = "test_nonce_for_firezone" - - # actor = - # Fixtures.Actors.create_actor(type: :account_admin_user, account: account) - # |> Fixtures.Actors.delete() - - # identity = Fixtures.Auth.create_identity(account: account, provider: provider, actor: actor) - # context = %Auth.Context{type: :browser, user_agent: user_agent, remote_ip: remote_ip} - # {:ok, identity} = Domain.Auth.Adapters.Email.request_sign_in_token(identity, context) - - # secret = identity.provider_virtual_state.nonce <> identity.provider_virtual_state.fragment - - # assert sign_in(provider, identity.provider_identifier, nonce, secret, context) == - # {:error, :unauthorized} - # end - - # TODO: HARD-DELETE - Not sure this test is needed any more. I don't think this is a reachable state. - # test "returns error when provider is deleted", %{ - # account: account, - # provider: provider, - # user_agent: user_agent, - # remote_ip: remote_ip - # } do - # nonce = "test_nonce_for_firezone" - - # actor = Fixtures.Actors.create_actor(type: :account_admin_user, account: account) - # identity = Fixtures.Auth.create_identity(account: account, provider: provider, actor: actor) - # subject = Fixtures.Auth.create_subject(identity: identity) - # {:ok, _provider} = delete_provider(provider, subject) - - # context = %Auth.Context{type: :browser, user_agent: user_agent, remote_ip: remote_ip} - # {:ok, identity} = Domain.Auth.Adapters.Email.request_sign_in_token(identity, context) - # secret = identity.provider_virtual_state.nonce <> identity.provider_virtual_state.fragment - - # assert sign_in(provider, identity.provider_identifier, nonce, secret, context) == - # {:error, :unauthorized} - # end end describe "sign_in/3" do @@ -4326,12 +4027,4 @@ defmodule Domain.AuthTest do refute can_grant_role?(subject, :account_admin_user) end end - - # TODO: HARD-DELETE - This may not be needed anymore - # defp allow_child_sandbox_access(parent_pid) do - # Ecto.Adapters.SQL.Sandbox.allow(Repo, parent_pid, self()) - # # Allow is async call we need to break current process execution - # # to allow sandbox to be enabled - # :timer.sleep(10) - # end end diff --git a/elixir/apps/domain/test/domain/change_logs/replication_connection_test.exs b/elixir/apps/domain/test/domain/change_logs/replication_connection_test.exs index 5bdfaf3d5..79b2b1bc9 100644 --- a/elixir/apps/domain/test/domain/change_logs/replication_connection_test.exs +++ b/elixir/apps/domain/test/domain/change_logs/replication_connection_test.exs @@ -273,14 +273,13 @@ defmodule Domain.ChangeLogs.ReplicationConnectionTest do } end - test "adds delete operation to flush buffer for non-soft-deleted records", %{account: account} do + test "adds delete operation to flush buffer for deleted records", %{account: account} do table = "resources" old_data = %{ "id" => Ecto.UUID.generate(), "account_id" => account.id, - "name" => "deleted resource", - "deleted_at" => nil + "name" => "deleted resource" } lsn = 12347 diff --git a/elixir/apps/domain/test/domain/changes/hooks/accounts_test.exs b/elixir/apps/domain/test/domain/changes/hooks/accounts_test.exs index f23cd6cf4..5ac252eae 100644 --- a/elixir/apps/domain/test/domain/changes/hooks/accounts_test.exs +++ b/elixir/apps/domain/test/domain/changes/hooks/accounts_test.exs @@ -30,26 +30,6 @@ defmodule Domain.Changes.Hooks.AccountsTest do assert account.id == account_id end - - test "sends delete when soft-deleted" do - account_id = "00000000-0000-0000-0000-000000000002" - :ok = PubSub.Account.subscribe(account_id) - - old_data = %{ - "id" => account_id, - "deleted_at" => nil - } - - data = %{ - "id" => account_id, - "deleted_at" => "2023-10-01T00:00:00Z" - } - - assert :ok == on_update(0, old_data, data) - assert_receive %Change{op: :delete, old_struct: %Accounts.Account{} = account, lsn: 0} - - assert account.id == account_id - end end describe "delete/1" do @@ -57,25 +37,18 @@ defmodule Domain.Changes.Hooks.AccountsTest do account_id = "00000000-0000-0000-0000-000000000003" :ok = PubSub.Account.subscribe(account_id) - old_data = %{ - "id" => account_id, - "deleted_at" => "2023-10-01T00:00:00Z" - } + old_data = %{"id" => account_id} assert :ok == on_delete(0, old_data) assert_receive %Change{op: :delete, old_struct: %Accounts.Account{} = account, lsn: 0} assert account.id == account_id - assert account.deleted_at == ~U[2023-10-01 00:00:00.000000Z] end test "deletes associated flows when account is deleted" do account = Fixtures.Accounts.create_account() flow = Fixtures.Flows.create_flow(account: account) - old_data = %{ - "id" => account.id, - "deleted_at" => "2023-10-01T00:00:00Z" - } + old_data = %{"id" => account.id} assert :ok == on_delete(0, old_data) assert Repo.get_by(Domain.Flows.Flow, id: flow.id) == nil diff --git a/elixir/apps/domain/test/domain/changes/hooks/actor_group_memberships_test.exs b/elixir/apps/domain/test/domain/changes/hooks/actor_group_memberships_test.exs index b77d1ad51..f9e554b8a 100644 --- a/elixir/apps/domain/test/domain/changes/hooks/actor_group_memberships_test.exs +++ b/elixir/apps/domain/test/domain/changes/hooks/actor_group_memberships_test.exs @@ -1,5 +1,5 @@ defmodule Domain.Changes.Hooks.ActorGroupMembershipsTest do - use API.ChannelCase, async: true + use Domain.DataCase, async: true import Domain.Changes.Hooks.ActorGroupMemberships alias Domain.{Actors, Changes.Change, Flows, PubSub} diff --git a/elixir/apps/domain/test/domain/changes/hooks/clients_test.exs b/elixir/apps/domain/test/domain/changes/hooks/clients_test.exs index 0d3f14797..9a8598b17 100644 --- a/elixir/apps/domain/test/domain/changes/hooks/clients_test.exs +++ b/elixir/apps/domain/test/domain/changes/hooks/clients_test.exs @@ -10,23 +10,6 @@ defmodule Domain.Changes.Hooks.ClientsTest do end describe "update/2" do - test "soft-delete broadcasts deleted client" do - client = Fixtures.Clients.create_client() - :ok = PubSub.Account.subscribe(client.account_id) - - old_data = %{"id" => client.id, "deleted_at" => nil, "account_id" => client.account_id} - - data = %{ - "id" => client.id, - "deleted_at" => DateTime.utc_now(), - "account_id" => client.account_id - } - - assert :ok == on_update(0, old_data, data) - assert_receive %Change{op: :delete, old_struct: %Clients.Client{} = deleted_client, lsn: 0} - assert deleted_client.id == client.id - end - test "update broadcasts updated client" do account = Fixtures.Accounts.create_account() client = Fixtures.Clients.create_client(account: account) diff --git a/elixir/apps/domain/test/domain/changes/hooks/gateway_groups_test.exs b/elixir/apps/domain/test/domain/changes/hooks/gateway_groups_test.exs index 886ee1ba7..9e30c8b43 100644 --- a/elixir/apps/domain/test/domain/changes/hooks/gateway_groups_test.exs +++ b/elixir/apps/domain/test/domain/changes/hooks/gateway_groups_test.exs @@ -25,8 +25,7 @@ defmodule Domain.Changes.Hooks.GatewayGroupsTest do old_data = %{ "id" => "00000000-0000-0000-0000-000000000001", "account_id" => account_id, - "name" => "Old Gateway Group", - "deleted_at" => nil + "name" => "Old Gateway Group" } data = Map.put(old_data, "name", "Updated Gateway Group") diff --git a/elixir/apps/domain/test/domain/changes/hooks/gateways_test.exs b/elixir/apps/domain/test/domain/changes/hooks/gateways_test.exs index 89665f2ff..0fd5c6622 100644 --- a/elixir/apps/domain/test/domain/changes/hooks/gateways_test.exs +++ b/elixir/apps/domain/test/domain/changes/hooks/gateways_test.exs @@ -10,38 +10,6 @@ defmodule Domain.Changes.Hooks.GatewaysTest do end describe "update/2" do - test "soft-delete broadcasts deleted gateway" do - account = Fixtures.Accounts.create_account() - gateway = Fixtures.Gateways.create_gateway(account: account) - - :ok = PubSub.Account.subscribe(account.id) - - old_data = %{"id" => gateway.id, "deleted_at" => nil, "account_id" => account.id} - data = Map.put(old_data, "deleted_at", "2023-01-01T00:00:00Z") - - assert :ok = on_update(0, old_data, data) - - assert_receive %Change{ - op: :delete, - old_struct: %Gateways.Gateway{} = deleted_gateway, - lsn: 0 - } - - assert deleted_gateway.id == gateway.id - end - - test "soft-delete deletes flows" do - account = Fixtures.Accounts.create_account() - gateway = Fixtures.Gateways.create_gateway(account: account) - - old_data = %{"id" => gateway.id, "deleted_at" => nil, "account_id" => account.id} - data = Map.put(old_data, "deleted_at", "2023-01-01T00:00:00Z") - - assert flow = Fixtures.Flows.create_flow(gateway: gateway, account: account) - assert :ok = on_update(0, old_data, data) - refute Repo.get_by(Domain.Flows.Flow, id: flow.id) - end - test "update returns :ok" do assert :ok = on_update(0, %{}, %{}) end @@ -57,8 +25,7 @@ defmodule Domain.Changes.Hooks.GatewaysTest do old_data = %{ "id" => gateway.id, "account_id" => account.id, - "name" => "Test Gateway", - "deleted_at" => nil + "name" => "Test Gateway" } assert :ok = on_delete(0, old_data) @@ -76,7 +43,7 @@ defmodule Domain.Changes.Hooks.GatewaysTest do account = Fixtures.Accounts.create_account() gateway = Fixtures.Gateways.create_gateway(account: account) - old_data = %{"id" => gateway.id, "account_id" => account.id, "deleted_at" => nil} + old_data = %{"id" => gateway.id, "account_id" => account.id} assert flow = Fixtures.Flows.create_flow(gateway: gateway, account: account) assert :ok = on_delete(0, old_data) diff --git a/elixir/apps/domain/test/domain/changes/hooks/policies_test.exs b/elixir/apps/domain/test/domain/changes/hooks/policies_test.exs index 4dd4e5079..448fecfd1 100644 --- a/elixir/apps/domain/test/domain/changes/hooks/policies_test.exs +++ b/elixir/apps/domain/test/domain/changes/hooks/policies_test.exs @@ -14,8 +14,7 @@ defmodule Domain.Changes.Hooks.PoliciesTest do "account_id" => account.id, "actor_group_id" => policy.actor_group_id, "resource_id" => policy.resource_id, - "disabled_at" => nil, - "deleted_at" => nil + "disabled_at" => nil } assert :ok == on_insert(0, data) @@ -40,8 +39,7 @@ defmodule Domain.Changes.Hooks.PoliciesTest do "account_id" => account.id, "actor_group_id" => policy.actor_group_id, "resource_id" => policy.resource_id, - "disabled_at" => nil, - "deleted_at" => nil + "disabled_at" => nil } data = Map.put(old_data, "disabled_at", "2023-10-01T00:00:00Z") @@ -74,8 +72,7 @@ defmodule Domain.Changes.Hooks.PoliciesTest do "account_id" => account.id, "actor_group_id" => policy.actor_group_id, "resource_id" => policy.resource_id, - "disabled_at" => "2023-09-01T00:00:00Z", - "deleted_at" => nil + "disabled_at" => "2023-09-01T00:00:00Z" } data = Map.put(old_data, "disabled_at", nil) @@ -89,62 +86,6 @@ defmodule Domain.Changes.Hooks.PoliciesTest do assert policy.resource_id == data["resource_id"] end - test "soft-delete broadcasts deleted policy" do - account = Fixtures.Accounts.create_account() - policy = Fixtures.Policies.create_policy(account: account) - :ok = PubSub.Account.subscribe(account.id) - - old_data = %{ - "id" => policy.id, - "account_id" => account.id, - "actor_group_id" => policy.actor_group_id, - "resource_id" => policy.resource_id, - "disabled_at" => nil, - "deleted_at" => nil - } - - data = Map.put(old_data, "deleted_at", "2023-10-01T00:00:00Z") - - assert :ok == on_update(0, old_data, data) - assert_receive %Change{op: :delete, old_struct: %Policies.Policy{} = policy, lsn: 0} - - assert policy.id == old_data["id"] - assert policy.account_id == old_data["account_id"] - assert policy.actor_group_id == old_data["actor_group_id"] - assert policy.resource_id == old_data["resource_id"] - end - - test "soft-delete deletes flows" do - account = Fixtures.Accounts.create_account() - resource = Fixtures.Resources.create_resource(account: account) - - policy = - Fixtures.Policies.create_policy( - account: account, - resource: resource - ) - - old_data = %{ - "id" => policy.id, - "account_id" => account.id, - "actor_group_id" => policy.actor_group_id, - "resource_id" => resource.id, - "deleted_at" => nil - } - - data = Map.put(old_data, "deleted_at", "2023-10-01T00:00:00Z") - - assert flow = - Fixtures.Flows.create_flow( - policy: policy, - resource: resource, - account: account - ) - - assert :ok = on_update(0, old_data, data) - refute Repo.get_by(Domain.Flows.Flow, id: flow.id) - end - test "non-breaking update broadcasts updated policy" do account = Fixtures.Accounts.create_account() policy = Fixtures.Policies.create_policy(account: account) @@ -156,8 +97,7 @@ defmodule Domain.Changes.Hooks.PoliciesTest do "account_id" => account.id, "actor_group_id" => policy.actor_group_id, "resource_id" => policy.resource_id, - "disabled_at" => nil, - "deleted_at" => nil + "disabled_at" => nil } data = Map.put(old_data, "description", "Updated description") @@ -186,8 +126,7 @@ defmodule Domain.Changes.Hooks.PoliciesTest do "id" => policy.id, "account_id" => account.id, "actor_group_id" => policy.actor_group_id, - "resource_id" => policy.resource_id, - "deleted_at" => nil + "resource_id" => policy.resource_id } data = Map.put(old_data, "resource_id", "00000000-0000-0000-0000-000000000001") @@ -210,8 +149,7 @@ defmodule Domain.Changes.Hooks.PoliciesTest do "id" => policy.id, "account_id" => account.id, "actor_group_id" => policy.actor_group_id, - "resource_id" => policy.resource_id, - "deleted_at" => nil + "resource_id" => policy.resource_id } data = Map.put(old_data, "actor_group_id", "00000000-0000-0000-0000-000000000001") @@ -233,8 +171,7 @@ defmodule Domain.Changes.Hooks.PoliciesTest do "resource_id" => policy.resource_id, "conditions" => [ %{"property" => "remote_ip", "operator" => "is_in", "values" => ["10.0.0.1"]} - ], - "deleted_at" => nil + ] } data = @@ -284,8 +221,7 @@ defmodule Domain.Changes.Hooks.PoliciesTest do "id" => policy.id, "account_id" => account.id, "actor_group_id" => policy.actor_group_id, - "resource_id" => policy.resource_id, - "deleted_at" => nil + "resource_id" => policy.resource_id } assert flow = Fixtures.Flows.create_flow(policy: policy, account: account) diff --git a/elixir/apps/domain/test/domain/changes/hooks/resources_test.exs b/elixir/apps/domain/test/domain/changes/hooks/resources_test.exs index 9b3f8b017..cfa86480f 100644 --- a/elixir/apps/domain/test/domain/changes/hooks/resources_test.exs +++ b/elixir/apps/domain/test/domain/changes/hooks/resources_test.exs @@ -18,8 +18,7 @@ defmodule Domain.Changes.Hooks.ResourcesTest do "type" => resource.type, "address" => resource.address, "filters" => filters, - "ip_stack" => resource.ip_stack, - "deleted_at" => nil + "ip_stack" => resource.ip_stack } assert :ok == on_insert(0, data) @@ -41,66 +40,6 @@ defmodule Domain.Changes.Hooks.ResourcesTest do end describe "update/2" do - test "soft-delete broadcasts deleted resource" do - account = Fixtures.Accounts.create_account() - filters = [%{"protocol" => "tcp", "ports" => ["80", "443"]}] - resource = Fixtures.Resources.create_resource(account: account, filters: filters) - - :ok = PubSub.Account.subscribe(account.id) - - old_data = %{ - "id" => resource.id, - "account_id" => account.id, - "address_description" => resource.address_description, - "type" => resource.type, - "address" => resource.address, - "filters" => filters, - "ip_stack" => resource.ip_stack, - "deleted_at" => nil - } - - data = Map.put(old_data, "deleted_at", "2023-10-01T00:00:00Z") - - assert :ok == on_update(0, old_data, data) - - assert_receive %Change{ - op: :delete, - old_struct: %Resources.Resource{} = deleted_resource, - lsn: 0 - } - - assert deleted_resource.id == resource.id - assert deleted_resource.account_id == resource.account_id - assert deleted_resource.type == resource.type - assert deleted_resource.address == resource.address - assert deleted_resource.filters == resource.filters - assert deleted_resource.ip_stack == resource.ip_stack - assert deleted_resource.address_description == resource.address_description - end - - test "soft-delete deletes flows" do - account = Fixtures.Accounts.create_account() - filters = [%{"protocol" => "tcp", "ports" => ["80", "443"]}] - resource = Fixtures.Resources.create_resource(account: account, filters: filters) - - old_data = %{ - "id" => resource.id, - "account_id" => account.id, - "address_description" => resource.address_description, - "type" => resource.type, - "address" => resource.address, - "filters" => filters, - "ip_stack" => resource.ip_stack, - "deleted_at" => nil - } - - data = Map.put(old_data, "deleted_at", "2023-10-01T00:00:00Z") - - assert flow = Fixtures.Flows.create_flow(resource: resource, account: account) - assert :ok = on_update(0, old_data, data) - refute Repo.get_by(Flows.Flow, id: flow.id) - end - test "regular update broadcasts updated resource" do account = Fixtures.Accounts.create_account() filters = [%{"protocol" => "tcp", "ports" => ["80", "443"]}] @@ -115,8 +54,7 @@ defmodule Domain.Changes.Hooks.ResourcesTest do "type" => resource.type, "address" => resource.address, "filters" => filters, - "ip_stack" => resource.ip_stack, - "deleted_at" => nil + "ip_stack" => resource.ip_stack } data = Map.put(old_data, "address", "new-address.example.com") @@ -151,8 +89,7 @@ defmodule Domain.Changes.Hooks.ResourcesTest do "type" => "dns", "address" => resource.address, "filters" => filters, - "ip_stack" => resource.ip_stack, - "deleted_at" => nil + "ip_stack" => resource.ip_stack } data = Map.put(old_data, "type", "cidr") @@ -178,8 +115,7 @@ defmodule Domain.Changes.Hooks.ResourcesTest do "type" => resource.type, "address" => resource.address, "filters" => filters, - "ip_stack" => resource.ip_stack, - "deleted_at" => nil + "ip_stack" => resource.ip_stack } assert :ok == on_delete(0, old_data) @@ -211,8 +147,7 @@ defmodule Domain.Changes.Hooks.ResourcesTest do "type" => resource.type, "address" => resource.address, "filters" => filters, - "ip_stack" => resource.ip_stack, - "deleted_at" => nil + "ip_stack" => resource.ip_stack } assert flow = Fixtures.Flows.create_flow(resource: resource, account: account) diff --git a/elixir/apps/domain/test/domain/changes/hooks/tokens_test.exs b/elixir/apps/domain/test/domain/changes/hooks/tokens_test.exs index 39220cc9f..b563e2713 100644 --- a/elixir/apps/domain/test/domain/changes/hooks/tokens_test.exs +++ b/elixir/apps/domain/test/domain/changes/hooks/tokens_test.exs @@ -14,48 +14,6 @@ defmodule Domain.Changes.Hooks.TokensTest do assert :ok = on_update(0, %{"type" => "email"}, %{"type" => "email"}) end - test "soft-delete broadcasts disconnect" do - account = Fixtures.Accounts.create_account() - token = Fixtures.Tokens.create_token(account: account) - - :ok = PubSub.subscribe("sessions:#{token.id}") - - old_data = %{ - "id" => token.id, - "account_id" => account.id, - "type" => token.type, - "deleted_at" => nil - } - - assert :ok == on_delete(0, old_data) - - assert_receive %Phoenix.Socket.Broadcast{ - topic: topic, - event: "disconnect" - } - - assert topic == "sessions:#{token.id}" - end - - test "soft-delete deletes flows" do - account = Fixtures.Accounts.create_account() - token = Fixtures.Tokens.create_token(account: account) - - old_data = %{ - "id" => token.id, - "account_id" => account.id, - "type" => token.type, - "deleted_at" => nil - } - - data = Map.put(old_data, "deleted_at", "2023-10-01T00:00:00Z") - - assert flow = Fixtures.Flows.create_flow(account: account, token: token) - assert flow.token_id == token.id - assert :ok = on_update(0, old_data, data) - refute Repo.get_by(Flows.Flow, id: flow.id) - end - test "regular update returns :ok" do assert :ok = on_update(0, %{}, %{}) end @@ -71,8 +29,7 @@ defmodule Domain.Changes.Hooks.TokensTest do old_data = %{ "id" => token.id, "account_id" => account.id, - "type" => token.type, - "deleted_at" => nil + "type" => token.type } assert :ok == on_delete(0, old_data) @@ -92,8 +49,7 @@ defmodule Domain.Changes.Hooks.TokensTest do old_data = %{ "id" => token.id, "account_id" => account.id, - "type" => token.type, - "deleted_at" => nil + "type" => token.type } assert flow = Fixtures.Flows.create_flow(account: account, token: token) diff --git a/elixir/apps/domain/test/domain/clients_test.exs b/elixir/apps/domain/test/domain/clients_test.exs index 64d0c8c56..e89a730b7 100644 --- a/elixir/apps/domain/test/domain/clients_test.exs +++ b/elixir/apps/domain/test/domain/clients_test.exs @@ -1306,7 +1306,7 @@ defmodule Domain.ClientsTest do Fixtures.Clients.create_client(actor: actor) query = - Clients.Client.Query.not_deleted() + Clients.Client.Query.all() |> Clients.Client.Query.by_actor_id(actor.id) assert Repo.aggregate(query, :count) == 3 diff --git a/elixir/apps/domain/test/domain/gateways_test.exs b/elixir/apps/domain/test/domain/gateways_test.exs index 2eafe8da4..512b44fb8 100644 --- a/elixir/apps/domain/test/domain/gateways_test.exs +++ b/elixir/apps/domain/test/domain/gateways_test.exs @@ -409,7 +409,7 @@ defmodule Domain.GatewaysTest do assert {:ok, _group} = delete_group(group, subject) - assert Resources.Resource.Query.not_deleted() + assert Resources.Resource.Query.all() |> Resources.Resource.Query.by_gateway_group_id(group.id) |> Repo.aggregate(:count) == 0 end diff --git a/elixir/apps/domain/test/domain/policies_test.exs b/elixir/apps/domain/test/domain/policies_test.exs index 871639ed3..54f6f3494 100644 --- a/elixir/apps/domain/test/domain/policies_test.exs +++ b/elixir/apps/domain/test/domain/policies_test.exs @@ -81,81 +81,6 @@ defmodule Domain.PoliciesTest do end end - describe "fetch_policy_by_id_or_persistent_id/3" do - test "returns error when policy does not exist", %{subject: subject} do - assert fetch_policy_by_id_or_persistent_id(Ecto.UUID.generate(), subject) == - {:error, :not_found} - end - - test "returns error when UUID is invalid", %{subject: subject} do - assert fetch_policy_by_id_or_persistent_id("foo", subject) == {:error, :not_found} - end - - test "returns policy when policy exists", %{account: account, subject: subject} do - policy = Fixtures.Policies.create_policy(account: account) - - assert {:ok, fetched_policy} = fetch_policy_by_id_or_persistent_id(policy.id, subject) - assert fetched_policy.id == policy.id - - assert {:ok, fetched_policy} = - fetch_policy_by_id_or_persistent_id(policy.persistent_id, subject) - - assert fetched_policy.id == policy.id - end - - test "does not return deleted policies", %{account: account, subject: subject} do - policy = Fixtures.Policies.create_policy(account: account) - delete_policy(policy, subject) - - assert {:error, :not_found} = fetch_policy_by_id_or_persistent_id(policy.id, subject) - end - - test "does not return policies in other accounts", %{subject: subject} do - policy = Fixtures.Policies.create_policy() - assert fetch_policy_by_id_or_persistent_id(policy.id, subject) == {:error, :not_found} - - assert fetch_policy_by_id_or_persistent_id(policy.persistent_id, subject) == - {:error, :not_found} - end - - test "returns error when subject has no permission to view policies", %{subject: subject} do - subject = Fixtures.Auth.remove_permissions(subject) - - assert fetch_policy_by_id_or_persistent_id(Ecto.UUID.generate(), subject) == - {:error, - {:unauthorized, - reason: :missing_permissions, - missing_permissions: [ - {:one_of, - [ - Policies.Authorizer.manage_policies_permission(), - Policies.Authorizer.view_available_policies_permission() - ]} - ]}} - end - - # TODO: add a test that soft-deleted assocs are not preloaded - test "associations are preloaded when opts given", %{account: account, subject: subject} do - policy = Fixtures.Policies.create_policy(account: account) - - {:ok, policy} = - fetch_policy_by_id_or_persistent_id(policy.id, subject, - preload: [:actor_group, :resource] - ) - - assert Ecto.assoc_loaded?(policy.actor_group) - assert Ecto.assoc_loaded?(policy.resource) - - {:ok, policy} = - fetch_policy_by_id_or_persistent_id(policy.persistent_id, subject, - preload: [:actor_group, :resource] - ) - - assert Ecto.assoc_loaded?(policy.actor_group) - assert Ecto.assoc_loaded?(policy.resource) - end - end - describe "list_policies/2" do test "returns empty list when there are no policies", %{subject: subject} do assert {:ok, [], _metadata} = list_policies(subject) @@ -754,139 +679,6 @@ defmodule Domain.PoliciesTest do end end - describe "delete_policies_for/1" do - setup %{resource: resource, actor_group: actor_group, account: account, subject: subject} do - policy = - Fixtures.Policies.create_policy( - account: account, - resource: resource, - actor_group: actor_group, - subject: subject - ) - - %{ - resource: resource, - actor_group: actor_group, - policy: policy - } - end - - test "deletes policies for actor group provider", %{ - actor_group: actor_group, - policy: policy - } do - assert {:ok, _count} = delete_policies_for(actor_group) - refute Repo.get(Policies.Policy, policy.id) - end - end - - describe "delete_policies_for/2" do - setup %{account: account, subject: subject} do - resource = Fixtures.Resources.create_resource(account: account) - actor_group = Fixtures.Actors.create_group(account: account) - - policy = - Fixtures.Policies.create_policy( - account: account, - resource: resource, - actor_group: actor_group, - subject: subject - ) - - %{ - resource: resource, - actor_group: actor_group, - policy: policy - } - end - - test "deletes policies for actor group", %{ - account: account, - policy: policy, - actor_group: actor_group, - subject: subject - } do - other_policy = Fixtures.Policies.create_policy(account: account, subject: subject) - - assert {:ok, 1} = delete_policies_for(actor_group, subject) - refute Repo.get(Policies.Policy, policy.id) - - assert is_nil(Repo.get(Policies.Policy, other_policy.id).deleted_at) - end - - test "deletes policies for actor group provider", %{ - account: account, - resource: resource, - policy: other_policy, - subject: subject - } do - Domain.Config.put_env_override(:outbound_email_adapter_configured?, true) - provider = Fixtures.Auth.create_email_provider(account: account) - actor_group = Fixtures.Actors.create_group(account: account, provider: provider) - - policy = - Fixtures.Policies.create_policy( - account: account, - resource: resource, - actor_group: actor_group, - subject: subject - ) - - assert {:ok, 1} = delete_policies_for(provider, subject) - refute Repo.get(Policies.Policy, policy.id) - - assert is_nil(Repo.get(Policies.Policy, other_policy.id).deleted_at) - end - - test "deletes policies for resource", %{ - account: account, - policy: policy, - resource: resource, - subject: subject - } do - other_policy = Fixtures.Policies.create_policy(account: account, subject: subject) - - assert {:ok, _deleted_policy} = delete_policies_for(resource, subject) - refute Repo.get(Policies.Policy, policy.id) - - assert is_nil(Repo.get(Policies.Policy, other_policy.id).deleted_at) - end - - test "returns error when subject has no permission to delete policies", %{ - resource: resource, - subject: subject - } do - subject = Fixtures.Auth.remove_permissions(subject) - - assert delete_policies_for(resource, subject) == - {:error, - {:unauthorized, - [ - reason: :missing_permissions, - missing_permissions: [ - %Domain.Auth.Permission{resource: Domain.Policies.Policy, action: :manage} - ] - ]}} - end - - test "does not do anything on state conflict", %{ - resource: resource, - actor_group: actor_group, - subject: subject - } do - assert {:ok, _count} = delete_policies_for(resource, subject) - assert delete_policies_for(actor_group, subject) == {:ok, 0} - assert delete_policies_for(resource, subject) == {:ok, 0} - end - - test "does not delete policies outside of account", %{ - resource: resource - } do - subject = Fixtures.Auth.create_subject() - assert delete_policies_for(resource, subject) == {:ok, 0} - end - end - describe "filter_by_conforming_policies_for_client/2" do test "returns empty list when there are no policies", %{} do client = Fixtures.Clients.create_client() diff --git a/elixir/apps/domain/test/domain/relays_test.exs b/elixir/apps/domain/test/domain/relays_test.exs index 37a2d4902..b84efddad 100644 --- a/elixir/apps/domain/test/domain/relays_test.exs +++ b/elixir/apps/domain/test/domain/relays_test.exs @@ -363,7 +363,6 @@ defmodule Domain.RelaysTest do assert delete_group(group, subject) == {:error, :unauthorized} end - # TODO: HARD-DELETE - This test should be moved to Tokens since it holds the FK test "deletes all tokens when group is deleted", %{account: account, subject: subject} do group = Fixtures.Relays.create_group(account: account) Fixtures.Relays.create_token(account: account, group: group) @@ -380,7 +379,6 @@ defmodule Domain.RelaysTest do assert length(tokens) == 0 end - # TODO: HARD-DELETE - This test should be moved to Tokens since it holds the FK test "deletes all relays when group is deleted", %{account: account, subject: subject} do group = Fixtures.Relays.create_group(account: account) Fixtures.Relays.create_relay(account: account, group: group) @@ -395,7 +393,6 @@ defmodule Domain.RelaysTest do assert length(relays) == 0 end - # TODO: HARD-DELETE - This test should be moved to Tokens since it holds the FK test "deletes associated tokens", %{ account: account, subject: subject diff --git a/elixir/apps/domain/test/domain/repo/filter_test.exs b/elixir/apps/domain/test/domain/repo/filter_test.exs index b93048b9b..eae5c6c71 100644 --- a/elixir/apps/domain/test/domain/repo/filter_test.exs +++ b/elixir/apps/domain/test/domain/repo/filter_test.exs @@ -29,7 +29,7 @@ defmodule Domain.Repo.FilterTest do type: :boolean, name: :bool, fun: fn queryable -> - {queryable, dynamic([accounts: accounts], is_nil(accounts.deleted_at))} + {queryable, dynamic([accounts: accounts], is_nil(accounts.disabled_at))} end } } @@ -41,7 +41,7 @@ defmodule Domain.Repo.FilterTest do |> inspect() == """ #Ecto.Query\ + where: is_nil(a0.disabled_at)>\ """ assert {queryable, dynamic} = build_dynamic(queryable, [bool: false], filters, nil) @@ -51,7 +51,7 @@ defmodule Domain.Repo.FilterTest do |> inspect() == """ #Ecto.Query\ + where: not is_nil(a0.disabled_at)>\ """ end diff --git a/elixir/apps/domain/test/domain/repo_test.exs b/elixir/apps/domain/test/domain/repo_test.exs index 280a53116..a710f0d7a 100644 --- a/elixir/apps/domain/test/domain/repo_test.exs +++ b/elixir/apps/domain/test/domain/repo_test.exs @@ -269,26 +269,27 @@ defmodule Domain.RepoTest do end end - test "allows to set custom order", %{ - account: account, - query_module: query_module, - queryable: queryable - } do - dt1 = ~U[2000-01-01 00:00:00.000000Z] - dt2 = ~U[2000-01-02 00:00:00.000000Z] + # TODO: BRIAN - Check if this test can be updated to use something other than deleted_at + # test "allows to set custom order", %{ + # account: account, + # query_module: query_module, + # queryable: queryable + # } do + # dt1 = ~U[2000-01-01 00:00:00.000000Z] + # dt2 = ~U[2000-01-02 00:00:00.000000Z] - Fixtures.Actors.create_actor(account: account) - |> Fixtures.Actors.update(deleted_at: dt1) + # Fixtures.Actors.create_actor(account: account) + # |> Fixtures.Actors.update(deleted_at: dt1) - Fixtures.Actors.create_actor(account: account) - |> Fixtures.Actors.update(deleted_at: dt2) + # Fixtures.Actors.create_actor(account: account) + # |> Fixtures.Actors.update(deleted_at: dt2) - assert {:ok, [%{deleted_at: ^dt1}, %{deleted_at: ^dt2}], _metadata} = - list(queryable, query_module, order_by: [{:actors, :asc, :deleted_at}]) + # assert {:ok, [%{deleted_at: ^dt1}, %{deleted_at: ^dt2}], _metadata} = + # list(queryable, query_module, order_by: [{:actors, :asc, :deleted_at}]) - assert {:ok, [%{deleted_at: ^dt2}, %{deleted_at: ^dt1}], _metadata} = - list(queryable, query_module, order_by: [{:actors, :desc, :deleted_at}]) - end + # assert {:ok, [%{deleted_at: ^dt2}, %{deleted_at: ^dt1}], _metadata} = + # list(queryable, query_module, order_by: [{:actors, :desc, :deleted_at}]) + # end test "allows to filter results" do query_module = Domain.Accounts.Account.Query diff --git a/elixir/apps/domain/test/domain/resources_test.exs b/elixir/apps/domain/test/domain/resources_test.exs index 2e32312b1..795798db9 100644 --- a/elixir/apps/domain/test/domain/resources_test.exs +++ b/elixir/apps/domain/test/domain/resources_test.exs @@ -103,122 +103,6 @@ defmodule Domain.ResourcesTest do end end - describe "fetch_resource_by_id_or_persistent_id/3" do - test "returns error when resource does not exist", %{subject: subject} do - assert fetch_resource_by_id_or_persistent_id(Ecto.UUID.generate(), subject) == - {:error, :not_found} - end - - test "returns error when UUID is invalid", %{subject: subject} do - assert fetch_resource_by_id_or_persistent_id("foo", subject) == {:error, :not_found} - end - - test "returns resource for account admin", %{account: account, subject: subject} do - resource = Fixtures.Resources.create_resource(account: account) - - assert {:ok, fetched_resource} = fetch_resource_by_id_or_persistent_id(resource.id, subject) - assert fetched_resource.id == resource.id - - assert {:ok, fetched_resource} = - fetch_resource_by_id_or_persistent_id(resource.persistent_id, subject) - - assert fetched_resource.id == resource.id - end - - test "returns authorized resource for account user", %{ - account: account - } do - actor_group = Fixtures.Actors.create_group(account: account) - actor = Fixtures.Actors.create_actor(type: :account_user, account: account) - Fixtures.Actors.create_membership(account: account, actor: actor, group: actor_group) - - identity = Fixtures.Auth.create_identity(account: account, actor: actor) - subject = Fixtures.Auth.create_subject(identity: identity) - - resource = Fixtures.Resources.create_resource(account: account) - - assert fetch_resource_by_id_or_persistent_id(resource.id, subject) == {:error, :not_found} - - assert fetch_resource_by_id_or_persistent_id(resource.persistent_id, subject) == - {:error, :not_found} - - policy = - Fixtures.Policies.create_policy( - account: account, - actor_group: actor_group, - resource: resource - ) - - assert {:ok, fetched_resource} = fetch_resource_by_id_or_persistent_id(resource.id, subject) - assert fetched_resource.id == resource.id - assert Enum.map(fetched_resource.authorized_by_policies, & &1.id) == [policy.id] - - assert {:ok, fetched_resource} = - fetch_resource_by_id_or_persistent_id(resource.persistent_id, subject) - - assert fetched_resource.id == resource.id - assert Enum.map(fetched_resource.authorized_by_policies, & &1.id) == [policy.id] - end - - test "does not return deleted resources", %{account: account, subject: subject} do - resource = Fixtures.Resources.create_resource(account: account) - delete_resource(resource, subject) - - assert {:error, :not_found} = fetch_resource_by_id_or_persistent_id(resource.id, subject) - - assert {:error, :not_found} = - fetch_resource_by_id_or_persistent_id(resource.persistent_id, subject) - end - - test "does not return resources in other accounts", %{subject: subject} do - resource = Fixtures.Resources.create_resource() - assert fetch_resource_by_id_or_persistent_id(resource.id, subject) == {:error, :not_found} - - assert fetch_resource_by_id_or_persistent_id(resource.persistent_id, subject) == - {:error, :not_found} - end - - test "returns error when subject has no permission to view resources", %{subject: subject} do - subject = Fixtures.Auth.remove_permissions(subject) - - assert fetch_resource_by_id_or_persistent_id(Ecto.UUID.generate(), subject) == - {:error, - {:unauthorized, - reason: :missing_permissions, - missing_permissions: [ - {:one_of, - [ - Resources.Authorizer.manage_resources_permission(), - Resources.Authorizer.view_available_resources_permission() - ]} - ]}} - end - - test "associations are preloaded when opts given", %{account: account, subject: subject} do - gateway_group = Fixtures.Gateways.create_group(account: account) - - resource = - Fixtures.Resources.create_resource( - account: account, - connections: [%{gateway_group_id: gateway_group.id}] - ) - - assert {:ok, resource} = - fetch_resource_by_id_or_persistent_id(resource.id, subject, preload: :connections) - - assert Ecto.assoc_loaded?(resource.connections) - assert length(resource.connections) == 1 - - assert {:ok, resource} = - fetch_resource_by_id_or_persistent_id(resource.persistent_id, subject, - preload: :connections - ) - - assert Ecto.assoc_loaded?(resource.connections) - assert length(resource.connections) == 1 - end - end - describe "all_authorized_resources/1" do test "returns empty list when there are no resources", %{subject: subject} do assert {:ok, []} = all_authorized_resources(subject) @@ -232,33 +116,6 @@ defmodule Domain.ResourcesTest do assert {:ok, []} = all_authorized_resources(subject) end - test "does not list deleted resources", %{ - account: account, - actor: actor, - subject: subject - } do - gateway_group = Fixtures.Gateways.create_group(account: account) - - resource = - Fixtures.Resources.create_resource( - account: account, - connections: [%{gateway_group_id: gateway_group.id}] - ) - - actor_group = Fixtures.Actors.create_group(account: account) - Fixtures.Actors.create_membership(account: account, actor: actor, group: actor_group) - - Fixtures.Policies.create_policy( - account: account, - actor_group: actor_group, - resource: resource - ) - - resource |> Ecto.Changeset.change(deleted_at: DateTime.utc_now()) |> Repo.update!() - - assert {:ok, []} = all_authorized_resources(subject) - end - test "does not list resources authorized by disabled policy", %{ account: account, actor: actor, @@ -1462,49 +1319,6 @@ defmodule Domain.ResourcesTest do end end - describe "delete_connections_for/2" do - setup %{account: account, subject: subject} do - group = Fixtures.Gateways.create_group(account: account, subject: subject) - - resource = - Fixtures.Resources.create_resource( - account: account, - connections: [%{gateway_group_id: group.id}] - ) - - %{ - group: group, - resource: resource - } - end - - test "does nothing on state conflict", %{ - group: group, - subject: subject - } do - assert delete_connections_for(group, subject) == {:ok, 1} - assert delete_connections_for(group, subject) == {:ok, 0} - end - - test "deletes connections for actor group", %{group: group, subject: subject} do - assert delete_connections_for(group, subject) == {:ok, 1} - assert Repo.aggregate(Resources.Connection.Query.by_gateway_group_id(group.id), :count) == 0 - end - - test "returns error when subject has no permission to manage resources", %{ - group: group, - subject: subject - } do - subject = Fixtures.Auth.remove_permissions(subject) - - assert delete_connections_for(group, subject) == - {:error, - {:unauthorized, - reason: :missing_permissions, - missing_permissions: [Resources.Authorizer.manage_resources_permission()]}} - end - end - describe "adapt_resource_for_version/2" do setup do account = Fixtures.Accounts.create_account() diff --git a/elixir/apps/domain/test/domain/tokens_test.exs b/elixir/apps/domain/test/domain/tokens_test.exs index 6e8d2eee5..3893c4a7d 100644 --- a/elixir/apps/domain/test/domain/tokens_test.exs +++ b/elixir/apps/domain/test/domain/tokens_test.exs @@ -424,7 +424,7 @@ defmodule Domain.TokensTest do end test "does not extend expiration of deleted tokens", %{token: token} do - token = Fixtures.Tokens.delete_token(token) + {:ok, token} = Fixtures.Tokens.delete_token(token) assert update_token(token, %{}) == {:error, :not_found} end end @@ -462,7 +462,7 @@ defmodule Domain.TokensTest do ] ]}} - refute Repo.get(Tokens.Token, token.id).deleted_at + assert Repo.get(Tokens.Token, token.id) end test "does not delete tokens that belong to other accounts", %{ @@ -531,22 +531,21 @@ defmodule Domain.TokensTest do assert {:ok, _token} = delete_token_for(subject) - refute Repo.get(Tokens.Token, token.id).deleted_at + assert Repo.get(Tokens.Token, token.id) end end - ## TODO: HARD-DELETE - This test should not be relevant after soft deletion is removed - # describe "delete_tokens_for/1" do - # test "deletes browser tokens for given identity", %{account: account} do - # actor = Fixtures.Actors.create_actor(account: account) - # identity = Fixtures.Auth.create_identity(account: account, actor: actor) - # token = Fixtures.Tokens.create_token(type: :browser, account: account, identity: identity) + describe "delete_tokens_for/1" do + test "deletes browser tokens for given identity", %{account: account} do + actor = Fixtures.Actors.create_actor(account: account) + identity = Fixtures.Auth.create_identity(account: account, actor: actor) + token = Fixtures.Tokens.create_token(type: :browser, account: account, identity: identity) - # assert {:ok, _num_tokens} = delete_tokens_for(identity) + assert {:ok, _num_tokens} = delete_tokens_for(identity) - # refute Repo.get(Tokens.Token, token.id) - # end - # end + refute Repo.get(Tokens.Token, token.id) + end + end describe "delete_tokens_for/2" do test "deletes browser tokens for given actor", %{account: account, subject: subject} do diff --git a/elixir/apps/domain/test/support/fixtures/accounts.ex b/elixir/apps/domain/test/support/fixtures/accounts.ex index 148702f89..826668d4c 100644 --- a/elixir/apps/domain/test/support/fixtures/accounts.ex +++ b/elixir/apps/domain/test/support/fixtures/accounts.ex @@ -41,7 +41,7 @@ defmodule Domain.Fixtures.Accounts do end def delete_account(%Accounts.Account{} = account) do - update_account(account, deleted_at: DateTime.utc_now()) + Repo.delete(account) end def disable_account(%Accounts.Account{} = account) do diff --git a/elixir/apps/domain/test/support/fixtures/actors.ex b/elixir/apps/domain/test/support/fixtures/actors.ex index e89073305..78bdd6369 100644 --- a/elixir/apps/domain/test/support/fixtures/actors.ex +++ b/elixir/apps/domain/test/support/fixtures/actors.ex @@ -76,11 +76,6 @@ defmodule Domain.Fixtures.Actors do group end - # TODO: HARD-DELETE - Remove after soft deletion functionality is removed - def soft_delete_group(group) do - update!(group, %{deleted_at: DateTime.utc_now()}) - end - def actor_attrs(attrs \\ %{}) do first_name = Enum.random(~w[Wade Dave Seth Riley Gilbert Jorge Dan Brian Roberto Ramon Juan]) last_name = Enum.random(~w[Robyn Traci Desiree Jon Bob Karl Joe Alberta Lynda Cara Brandi B]) @@ -166,8 +161,4 @@ defmodule Domain.Fixtures.Actors do {:ok, deleted_actor} = Domain.Actors.delete_actor(actor, subject) deleted_actor end - - def soft_delete(actor) do - update!(actor, %{deleted_at: DateTime.utc_now()}) - end end diff --git a/elixir/apps/domain/test/support/fixtures/auth.ex b/elixir/apps/domain/test/support/fixtures/auth.ex index 53104fabd..fee63869f 100644 --- a/elixir/apps/domain/test/support/fixtures/auth.ex +++ b/elixir/apps/domain/test/support/fixtures/auth.ex @@ -376,7 +376,8 @@ defmodule Domain.Fixtures.Auth do end def delete_provider(provider) do - update!(provider, deleted_at: DateTime.utc_now()) + {:ok, deleted_provider} = Repo.delete(provider) + deleted_provider end def fail_provider_sync(provider) do @@ -460,7 +461,7 @@ defmodule Domain.Fixtures.Auth do end def delete_identity(identity) do - update!(identity, deleted_at: DateTime.utc_now()) + Repo.delete!(identity) end def build_context(attrs \\ %{}) do diff --git a/elixir/apps/domain/test/support/fixtures/tokens.ex b/elixir/apps/domain/test/support/fixtures/tokens.ex index de06bd0a1..e321a9edf 100644 --- a/elixir/apps/domain/test/support/fixtures/tokens.ex +++ b/elixir/apps/domain/test/support/fixtures/tokens.ex @@ -1,6 +1,5 @@ defmodule Domain.Fixtures.Tokens do use Domain.Fixture - alias Domain.Tokens def remote_ip, do: Enum.random([unique_ipv4(), unique_ipv6()]) def user_agent, do: "iOS/12.5 (iPhone; #{unique_integer()}) connlib/0.7.412" @@ -198,9 +197,7 @@ defmodule Domain.Fixtures.Tokens do end def delete_token(token) do - token - |> Tokens.Token.Changeset.delete() - |> Domain.Repo.update!() + Domain.Repo.delete(token) end def expire_token(token) do diff --git a/elixir/apps/web/lib/web/live/actors/components.ex b/elixir/apps/web/lib/web/live/actors/components.ex index c15835552..eb7ff402a 100644 --- a/elixir/apps/web/lib/web/live/actors/components.ex +++ b/elixir/apps/web/lib/web/live/actors/components.ex @@ -29,10 +29,7 @@ defmodule Web.Actors.Components do Disabled - - Deleted - - + Active """ diff --git a/elixir/apps/web/lib/web/live/actors/edit.ex b/elixir/apps/web/lib/web/live/actors/edit.ex index d3b559034..c22329cb6 100644 --- a/elixir/apps/web/lib/web/live/actors/edit.ex +++ b/elixir/apps/web/lib/web/live/actors/edit.ex @@ -5,12 +5,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], - filter: [ - deleted?: false - ] - ) do + Actors.fetch_actor_by_id(id, socket.assigns.subject, preload: [:memberships]) do changeset = Actors.change_actor(actor) socket = diff --git a/elixir/apps/web/lib/web/live/actors/groups.ex b/elixir/apps/web/lib/web/live/actors/groups.ex index 5c8e0583f..41a470370 100644 --- a/elixir/apps/web/lib/web/live/actors/groups.ex +++ b/elixir/apps/web/lib/web/live/actors/groups.ex @@ -4,12 +4,7 @@ defmodule Web.Actors.EditGroups do def mount(%{"id" => id}, _session, socket) do with {:ok, actor} <- - Actors.fetch_actor_by_id(id, socket.assigns.subject, - preload: [:memberships], - filter: [ - deleted?: false - ] - ) do + Actors.fetch_actor_by_id(id, socket.assigns.subject, preload: [:memberships]) do current_group_ids = Enum.map(actor.memberships, & &1.group_id) socket = diff --git a/elixir/apps/web/lib/web/live/actors/service_accounts/new_identity.ex b/elixir/apps/web/lib/web/live/actors/service_accounts/new_identity.ex index c0ea04ad5..48740b21b 100644 --- a/elixir/apps/web/lib/web/live/actors/service_accounts/new_identity.ex +++ b/elixir/apps/web/lib/web/live/actors/service_accounts/new_identity.ex @@ -7,7 +7,6 @@ defmodule Web.Actors.ServiceAccounts.NewIdentity do Actors.fetch_actor_by_id(id, socket.assigns.subject, preload: [:memberships], filter: [ - deleted?: false, types: ["service_account"] ] ) do diff --git a/elixir/apps/web/lib/web/live/actors/show.ex b/elixir/apps/web/lib/web/live/actors/show.ex index c73c7cdff..4eaa8f727 100644 --- a/elixir/apps/web/lib/web/live/actors/show.ex +++ b/elixir/apps/web/lib/web/live/actors/show.ex @@ -159,15 +159,14 @@ defmodule Web.Actors.Show do <:title> {actor_type(@actor.type)}: {@actor.name} (you) - (deleted) (disabled) - <:action :if={is_nil(@actor.deleted_at)}> + <:action> <.edit_button navigate={~p"/#{@account}/actors/#{@actor}/edit"}> Edit {actor_type(@actor.type)} - <:action :if={is_nil(@actor.deleted_at) and not Actors.actor_disabled?(@actor)}> + <:action :if={not Actors.actor_disabled?(@actor)}> <.button_with_confirmation id="disable_actor" style="warning" @@ -188,7 +187,7 @@ defmodule Web.Actors.Show do Disable {actor_type(@actor.type)} - <:action :if={is_nil(@actor.deleted_at) and Actors.actor_disabled?(@actor)}> + <:action :if={Actors.actor_disabled?(@actor)}> <.button_with_confirmation id="enable_actor" style="warning" @@ -244,7 +243,7 @@ defmodule Web.Actors.Show do Each authentication identity is associated with an identity provider and is used to identify the actor upon successful authentication. - <:action :if={is_nil(@actor.deleted_at) and Enum.any?(@available_providers)}> + <:action :if={Enum.any?(@available_providers)}> <.add_button :if={@actor.type != :service_account} navigate={~p"/#{@account}/actors/users/#{@actor}/new_identity"} @@ -316,7 +315,7 @@ defmodule Web.Actors.Show do
No authentication identities to display. - + <.link class={[link_style()]} navigate={~p"/#{@account}/actors/service_accounts/#{@actor}/new_identity"} @@ -325,7 +324,7 @@ defmodule Web.Actors.Show do to authenticate this service account. - + <.link class={[link_style()]} navigate={~p"/#{@account}/actors/users/#{@actor}/new_identity"} @@ -347,7 +346,7 @@ defmodule Web.Actors.Show do Authentication tokens are used to authenticate the actor. Revoke tokens to sign the actor out of all associated client sessions. - <:action :if={is_nil(@actor.deleted_at) and @actor.type == :service_account}> + <:action :if={@actor.type == :service_account}> <.add_button :if={@actor.type == :service_account} navigate={~p"/#{@account}/actors/service_accounts/#{@actor}/new_identity"} @@ -356,7 +355,7 @@ defmodule Web.Actors.Show do - <:action :if={is_nil(@actor.deleted_at)}> + <:action> <.button_with_confirmation id="revoke_all_tokens" style="danger" @@ -581,7 +580,7 @@ defmodule Web.Actors.Show do - <.danger_zone :if={is_nil(@actor.deleted_at)}> + <.danger_zone> <:action :if={not Actors.actor_synced?(@actor) or @identities == []}> <.button_with_confirmation id="delete_actor" diff --git a/elixir/apps/web/lib/web/live/actors/users/new_identity.ex b/elixir/apps/web/lib/web/live/actors/users/new_identity.ex index a75b58693..5c5eb7112 100644 --- a/elixir/apps/web/lib/web/live/actors/users/new_identity.ex +++ b/elixir/apps/web/lib/web/live/actors/users/new_identity.ex @@ -8,7 +8,6 @@ defmodule Web.Actors.Users.NewIdentity do Actors.fetch_actor_by_id(id, socket.assigns.subject, preload: [:memberships, :identities], filter: [ - deleted?: false, types: ["account_user", "account_admin_user"] ] ) do diff --git a/elixir/apps/web/lib/web/live/clients/edit.ex b/elixir/apps/web/lib/web/live/clients/edit.ex index d3d4bb697..05909ab7a 100644 --- a/elixir/apps/web/lib/web/live/clients/edit.ex +++ b/elixir/apps/web/lib/web/live/clients/edit.ex @@ -3,8 +3,7 @@ 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), - nil <- client.deleted_at do + with {:ok, client} <- Clients.fetch_client_by_id(id, socket.assigns.subject) do changeset = Clients.change_client(client) socket = diff --git a/elixir/apps/web/lib/web/live/clients/show.ex b/elixir/apps/web/lib/web/live/clients/show.ex index f1be14c9a..16ec7f5d8 100644 --- a/elixir/apps/web/lib/web/live/clients/show.ex +++ b/elixir/apps/web/lib/web/live/clients/show.ex @@ -73,10 +73,9 @@ defmodule Web.Clients.Show do <.section> <:title> Client Details - (deleted) - <:action :if={is_nil(@client.deleted_at)}> + <:action> <.edit_button navigate={~p"/#{@account}/clients/#{@client}/edit"}> Edit Client @@ -182,7 +181,7 @@ defmodule Web.Clients.Show do Information about the device that the Client is running on. - <:action :if={is_nil(@client.deleted_at) and not is_nil(@client.verified_at)}> + <:action :if={not is_nil(@client.verified_at)}> <.button_with_confirmation id="remove_client_verification" style="danger" @@ -203,7 +202,7 @@ defmodule Web.Clients.Show do Remove verification - <:action :if={is_nil(@client.deleted_at) and is_nil(@client.verified_at)}> + <:action :if={is_nil(@client.verified_at)}> <.button_with_confirmation id="verify_client" style="warning" @@ -331,7 +330,7 @@ defmodule Web.Clients.Show do - <.danger_zone :if={is_nil(@client.deleted_at)}> + <.danger_zone> <:action> <.button_with_confirmation id="delete_client" diff --git a/elixir/apps/web/lib/web/live/gateways/show.ex b/elixir/apps/web/lib/web/live/gateways/show.ex index 9e63f1756..b3b9717d2 100644 --- a/elixir/apps/web/lib/web/live/gateways/show.ex +++ b/elixir/apps/web/lib/web/live/gateways/show.ex @@ -39,7 +39,6 @@ defmodule Web.Gateways.Show do <.section> <:title> Gateway: {@gateway.name} - (deleted) <:content> <.vertical_table id="gateway"> @@ -106,7 +105,7 @@ defmodule Web.Gateways.Show do - <.danger_zone :if={is_nil(@gateway.deleted_at)}> + <.danger_zone> <:action> <.button_with_confirmation id="delete_gateway" diff --git a/elixir/apps/web/lib/web/live/groups/edit.ex b/elixir/apps/web/lib/web/live/groups/edit.ex index 14c027c79..66fdd32cc 100644 --- a/elixir/apps/web/lib/web/live/groups/edit.ex +++ b/elixir/apps/web/lib/web/live/groups/edit.ex @@ -7,7 +7,6 @@ defmodule Web.Groups.Edit do Actors.fetch_group_by_id(id, socket.assigns.subject, preload: [:memberships], filter: [ - deleted?: false, editable?: true ] ) do 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 186e3c5f5..8c9e42123 100644 --- a/elixir/apps/web/lib/web/live/groups/edit_actors.ex +++ b/elixir/apps/web/lib/web/live/groups/edit_actors.ex @@ -8,7 +8,6 @@ defmodule Web.Groups.EditActors do Actors.fetch_group_by_id(id, socket.assigns.subject, preload: [:memberships], filter: [ - deleted?: false, editable?: true ] ) do diff --git a/elixir/apps/web/lib/web/live/groups/index.ex b/elixir/apps/web/lib/web/live/groups/index.ex index fcf216c3f..c44f95fb3 100644 --- a/elixir/apps/web/lib/web/live/groups/index.ex +++ b/elixir/apps/web/lib/web/live/groups/index.ex @@ -75,10 +75,6 @@ defmodule Web.Groups.Index do > <:col :let={group} field={{:groups, :name}} label="name" class="w-3/12"> <.group account={@account} group={group} /> - - - (deleted) - <:col :let={group} label="actors"> <.peek peek={Map.fetch!(@group_actors, group.id)}> diff --git a/elixir/apps/web/lib/web/live/groups/show.ex b/elixir/apps/web/lib/web/live/groups/show.ex index 7e057a6ac..8432213fb 100644 --- a/elixir/apps/web/lib/web/live/groups/show.ex +++ b/elixir/apps/web/lib/web/live/groups/show.ex @@ -83,9 +83,8 @@ defmodule Web.Groups.Show do <.section> <:title> Group: {@group.name} - (deleted) - <:action :if={is_nil(@group.deleted_at)}> + <:action> <.edit_button :if={Actors.group_editable?(@group)} navigate={~p"/#{@account}/groups/#{@group}/edit"} @@ -116,7 +115,7 @@ defmodule Web.Groups.Show do <.section> <:title>Actors - <:action :if={is_nil(@group.deleted_at)}> + <:action> <.edit_button :if={not Actors.group_synced?(@group) and not Actors.group_managed?(@group)} navigate={~p"/#{@account}/groups/#{@group}/edit_actors"} @@ -194,14 +193,10 @@ defmodule Web.Groups.Show do <:col :let={policy} label="status"> - <%= if is_nil(policy.deleted_at) do %> - <%= if is_nil(policy.disabled_at) do %> - Active - <% else %> - Disabled - <% end %> + <%= if is_nil(policy.disabled_at) do %> + Active <% else %> - Deleted + Disabled <% end %> <:empty> @@ -222,7 +217,7 @@ defmodule Web.Groups.Show do - <.danger_zone :if={is_nil(@group.deleted_at) and Actors.group_editable?(@group)}> + <.danger_zone :if={Actors.group_editable?(@group)}> <:action> <.button_with_confirmation id="delete_group" diff --git a/elixir/apps/web/lib/web/live/policies/edit.ex b/elixir/apps/web/lib/web/live/policies/edit.ex index 3bd26b960..afdf3d757 100644 --- a/elixir/apps/web/lib/web/live/policies/edit.ex +++ b/elixir/apps/web/lib/web/live/policies/edit.ex @@ -5,9 +5,8 @@ defmodule Web.Policies.Edit do def mount(%{"id" => id}, _session, socket) do with {:ok, policy} <- - Policies.fetch_policy_by_id_or_persistent_id(id, socket.assigns.subject, - preload: [:actor_group, :resource], - filter: [deleted?: false] + Policies.fetch_policy_by_id(id, socket.assigns.subject, + preload: [:actor_group, :resource] ) do providers = Auth.all_active_providers_for_account!(socket.assigns.account) diff --git a/elixir/apps/web/lib/web/live/policies/index.ex b/elixir/apps/web/lib/web/live/policies/index.ex index 5deae3bcf..b444a8045 100644 --- a/elixir/apps/web/lib/web/live/policies/index.ex +++ b/elixir/apps/web/lib/web/live/policies/index.ex @@ -92,14 +92,10 @@ defmodule Web.Policies.Index do <:col :let={policy} label="status"> - <%= if is_nil(policy.deleted_at) do %> - <%= if is_nil(policy.disabled_at) do %> - Active - <% else %> - Disabled - <% end %> + <%= if is_nil(policy.disabled_at) do %> + Active <% else %> - Deleted + Disabled <% end %> <:empty> diff --git a/elixir/apps/web/lib/web/live/policies/show.ex b/elixir/apps/web/lib/web/live/policies/show.ex index 1eb893b5f..38a641ce1 100644 --- a/elixir/apps/web/lib/web/live/policies/show.ex +++ b/elixir/apps/web/lib/web/live/policies/show.ex @@ -5,12 +5,10 @@ defmodule Web.Policies.Show do def mount(%{"id" => id}, _session, socket) do with {:ok, policy} <- - Policies.fetch_policy_by_id_or_persistent_id(id, socket.assigns.subject, + Policies.fetch_policy_by_id(id, socket.assigns.subject, preload: [ actor_group: [:provider], - resource: [], - replaced_by_policy: [:actor_group, :resource], - replaces_policy: [:actor_group, :resource] + resource: [] ] ) do providers = Auth.all_active_providers_for_account!(socket.assigns.account) @@ -73,23 +71,13 @@ defmodule Web.Policies.Show do <:title> <.policy_name policy={@policy} /> (disabled) - - (deleted) - - - (replaced) - - <:action :if={is_nil(@policy.deleted_at)}> + <:action> <.edit_button navigate={~p"/#{@account}/policies/#{@policy}/edit"}> Edit Policy - <:action :if={is_nil(@policy.deleted_at)}> + <:action> <.button_with_confirmation :if={is_nil(@policy.disabled_at)} id="disable" @@ -144,53 +132,12 @@ defmodule Web.Policies.Show do {@policy.id} - <.vertical_table_row :if={not is_nil(@policy.deleted_at)}> - <:label> - Persistent ID - - <:value> - {@policy.persistent_id} - - - <.vertical_table_row :if={ - not is_nil(@policy.deleted_at) and not is_nil(@policy.replaced_by_policy) - }> - <:label> - Replaced by Policy - - <:value> - <.link - navigate={~p"/#{@account}/policies/#{@policy.replaced_by_policy}"} - class={["text-accent-600"] ++ link_style()} - > - <.policy_name policy={@policy.replaced_by_policy} /> - - - - <.vertical_table_row :if={ - not is_nil(@policy.deleted_at) and not is_nil(@policy.replaces_policy) - }> - <:label> - Replaced Policy - - <:value> - <.link - navigate={~p"/#{@account}/policies/#{@policy.replaces_policy}"} - class={["text-accent-600"] ++ link_style()} - > - <.policy_name policy={@policy.replaces_policy} /> - - - <.vertical_table_row> <:label> Group <:value> <.group account={@account} group={@policy.actor_group} /> - - (deleted) - <.vertical_table_row> @@ -201,9 +148,6 @@ defmodule Web.Policies.Show do <.link navigate={~p"/#{@account}/resources/#{@policy.resource_id}"} class={link_style()}> {@policy.resource.name} - - (deleted) - <.vertical_table_row :if={@policy.conditions != []}> @@ -276,7 +220,7 @@ defmodule Web.Policies.Show do - <.danger_zone :if={is_nil(@policy.deleted_at)}> + <.danger_zone> <:action> <.button_with_confirmation id="delete_policy" @@ -309,14 +253,12 @@ defmodule Web.Policies.Show do ) when policy_id == id do {:ok, policy} = - Policies.fetch_policy_by_id_or_persistent_id( + Policies.fetch_policy_by_id( socket.assigns.policy.id, socket.assigns.subject, preload: [ actor_group: [:provider], - resource: [], - replaced_by_policy: [:actor_group, :resource], - replaces_policy: [:actor_group, :resource] + resource: [] ] ) @@ -336,9 +278,7 @@ defmodule Web.Policies.Show do policy = %{ policy | actor_group: socket.assigns.policy.actor_group, - resource: socket.assigns.policy.resource, - replaced_by_policy: socket.assigns.policy.replaced_by_policy, - replaces_policy: socket.assigns.policy.replaces_policy + resource: socket.assigns.policy.resource } {:noreply, assign(socket, policy: policy)} @@ -350,9 +290,7 @@ defmodule Web.Policies.Show do policy = %{ policy | actor_group: socket.assigns.policy.actor_group, - resource: socket.assigns.policy.resource, - replaced_by_policy: socket.assigns.policy.replaced_by_policy, - replaces_policy: socket.assigns.policy.replaces_policy + resource: socket.assigns.policy.resource } {:noreply, assign(socket, policy: policy)} 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 ab7b35ae1..da0cb044c 100644 --- a/elixir/apps/web/lib/web/live/relay_groups/edit.ex +++ b/elixir/apps/web/lib/web/live/relay_groups/edit.ex @@ -4,12 +4,7 @@ defmodule Web.RelayGroups.Edit do def mount(%{"id" => id}, _session, socket) do with true <- Accounts.self_hosted_relays_enabled?(socket.assigns.account), - {:ok, group} <- - Relays.fetch_group_by_id(id, socket.assigns.subject, - filter: [ - deleted?: false - ] - ) do + {:ok, group} <- Relays.fetch_group_by_id(id, socket.assigns.subject) do changeset = Relays.change_group(group) socket = diff --git a/elixir/apps/web/lib/web/live/relay_groups/new_token.ex b/elixir/apps/web/lib/web/live/relay_groups/new_token.ex index c3463f2d2..c586fbfd7 100644 --- a/elixir/apps/web/lib/web/live/relay_groups/new_token.ex +++ b/elixir/apps/web/lib/web/live/relay_groups/new_token.ex @@ -4,12 +4,7 @@ defmodule Web.RelayGroups.NewToken do def mount(%{"id" => id}, _session, socket) do with true <- Accounts.self_hosted_relays_enabled?(socket.assigns.account), - {:ok, group} <- - Relays.fetch_group_by_id(id, socket.assigns.subject, - filter: [ - deleted?: false - ] - ) do + {:ok, group} <- Relays.fetch_group_by_id(id, socket.assigns.subject) do {group, token, env} = if connected?(socket) do {:ok, token, encoded_token} = Relays.create_token(group, %{}, socket.assigns.subject) 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 35e3be5f8..ae18ef0e7 100644 --- a/elixir/apps/web/lib/web/live/relay_groups/show.ex +++ b/elixir/apps/web/lib/web/live/relay_groups/show.ex @@ -62,9 +62,8 @@ defmodule Web.RelayGroups.Show do <.section> <:title> Relay Instance Group: {@group.name} - (deleted) - <:action :if={not is_nil(@group.account_id) and is_nil(@group.deleted_at)}> + <:action :if={not is_nil(@group.account_id)}> <.edit_button navigate={~p"/#{@account}/relay_groups/#{@group}/edit"}> Edit Instance Group @@ -89,12 +88,12 @@ defmodule Web.RelayGroups.Show do <.section> <:title>Relays - <:action :if={not is_nil(@group.account_id) and is_nil(@group.deleted_at)}> + <:action :if={not is_nil(@group.account_id)}> <.add_button navigate={~p"/#{@account}/relay_groups/#{@group}/new_token"}> Deploy - <:action :if={is_nil(@group.deleted_at)}> + <:action> <.button_with_confirmation id="delete_site" style="danger" @@ -149,7 +148,7 @@ defmodule Web.RelayGroups.Show do - <.danger_zone :if={not is_nil(@group.account_id) and is_nil(@group.deleted_at)}> + <.danger_zone :if={not is_nil(@group.account_id)}> <:action :if={@group.account_id}> <.button_with_confirmation id="delete_relay_group" diff --git a/elixir/apps/web/lib/web/live/relays/show.ex b/elixir/apps/web/lib/web/live/relays/show.ex index dfa872182..46c9ed27e 100644 --- a/elixir/apps/web/lib/web/live/relays/show.ex +++ b/elixir/apps/web/lib/web/live/relays/show.ex @@ -44,7 +44,6 @@ defmodule Web.Relays.Show do {@relay.ipv4} - (deleted) <:content>
@@ -112,7 +111,7 @@ defmodule Web.Relays.Show do - <.danger_zone :if={is_nil(@relay.deleted_at)}> + <.danger_zone> <:action :if={@relay.account_id}> <.button_with_confirmation id="delete_relay" diff --git a/elixir/apps/web/lib/web/live/resources/components.ex b/elixir/apps/web/lib/web/live/resources/components.ex index 58550dc63..851face7c 100644 --- a/elixir/apps/web/lib/web/live/resources/components.ex +++ b/elixir/apps/web/lib/web/live/resources/components.ex @@ -10,7 +10,7 @@ defmodule Web.Resources.Components do } def fetch_resource_option(id, subject) do - {:ok, resource} = Resources.fetch_resource_by_id_or_persistent_id(id, subject) + {:ok, resource} = Resources.fetch_resource_by_id(id, subject) {:ok, resource_option(resource)} end diff --git a/elixir/apps/web/lib/web/live/resources/edit.ex b/elixir/apps/web/lib/web/live/resources/edit.ex index 77d883f86..20eab80f4 100644 --- a/elixir/apps/web/lib/web/live/resources/edit.ex +++ b/elixir/apps/web/lib/web/live/resources/edit.ex @@ -8,7 +8,6 @@ defmodule Web.Resources.Edit do Resources.fetch_resource_by_id(id, socket.assigns.subject, preload: :gateway_groups, filter: [ - deleted?: false, type: ["cidr", "dns", "ip"] ] ) do diff --git a/elixir/apps/web/lib/web/live/resources/show.ex b/elixir/apps/web/lib/web/live/resources/show.ex index 0bc6c89da..8459f8292 100644 --- a/elixir/apps/web/lib/web/live/resources/show.ex +++ b/elixir/apps/web/lib/web/live/resources/show.ex @@ -92,19 +92,8 @@ defmodule Web.Resources.Show do <.section> <:title> Resource: {@resource.name} - - - (deleted) - - - (replaced) - - <:action :if={@resource.type != :internet && is_nil(@resource.deleted_at)}> + <:action :if={@resource.type != :internet}> <.edit_button navigate={~p"/#{@account}/resources/#{@resource.id}/edit?#{@params}"}> Edit Resource @@ -119,14 +108,6 @@ defmodule Web.Resources.Show do {@resource.id} - <.vertical_table_row :if={not is_nil(@resource.deleted_at)}> - <:label> - Persistent ID - - <:value> - {@resource.persistent_id} - - <.vertical_table_row> <:label> Name @@ -212,36 +193,6 @@ defmodule Web.Resources.Show do
- <.vertical_table_row :if={ - not is_nil(@resource.deleted_at) and not is_nil(@resource.replaced_by_resource) - }> - <:label> - Replaced by Resource - - <:value> - <.link - navigate={~p"/#{@account}/resources/#{@resource.replaced_by_resource}"} - class={["text-accent-600"] ++ link_style()} - > - {@resource.replaced_by_resource.name} - - - - <.vertical_table_row :if={ - not is_nil(@resource.deleted_at) and not is_nil(@resource.replaces_resource) - }> - <:label> - Replaced Resource - - <:value> - <.link - navigate={~p"/#{@account}/resources/#{@resource.replaces_resource}"} - class={["text-accent-600"] ++ link_style()} - > - {@resource.replaces_resource.name} - - - <.vertical_table_row> <:label> Created @@ -288,14 +239,10 @@ defmodule Web.Resources.Show do <.group account={@account} group={policy.actor_group} /> <:col :let={policy} label="status"> - <%= if is_nil(policy.deleted_at) do %> - <%= if is_nil(policy.disabled_at) do %> - Active - <% else %> - Disabled - <% end %> + <%= if is_nil(policy.disabled_at) do %> + Active <% else %> - Deleted + Disabled <% end %> <:empty> @@ -372,7 +319,7 @@ defmodule Web.Resources.Show do - <.danger_zone :if={is_nil(@resource.deleted_at) and @resource.type != :internet}> + <.danger_zone :if={@resource.type != :internet}> <:action> <.button_with_confirmation id="delete_resource" @@ -409,9 +356,7 @@ defmodule Web.Resources.Show do Resources.fetch_resource_by_id(socket.assigns.resource.id, socket.assigns.subject, preload: [ :gateway_groups, - :policies, - replaced_by_resource: [], - replaces_resource: [] + :policies ] ) @@ -451,23 +396,11 @@ defmodule Web.Resources.Show do end defp fetch_resource("internet", subject) do - Resources.fetch_internet_resource(subject, - preload: [ - :gateway_groups, - replaced_by_resource: [], - replaces_resource: [] - ] - ) + Resources.fetch_internet_resource(subject, preload: [:gateway_groups]) end defp fetch_resource(id, subject) do - Resources.fetch_resource_by_id_or_persistent_id(id, subject, - preload: [ - :gateway_groups, - replaced_by_resource: [], - replaces_resource: [] - ] - ) + Resources.fetch_resource_by_id(id, subject, preload: [:gateway_groups]) end defp format_ip_stack(:dual), do: "Dual-stack (IPv4 and IPv6)" diff --git a/elixir/apps/web/lib/web/live/settings/api_clients/edit.ex b/elixir/apps/web/lib/web/live/settings/api_clients/edit.ex index 4b0313255..e3cbfab3b 100644 --- a/elixir/apps/web/lib/web/live/settings/api_clients/edit.ex +++ b/elixir/apps/web/lib/web/live/settings/api_clients/edit.ex @@ -5,8 +5,7 @@ defmodule Web.Settings.ApiClients.Edit do def mount(%{"id" => id}, _session, socket) do if Domain.Accounts.rest_api_enabled?(socket.assigns.account) do - with {:ok, actor} <- Actors.fetch_actor_by_id(id, socket.assigns.subject, preload: []), - nil <- actor.deleted_at do + with {:ok, actor} <- Actors.fetch_actor_by_id(id, socket.assigns.subject, preload: []) do changeset = Actors.change_actor(actor) socket = diff --git a/elixir/apps/web/lib/web/live/settings/api_clients/show.ex b/elixir/apps/web/lib/web/live/settings/api_clients/show.ex index 11672d49c..abf4b54af 100644 --- a/elixir/apps/web/lib/web/live/settings/api_clients/show.ex +++ b/elixir/apps/web/lib/web/live/settings/api_clients/show.ex @@ -54,9 +54,8 @@ defmodule Web.Settings.ApiClients.Show do <.section> <:title> API Client: {@actor.name} - (deleted) - <:action :if={is_nil(@actor.deleted_at)}> + <:action> <.edit_button navigate={~p"/#{@account}/settings/api_clients/#{@actor}/edit"}> Edit API Client @@ -81,7 +80,7 @@ defmodule Web.Settings.ApiClients.Show do Disable API Client - <:action :if={is_nil(@actor.deleted_at) and Actors.actor_disabled?(@actor)}> + <:action :if={Actors.actor_disabled?(@actor)}> <.button_with_confirmation id="enable" style="warning" @@ -210,7 +209,7 @@ defmodule Web.Settings.ApiClients.Show do - <.danger_zone :if={is_nil(@actor.deleted_at)}> + <.danger_zone> <:action> <.button_with_confirmation id="delete_api_client" diff --git a/elixir/apps/web/lib/web/live/settings/identity_providers/components.ex b/elixir/apps/web/lib/web/live/settings/identity_providers/components.ex index 3271ffd49..35a25a7fd 100644 --- a/elixir/apps/web/lib/web/live/settings/identity_providers/components.ex +++ b/elixir/apps/web/lib/web/live/settings/identity_providers/components.ex @@ -1,17 +1,6 @@ defmodule Web.Settings.IdentityProviders.Components do use Web, :component_library - def status(%{provider: %{deleted_at: deleted_at}} = assigns) when not is_nil(deleted_at) do - ~H""" -
- <.ping_icon color="info" /> - - Deleted - -
- """ - end - def status( %{ provider: %{ diff --git a/elixir/apps/web/lib/web/live/settings/identity_providers/google_workspace/show.ex b/elixir/apps/web/lib/web/live/settings/identity_providers/google_workspace/show.ex index 8050b80f8..7c290029f 100644 --- a/elixir/apps/web/lib/web/live/settings/identity_providers/google_workspace/show.ex +++ b/elixir/apps/web/lib/web/live/settings/identity_providers/google_workspace/show.ex @@ -10,14 +10,11 @@ defmodule Web.Settings.IdentityProviders.GoogleWorkspace.Show do Auth.fetch_identities_count_grouped_by_provider_id(socket.assigns.subject), {:ok, groups_count_by_provider_id} <- Actors.fetch_groups_count_grouped_by_provider_id(socket.assigns.subject) do - safe_to_delete_actors_count = Actors.count_synced_actors_for_provider(provider) - {:ok, assign(socket, provider: provider, identities_count_by_provider_id: identities_count_by_provider_id, groups_count_by_provider_id: groups_count_by_provider_id, - safe_to_delete_actors_count: safe_to_delete_actors_count, page_title: "Identity Provider #{provider.name}" )} else @@ -41,16 +38,15 @@ defmodule Web.Settings.IdentityProviders.GoogleWorkspace.Show do <:title> Identity Provider: {@provider.name} (disabled) - (deleted) - <:action :if={is_nil(@provider.deleted_at)}> + <:action> <.edit_button navigate={ ~p"/#{@account}/settings/identity_providers/google_workspace/#{@provider.id}/edit" }> Edit - <:action :if={is_nil(@provider.deleted_at)}> + <:action> <.button_with_confirmation :if={is_nil(@provider.disabled_at)} id="disable" @@ -95,7 +91,7 @@ defmodule Web.Settings.IdentityProviders.GoogleWorkspace.Show do <% end %> - <:action :if={is_nil(@provider.deleted_at)}> + <:action> <.button style="primary" href={ @@ -125,29 +121,6 @@ defmodule Web.Settings.IdentityProviders.GoogleWorkspace.Show do <.flash_group flash={@flash} /> - <.flash :if={@safe_to_delete_actors_count > 0} kind={:warning}> - You have {@safe_to_delete_actors_count} Actor(s) that were synced from this provider and do not have any other identities. - <.button_with_confirmation - id="delete_stale_actors" - style="danger" - icon="hero-trash-solid" - on_confirm="delete_stale_actors" - class="mt-4" - > - <:dialog_title>Confirm deletion of stale Actors - <:dialog_content> - Are you sure you want to delete all Actors that were synced synced from this provider and do not have any other identities? - - <:dialog_confirm_button> - Delete Actors - - <:dialog_cancel_button> - Cancel - - Delete Actors - - -
<.vertical_table id="provider"> <.vertical_table_row> @@ -206,7 +179,7 @@ defmodule Web.Settings.IdentityProviders.GoogleWorkspace.Show do - <.danger_zone :if={is_nil(@provider.deleted_at)}> + <.danger_zone> <:action> <.button_with_confirmation id="delete_identity_provider" @@ -240,17 +213,6 @@ defmodule Web.Settings.IdentityProviders.GoogleWorkspace.Show do push_navigate(socket, to: ~p"/#{socket.assigns.account}/settings/identity_providers")} end - def handle_event("delete_stale_actors", _params, socket) do - :ok = - Actors.delete_stale_synced_actors_for_provider( - socket.assigns.provider, - socket.assigns.subject - ) - - {:noreply, - push_navigate(socket, to: view_provider(socket.assigns.account, socket.assigns.provider))} - end - def handle_event("enable", _params, socket) do attrs = %{disabled_at: nil} {:ok, provider} = Auth.update_provider(socket.assigns.provider, attrs, socket.assigns.subject) diff --git a/elixir/apps/web/lib/web/live/settings/identity_providers/jumpcloud/show.ex b/elixir/apps/web/lib/web/live/settings/identity_providers/jumpcloud/show.ex index f9a81b67a..7d480fcf0 100644 --- a/elixir/apps/web/lib/web/live/settings/identity_providers/jumpcloud/show.ex +++ b/elixir/apps/web/lib/web/live/settings/identity_providers/jumpcloud/show.ex @@ -10,7 +10,6 @@ defmodule Web.Settings.IdentityProviders.JumpCloud.Show do Auth.fetch_identities_count_grouped_by_provider_id(socket.assigns.subject), {:ok, groups_count_by_provider_id} <- Actors.fetch_groups_count_grouped_by_provider_id(socket.assigns.subject) do - safe_to_delete_actors_count = Actors.count_synced_actors_for_provider(provider) {:ok, maybe_workos_directory} = maybe_fetch_directory(provider) {:ok, @@ -19,7 +18,6 @@ defmodule Web.Settings.IdentityProviders.JumpCloud.Show do identities_count_by_provider_id: identities_count_by_provider_id, groups_count_by_provider_id: groups_count_by_provider_id, workos_directory: maybe_workos_directory, - safe_to_delete_actors_count: safe_to_delete_actors_count, page_title: "Identity Provider #{provider.name}" )} else @@ -43,16 +41,15 @@ defmodule Web.Settings.IdentityProviders.JumpCloud.Show do <:title> Identity Provider: {@provider.name} (disabled) - (deleted) - <:action :if={is_nil(@provider.deleted_at)}> + <:action> <.edit_button navigate={ ~p"/#{@account}/settings/identity_providers/jumpcloud/#{@provider.id}/edit" }> Edit - <:action :if={is_nil(@provider.deleted_at)}> + <:action> <.button_with_confirmation :if={is_nil(@provider.disabled_at)} id="disable" @@ -97,7 +94,7 @@ defmodule Web.Settings.IdentityProviders.JumpCloud.Show do <% end %> - <:action :if={is_nil(@provider.deleted_at)}> + <:action> <.button style="primary" href={~p"/#{@account.id}/settings/identity_providers/jumpcloud/#{@provider}/redirect"} @@ -125,29 +122,6 @@ defmodule Web.Settings.IdentityProviders.JumpCloud.Show do <.flash_group flash={@flash} /> - <.flash :if={@safe_to_delete_actors_count > 0} kind={:warning}> - You have {@safe_to_delete_actors_count} Actor(s) that were synced from this provider and do not have any other identities. - <.button_with_confirmation - id="delete_stale_actors" - style="danger" - icon="hero-trash-solid" - on_confirm="delete_stale_actors" - class="mt-4" - > - <:dialog_title>Confirm deletion of stale Actors - <:dialog_content> - Are you sure you want to delete all Actors that were synced synced from this provider and do not have any other identities? - - <:dialog_confirm_button> - Delete Actors - - <:dialog_cancel_button> - Cancel - - Delete Actors - - -
<.vertical_table id="provider"> <.vertical_table_row> @@ -217,7 +191,7 @@ defmodule Web.Settings.IdentityProviders.JumpCloud.Show do - <.danger_zone :if={is_nil(@provider.deleted_at)}> + <.danger_zone> <:action> <.button_with_confirmation id="delete_identity_provider" @@ -251,17 +225,6 @@ defmodule Web.Settings.IdentityProviders.JumpCloud.Show do push_navigate(socket, to: ~p"/#{socket.assigns.account}/settings/identity_providers")} end - def handle_event("delete_stale_actors", _params, socket) do - :ok = - Actors.delete_stale_synced_actors_for_provider( - socket.assigns.provider, - socket.assigns.subject - ) - - {:noreply, - push_navigate(socket, to: view_provider(socket.assigns.account, socket.assigns.provider))} - end - def handle_event("enable", _params, socket) do attrs = %{disabled_at: nil} {:ok, provider} = Auth.update_provider(socket.assigns.provider, attrs, socket.assigns.subject) @@ -320,7 +283,7 @@ defmodule Web.Settings.IdentityProviders.JumpCloud.Show do end defp provider_active?(provider) do - is_nil(provider.deleted_at) and is_nil(provider.disabled_at) + is_nil(provider.disabled_at) end defp maybe_fetch_directory(provider) do diff --git a/elixir/apps/web/lib/web/live/settings/identity_providers/microsoft_entra/show.ex b/elixir/apps/web/lib/web/live/settings/identity_providers/microsoft_entra/show.ex index e1a2d4fb7..a75ec3fc4 100644 --- a/elixir/apps/web/lib/web/live/settings/identity_providers/microsoft_entra/show.ex +++ b/elixir/apps/web/lib/web/live/settings/identity_providers/microsoft_entra/show.ex @@ -10,14 +10,11 @@ defmodule Web.Settings.IdentityProviders.MicrosoftEntra.Show do Auth.fetch_identities_count_grouped_by_provider_id(socket.assigns.subject), {:ok, groups_count_by_provider_id} <- Actors.fetch_groups_count_grouped_by_provider_id(socket.assigns.subject) do - safe_to_delete_actors_count = Actors.count_synced_actors_for_provider(provider) - {:ok, assign(socket, provider: provider, identities_count_by_provider_id: identities_count_by_provider_id, groups_count_by_provider_id: groups_count_by_provider_id, - safe_to_delete_actors_count: safe_to_delete_actors_count, page_title: "Identity Provider #{provider.name}" )} else @@ -41,16 +38,15 @@ defmodule Web.Settings.IdentityProviders.MicrosoftEntra.Show do <:title> Identity Provider: {@provider.name} (disabled) - (deleted) - <:action :if={is_nil(@provider.deleted_at)}> + <:action> <.edit_button navigate={ ~p"/#{@account}/settings/identity_providers/microsoft_entra/#{@provider.id}/edit" }> Edit - <:action :if={is_nil(@provider.deleted_at)}> + <:action> <.button_with_confirmation :if={is_nil(@provider.disabled_at)} id="disable" @@ -95,7 +91,7 @@ defmodule Web.Settings.IdentityProviders.MicrosoftEntra.Show do <% end %> - <:action :if={is_nil(@provider.deleted_at)}> + <:action> <.button style="primary" href={~p"/#{@account.id}/settings/identity_providers/microsoft_entra/#{@provider}/redirect"} @@ -123,29 +119,6 @@ defmodule Web.Settings.IdentityProviders.MicrosoftEntra.Show do <.flash_group flash={@flash} /> - <.flash :if={@safe_to_delete_actors_count > 0} kind={:warning}> - You have {@safe_to_delete_actors_count} Actor(s) that were synced from this provider and do not have any other identities. - <.button_with_confirmation - id="delete_stale_actors" - style="danger" - icon="hero-trash-solid" - on_confirm="delete_stale_actors" - class="mt-4" - > - <:dialog_title>Confirm deletion of stale Actors - <:dialog_content> - Are you sure you want to delete all Actors that were synced synced from this provider and do not have any other identities? - - <:dialog_confirm_button> - Delete Actors - - <:dialog_cancel_button> - Cancel - - Delete Actors - - -
<.vertical_table id="provider"> <.vertical_table_row> @@ -204,7 +177,7 @@ defmodule Web.Settings.IdentityProviders.MicrosoftEntra.Show do - <.danger_zone :if={is_nil(@provider.deleted_at)}> + <.danger_zone> <:action> <.button_with_confirmation id="delete_identity_provider" @@ -238,17 +211,6 @@ defmodule Web.Settings.IdentityProviders.MicrosoftEntra.Show do push_navigate(socket, to: ~p"/#{socket.assigns.account}/settings/identity_providers")} end - def handle_event("delete_stale_actors", _params, socket) do - :ok = - Actors.delete_stale_synced_actors_for_provider( - socket.assigns.provider, - socket.assigns.subject - ) - - {:noreply, - push_navigate(socket, to: view_provider(socket.assigns.account, socket.assigns.provider))} - end - def handle_event("enable", _params, socket) do attrs = %{disabled_at: nil} {:ok, provider} = Auth.update_provider(socket.assigns.provider, attrs, socket.assigns.subject) diff --git a/elixir/apps/web/lib/web/live/settings/identity_providers/mock/show.ex b/elixir/apps/web/lib/web/live/settings/identity_providers/mock/show.ex index b1cbac1c7..394bdbb0b 100644 --- a/elixir/apps/web/lib/web/live/settings/identity_providers/mock/show.ex +++ b/elixir/apps/web/lib/web/live/settings/identity_providers/mock/show.ex @@ -10,14 +10,11 @@ defmodule Web.Settings.IdentityProviders.Mock.Show do Auth.fetch_identities_count_grouped_by_provider_id(socket.assigns.subject), {:ok, groups_count_by_provider_id} <- Actors.fetch_groups_count_grouped_by_provider_id(socket.assigns.subject) do - safe_to_delete_actors_count = Actors.count_synced_actors_for_provider(provider) - {:ok, assign(socket, provider: provider, identities_count_by_provider_id: identities_count_by_provider_id, groups_count_by_provider_id: groups_count_by_provider_id, - safe_to_delete_actors_count: safe_to_delete_actors_count, page_title: "Identity Provider #{provider.name}" )} else @@ -41,16 +38,15 @@ defmodule Web.Settings.IdentityProviders.Mock.Show do <:title> Identity Provider: {@provider.name} (disabled) - (deleted) - <:action :if={is_nil(@provider.deleted_at)}> + <:action> <.edit_button navigate={ ~p"/#{@account}/settings/identity_providers/mock/#{@provider.id}/edit" }> Edit - <:action :if={is_nil(@provider.deleted_at)}> + <:action> <.button_with_confirmation :if={is_nil(@provider.disabled_at)} id="disable" @@ -112,29 +108,6 @@ defmodule Web.Settings.IdentityProviders.Mock.Show do <.flash_group flash={@flash} /> - <.flash :if={@safe_to_delete_actors_count > 0} kind={:warning}> - You have {@safe_to_delete_actors_count} Actor(s) that were synced from this provider and do not have any other identities. - <.button_with_confirmation - id="delete_stale_actors" - style="danger" - icon="hero-trash-solid" - on_confirm="delete_stale_actors" - class="mt-4" - > - <:dialog_title>Confirm deletion of stale Actors - <:dialog_content> - Are you sure you want to delete all Actors that were synced synced from this provider and do not have any other identities? - - <:dialog_confirm_button> - Delete Actors - - <:dialog_cancel_button> - Cancel - - Delete Actors - - -
<.vertical_table id="provider"> <.vertical_table_row> @@ -209,7 +182,7 @@ defmodule Web.Settings.IdentityProviders.Mock.Show do - <.danger_zone :if={is_nil(@provider.deleted_at)}> + <.danger_zone> <:action> <.button_with_confirmation id="delete_identity_provider" @@ -243,17 +216,6 @@ defmodule Web.Settings.IdentityProviders.Mock.Show do push_navigate(socket, to: ~p"/#{socket.assigns.account}/settings/identity_providers")} end - def handle_event("delete_stale_actors", _params, socket) do - :ok = - Actors.delete_stale_synced_actors_for_provider( - socket.assigns.provider, - socket.assigns.subject - ) - - {:noreply, - push_navigate(socket, to: view_provider(socket.assigns.account, socket.assigns.provider))} - end - def handle_event("enable", _params, socket) do attrs = %{disabled_at: nil} {:ok, provider} = Auth.update_provider(socket.assigns.provider, attrs, socket.assigns.subject) diff --git a/elixir/apps/web/lib/web/live/settings/identity_providers/okta/show.ex b/elixir/apps/web/lib/web/live/settings/identity_providers/okta/show.ex index 3cc254b26..5b4862358 100644 --- a/elixir/apps/web/lib/web/live/settings/identity_providers/okta/show.ex +++ b/elixir/apps/web/lib/web/live/settings/identity_providers/okta/show.ex @@ -10,15 +10,12 @@ defmodule Web.Settings.IdentityProviders.Okta.Show do Auth.fetch_identities_count_grouped_by_provider_id(socket.assigns.subject), {:ok, groups_count_by_provider_id} <- Actors.fetch_groups_count_grouped_by_provider_id(socket.assigns.subject) do - safe_to_delete_actors_count = Actors.count_synced_actors_for_provider(provider) - {:ok, assign(socket, page_title: "Identity Provider #{provider.name}", provider: provider, identities_count_by_provider_id: identities_count_by_provider_id, - groups_count_by_provider_id: groups_count_by_provider_id, - safe_to_delete_actors_count: safe_to_delete_actors_count + groups_count_by_provider_id: groups_count_by_provider_id )} else _ -> raise Web.LiveErrors.NotFoundError @@ -41,16 +38,15 @@ defmodule Web.Settings.IdentityProviders.Okta.Show do <:title> Identity Provider: {@provider.name} (disabled) - (deleted) - <:action :if={is_nil(@provider.deleted_at)}> + <:action> <.edit_button navigate={ ~p"/#{@account}/settings/identity_providers/okta/#{@provider.id}/edit" }> Edit - <:action :if={is_nil(@provider.deleted_at)}> + <:action> <.button_with_confirmation :if={is_nil(@provider.disabled_at)} id="disable" @@ -95,7 +91,7 @@ defmodule Web.Settings.IdentityProviders.Okta.Show do <% end %> - <:action :if={is_nil(@provider.deleted_at)}> + <:action> <.button style="primary" href={~p"/#{@account.id}/settings/identity_providers/okta/#{@provider}/redirect"} @@ -123,29 +119,6 @@ defmodule Web.Settings.IdentityProviders.Okta.Show do <.flash_group flash={@flash} /> - <.flash :if={@safe_to_delete_actors_count > 0} kind={:warning}> - You have {@safe_to_delete_actors_count} Actor(s) that were synced from this provider and do not have any other identities. - <.button_with_confirmation - id="delete_stale_actors" - style="danger" - icon="hero-trash-solid" - on_confirm="delete_stale_actors" - class="mt-4" - > - <:dialog_title>Confirm deletion of stale Actors - <:dialog_content> - Are you sure you want to delete all Actors that were synced synced from this provider and do not have any other identities? - - <:dialog_confirm_button> - Delete Actors - - <:dialog_cancel_button> - Cancel - - Delete Actors - - -
<.vertical_table id="provider"> <.vertical_table_row> @@ -224,7 +197,7 @@ defmodule Web.Settings.IdentityProviders.Okta.Show do - <.danger_zone :if={is_nil(@provider.deleted_at)}> + <.danger_zone> <:action> <.button_with_confirmation id="delete_identity_provider" @@ -258,17 +231,6 @@ defmodule Web.Settings.IdentityProviders.Okta.Show do push_navigate(socket, to: ~p"/#{socket.assigns.account}/settings/identity_providers")} end - def handle_event("delete_stale_actors", _params, socket) do - :ok = - Actors.delete_stale_synced_actors_for_provider( - socket.assigns.provider, - socket.assigns.subject - ) - - {:noreply, - push_navigate(socket, to: view_provider(socket.assigns.account, socket.assigns.provider))} - end - def handle_event("enable", _params, socket) do attrs = %{disabled_at: nil} {:ok, provider} = Auth.update_provider(socket.assigns.provider, attrs, socket.assigns.subject) diff --git a/elixir/apps/web/lib/web/live/settings/identity_providers/openid_connect/show.ex b/elixir/apps/web/lib/web/live/settings/identity_providers/openid_connect/show.ex index 1deef0cd9..ec3f206b8 100644 --- a/elixir/apps/web/lib/web/live/settings/identity_providers/openid_connect/show.ex +++ b/elixir/apps/web/lib/web/live/settings/identity_providers/openid_connect/show.ex @@ -1,16 +1,13 @@ defmodule Web.Settings.IdentityProviders.OpenIDConnect.Show do use Web, :live_view import Web.Settings.IdentityProviders.Components - alias Domain.{Auth, Actors} + alias Domain.Auth def mount(%{"provider_id" => provider_id}, _session, socket) do with {:ok, provider} <- Auth.fetch_provider_by_id(provider_id, socket.assigns.subject) do - safe_to_delete_actors_count = Actors.count_synced_actors_for_provider(provider) - socket = assign(socket, provider: provider, - safe_to_delete_actors_count: safe_to_delete_actors_count, page_title: "Identity Provider #{provider.name}" ) @@ -35,16 +32,15 @@ defmodule Web.Settings.IdentityProviders.OpenIDConnect.Show do <:title> Identity Provider: {@provider.name} (disabled) - (deleted) - <:action :if={is_nil(@provider.deleted_at)}> + <:action> <.edit_button navigate={ ~p"/#{@account}/settings/identity_providers/openid_connect/#{@provider}/edit" }> Edit - <:action :if={is_nil(@provider.deleted_at)}> + <:action> <.button_with_confirmation :if={is_nil(@provider.disabled_at)} id="disable" @@ -87,7 +83,7 @@ defmodule Web.Settings.IdentityProviders.OpenIDConnect.Show do Enable - <:action :if={is_nil(@provider.deleted_at)}> + <:action> <.button style="primary" href={~p"/#{@account.id}/settings/identity_providers/openid_connect/#{@provider}/redirect"} @@ -102,29 +98,6 @@ defmodule Web.Settings.IdentityProviders.OpenIDConnect.Show do <.flash_group flash={@flash} /> - <.flash :if={@safe_to_delete_actors_count > 0} kind={:warning}> - You have {@safe_to_delete_actors_count} Actor(s) that were synced from this provider and do not have any other identities. - <.button_with_confirmation - id="delete_stale_actors" - style="danger" - icon="hero-trash-solid" - on_confirm="delete_stale_actors" - class="mt-4" - > - <:dialog_title>Confirm deletion of stale Actors - <:dialog_content> - Are you sure you want to delete all Actors that were synced synced from this provider and do not have any other identities? - - <:dialog_confirm_button> - Delete Actors - - <:dialog_cancel_button> - Cancel - - Delete Actors - - -
<.vertical_table id="provider"> <.vertical_table_row> @@ -179,7 +152,7 @@ defmodule Web.Settings.IdentityProviders.OpenIDConnect.Show do
- <.danger_zone :if={is_nil(@provider.deleted_at)}> + <.danger_zone> <:action> <.button_with_confirmation id="delete_identity_provider" @@ -213,17 +186,6 @@ defmodule Web.Settings.IdentityProviders.OpenIDConnect.Show do push_navigate(socket, to: ~p"/#{socket.assigns.account}/settings/identity_providers")} end - def handle_event("delete_stale_actors", _params, socket) do - :ok = - Actors.delete_stale_synced_actors_for_provider( - socket.assigns.provider, - socket.assigns.subject - ) - - {:noreply, - push_navigate(socket, to: view_provider(socket.assigns.account, socket.assigns.provider))} - end - def handle_event("enable", _params, socket) do attrs = %{disabled_at: nil} {:ok, provider} = Auth.update_provider(socket.assigns.provider, attrs, socket.assigns.subject) diff --git a/elixir/apps/web/lib/web/live/settings/identity_providers/system/show.ex b/elixir/apps/web/lib/web/live/settings/identity_providers/system/show.ex index 298b0678f..2f183c37d 100644 --- a/elixir/apps/web/lib/web/live/settings/identity_providers/system/show.ex +++ b/elixir/apps/web/lib/web/live/settings/identity_providers/system/show.ex @@ -21,9 +21,7 @@ defmodule Web.Settings.IdentityProviders.System.Show do Identity Providers Settings - <.breadcrumb path={ - ~p"/#{@account}/settings/identity_providers/google_workspace//DF43E951-7DFB-4921-8F7F-BF0F8D31FA89" - }> + <.breadcrumb path={~p"/#{@account}/settings/identity_providers/system/#{@provider}"}> {@provider.name} @@ -32,9 +30,8 @@ defmodule Web.Settings.IdentityProviders.System.Show do <:title> Identity Provider: {@provider.name} (disabled) - (deleted) - <:action :if={is_nil(@provider.deleted_at)}> + <:action> <.button_with_confirmation :if={is_nil(@provider.disabled_at)} id="disable" diff --git a/elixir/apps/web/lib/web/live/sites/edit.ex b/elixir/apps/web/lib/web/live/sites/edit.ex index 44208b806..de3fd3e56 100644 --- a/elixir/apps/web/lib/web/live/sites/edit.ex +++ b/elixir/apps/web/lib/web/live/sites/edit.ex @@ -3,8 +3,7 @@ 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, filter: [deleted?: false]) do + with {:ok, group} <- Gateways.fetch_group_by_id(id, socket.assigns.subject) do changeset = Gateways.change_group(group) socket = diff --git a/elixir/apps/web/lib/web/live/sites/gateways/index.ex b/elixir/apps/web/lib/web/live/sites/gateways/index.ex index 7be37a04a..d445ef3fb 100644 --- a/elixir/apps/web/lib/web/live/sites/gateways/index.ex +++ b/elixir/apps/web/lib/web/live/sites/gateways/index.ex @@ -69,7 +69,7 @@ defmodule Web.Sites.Gateways.Index do Gateways deployed to the Internet Site will be used for full-route tunneling of traffic that doesn't match a more specific Resource. - <:help :if={is_nil(@group.deleted_at) and @group.managed_by == :account}> + <:help :if={@group.managed_by == :account}> Deploy gateways to terminate connections to your site's resources. All gateways deployed within a site must be able to reach all its resources. @@ -108,7 +108,7 @@ defmodule Web.Sites.Gateways.Index do Deploy a Gateway to the Internet Site. - + <.link class={[link_style()]} navigate={~p"/#{@account}/sites/#{@group}/new_token"}> Deploy a Gateway to connect Resources. diff --git a/elixir/apps/web/lib/web/live/sites/new_token.ex b/elixir/apps/web/lib/web/live/sites/new_token.ex index 80953cad9..b4e4913f4 100644 --- a/elixir/apps/web/lib/web/live/sites/new_token.ex +++ b/elixir/apps/web/lib/web/live/sites/new_token.ex @@ -4,11 +4,7 @@ defmodule Web.Sites.NewToken do def mount(%{"id" => id}, _session, socket) do with {:ok, group} <- - Gateways.fetch_group_by_id(id, socket.assigns.subject, - filter: [ - deleted?: false - ] - ) do + Gateways.fetch_group_by_id(id, socket.assigns.subject) do {group, token, env} = if connected?(socket) do {:ok, token, encoded_token} = Gateways.create_token(group, %{}, socket.assigns.subject) diff --git a/elixir/apps/web/lib/web/live/sites/show.ex b/elixir/apps/web/lib/web/live/sites/show.ex index 64bad2188..799598a64 100644 --- a/elixir/apps/web/lib/web/live/sites/show.ex +++ b/elixir/apps/web/lib/web/live/sites/show.ex @@ -25,11 +25,7 @@ defmodule Web.Sites.Show do defp mount_page(socket, %{managed_by: :system, name: "Internet"} = group) do with {:ok, resource} <- Resources.fetch_internet_resource(socket.assigns.subject, - preload: [ - :gateway_groups, - replaced_by_resource: [], - replaces_resource: [] - ] + preload: [:gateway_groups] ) do socket = socket @@ -177,10 +173,9 @@ defmodule Web.Sites.Show do <.section> <:title> Site: {@group.name} - (deleted) - <:action :if={is_nil(@group.deleted_at) and @group.managed_by == :account}> + <:action :if={@group.managed_by == :account}> <.edit_button navigate={~p"/#{@account}/sites/#{@group}/edit"}> Edit Site @@ -216,12 +211,12 @@ defmodule Web.Sites.Show do <:action> <.docs_action path="/deploy/gateways" /> - <:action :if={is_nil(@group.deleted_at)}> + <:action> <.add_button navigate={~p"/#{@account}/sites/#{@group}/new_token"}> Deploy Gateway - <:action :if={is_nil(@group.deleted_at)}> + <:action> <.button_with_confirmation id="revoke_all_tokens" style="danger" @@ -245,7 +240,7 @@ defmodule Web.Sites.Show do <:help :if={@group.managed_by == :system and @group.name == "Internet"}> Gateways deployed to the Internet Site are used to tunnel all traffic that doesn't match any specific Resource. - <:help :if={is_nil(@group.deleted_at) and @group.managed_by == :account}> + <:help :if={@group.managed_by == :account}> Deploy gateways to terminate connections to your site's resources. All gateways deployed within a site must be able to reach all its resources. @@ -298,7 +293,7 @@ defmodule Web.Sites.Show do Deploy a Gateway to the Internet Site. - + <.link class={[link_style()]} navigate={~p"/#{@account}/sites/#{@group}/new_token"} @@ -318,7 +313,7 @@ defmodule Web.Sites.Show do <:title> Resources - <:action :if={is_nil(@group.deleted_at)}> + <:action> <.add_button navigate={~p"/#{@account}/resources/new?site_id=#{@group}"}> Add Resource @@ -420,14 +415,10 @@ defmodule Web.Sites.Show do <.group account={@account} group={policy.actor_group} /> <:col :let={policy} label="status"> - <%= if is_nil(policy.deleted_at) do %> - <%= if is_nil(policy.disabled_at) do %> - Active - <% else %> - Disabled - <% end %> + <%= if is_nil(policy.disabled_at) do %> + Active <% else %> - Deleted + Disabled <% end %> <:empty> @@ -451,7 +442,7 @@ defmodule Web.Sites.Show do - <.danger_zone :if={is_nil(@group.deleted_at) and @group.managed_by == :account}> + <.danger_zone :if={@group.managed_by == :account}> <:action> <.button_with_confirmation id="delete_site" diff --git a/elixir/apps/web/test/web/live/settings/identity_providers/google_workspace/show_test.exs b/elixir/apps/web/test/web/live/settings/identity_providers/google_workspace/show_test.exs index 9782c15c6..9e571bedd 100644 --- a/elixir/apps/web/test/web/live/settings/identity_providers/google_workspace/show_test.exs +++ b/elixir/apps/web/test/web/live/settings/identity_providers/google_workspace/show_test.exs @@ -36,23 +36,6 @@ defmodule Web.Live.Settings.IdentityProviders.GoogleWorkspace.ShowTest do }}} end - test "renders deleted provider without action buttons", %{ - account: account, - provider: provider, - identity: identity, - conn: conn - } do - provider = Fixtures.Auth.delete_provider(provider) - - {:ok, _lv, html} = - conn - |> authorize_conn(identity) - |> live(~p"/#{account}/settings/identity_providers/google_workspace/#{provider}") - - assert html =~ "(deleted)" - assert active_buttons(html) == [] - end - test "renders breadcrumbs item", %{ account: account, provider: provider, diff --git a/elixir/apps/web/test/web/live/settings/identity_providers/jumpcloud/show_test.exs b/elixir/apps/web/test/web/live/settings/identity_providers/jumpcloud/show_test.exs index 6a704d1af..1202fea37 100644 --- a/elixir/apps/web/test/web/live/settings/identity_providers/jumpcloud/show_test.exs +++ b/elixir/apps/web/test/web/live/settings/identity_providers/jumpcloud/show_test.exs @@ -37,27 +37,6 @@ defmodule Web.Live.Settings.IdentityProviders.JumpCloud.ShowTest do }}} end - test "renders deleted provider without action buttons", %{ - account: account, - provider: provider, - identity: identity, - conn: conn - } do - provider = Fixtures.Auth.delete_provider(provider) - - bypass = Bypass.open() - WorkOSDirectory.override_base_url("http://localhost:#{bypass.port}") - WorkOSDirectory.mock_list_directories_endpoint(bypass) - - {:ok, _lv, html} = - conn - |> authorize_conn(identity) - |> live(~p"/#{account}/settings/identity_providers/jumpcloud/#{provider}") - - assert html =~ "(deleted)" - assert active_buttons(html) == [] - end - test "renders breadcrumbs item", %{ account: account, provider: provider, diff --git a/elixir/apps/web/test/web/live/settings/identity_providers/microsoft_entra/show_test.exs b/elixir/apps/web/test/web/live/settings/identity_providers/microsoft_entra/show_test.exs index d1293d601..6bf7abf4b 100644 --- a/elixir/apps/web/test/web/live/settings/identity_providers/microsoft_entra/show_test.exs +++ b/elixir/apps/web/test/web/live/settings/identity_providers/microsoft_entra/show_test.exs @@ -36,23 +36,6 @@ defmodule Web.Live.Settings.IdentityProviders.MicrosoftEntra.ShowTest do }}} end - test "renders deleted provider without action buttons", %{ - account: account, - provider: provider, - identity: identity, - conn: conn - } do - provider = Fixtures.Auth.delete_provider(provider) - - {:ok, _lv, html} = - conn - |> authorize_conn(identity) - |> live(~p"/#{account}/settings/identity_providers/microsoft_entra/#{provider}") - - assert html =~ "(deleted)" - assert active_buttons(html) == [] - end - test "renders breadcrumbs item", %{ account: account, provider: provider, diff --git a/elixir/apps/web/test/web/live/settings/identity_providers/okta/show_test.exs b/elixir/apps/web/test/web/live/settings/identity_providers/okta/show_test.exs index 5fb1884dc..71b764fbf 100644 --- a/elixir/apps/web/test/web/live/settings/identity_providers/okta/show_test.exs +++ b/elixir/apps/web/test/web/live/settings/identity_providers/okta/show_test.exs @@ -36,23 +36,6 @@ defmodule Web.Live.Settings.IdentityProviders.Okta.ShowTest do }}} end - test "renders deleted provider without action buttons", %{ - account: account, - provider: provider, - identity: identity, - conn: conn - } do - provider = Fixtures.Auth.delete_provider(provider) - - {:ok, _lv, html} = - conn - |> authorize_conn(identity) - |> live(~p"/#{account}/settings/identity_providers/okta/#{provider}") - - assert html =~ "(deleted)" - assert active_buttons(html) == [] - end - test "renders breadcrumbs item", %{ account: account, provider: provider, diff --git a/elixir/apps/web/test/web/live/settings/identity_providers/openid_connect/show_test.exs b/elixir/apps/web/test/web/live/settings/identity_providers/openid_connect/show_test.exs index c09cef8e1..d6b98f6a0 100644 --- a/elixir/apps/web/test/web/live/settings/identity_providers/openid_connect/show_test.exs +++ b/elixir/apps/web/test/web/live/settings/identity_providers/openid_connect/show_test.exs @@ -35,23 +35,6 @@ defmodule Web.Live.Settings.IdentityProviders.OpenIDConnect.ShowTest do }}} end - test "renders deleted provider without action buttons", %{ - account: account, - provider: provider, - identity: identity, - conn: conn - } do - provider = Fixtures.Auth.delete_provider(provider) - - {:ok, _lv, html} = - conn - |> authorize_conn(identity) - |> live(~p"/#{account}/settings/identity_providers/openid_connect/#{provider}") - - assert html =~ "(deleted)" - assert active_buttons(html) == [] - end - test "renders breadcrumbs item", %{ account: account, provider: provider, diff --git a/elixir/apps/web/test/web/live/settings/identity_providers/system/show_test.exs b/elixir/apps/web/test/web/live/settings/identity_providers/system/show_test.exs index 713cbe578..609ff20b4 100644 --- a/elixir/apps/web/test/web/live/settings/identity_providers/system/show_test.exs +++ b/elixir/apps/web/test/web/live/settings/identity_providers/system/show_test.exs @@ -33,23 +33,6 @@ defmodule Web.Live.Settings.IdentityProviders.System.ShowTest do }}} end - test "renders deleted provider without action buttons", %{ - account: account, - identity: identity, - conn: conn - } do - provider = Fixtures.Auth.create_userpass_provider(account: account) - provider = Fixtures.Auth.delete_provider(provider) - - {:ok, _lv, html} = - conn - |> authorize_conn(identity) - |> live(~p"/#{account}/settings/identity_providers/system/#{provider}") - - assert html =~ "(deleted)" - assert active_buttons(html) == [] - end - test "renders breadcrumbs item", %{ account: account, provider: provider, diff --git a/scripts/tests/lib.sh b/scripts/tests/lib.sh index 69acbe147..370b43036 100755 --- a/scripts/tests/lib.sh +++ b/scripts/tests/lib.sh @@ -41,10 +41,10 @@ function api_send_reject_access() { Application.ensure_all_started(:domain) account_id = \"c89bcc8c-9392-4dae-a40d-888aef6d28e0\" -[gateway_group] = Domain.Gateways.Group.Query.not_deleted() |> Domain.Gateways.Group.Query.by_account_id(account_id) |> Domain.Gateways.Group.Query.by_name(\"$site_name\") |> Domain.Repo.all() +[gateway_group] = Domain.Gateways.Group.Query.all() |> Domain.Gateways.Group.Query.by_account_id(account_id) |> Domain.Gateways.Group.Query.by_name(\"$site_name\") |> Domain.Repo.all() [gateway_id | _] = Domain.Gateways.Presence.Group.list(gateway_group.id) |> Map.keys() [client_id | _] = Domain.Clients.Presence.Account.list(account_id) |> Map.keys() -[resource] = Domain.Resources.Resource.Query.not_deleted() |> Domain.Resources.Resource.Query.by_account_id(account_id) |> Domain.Repo.all() |> Enum.filter(&(&1.name == \"$resource_name\")) +[resource] = Domain.Resources.Resource.Query.all() |> Domain.Resources.Resource.Query.by_account_id(account_id) |> Domain.Repo.all() |> Enum.filter(&(&1.name == \"$resource_name\")) Domain.PubSub.Account.broadcast(account_id, {{:reject_access, gateway_id}, client_id, resource.id}) "