diff --git a/lib/wanderer_app/api/access_list_member.ex b/lib/wanderer_app/api/access_list_member.ex index 9d05afb8..39155e14 100644 --- a/lib/wanderer_app/api/access_list_member.ex +++ b/lib/wanderer_app/api/access_list_member.ex @@ -104,6 +104,12 @@ defmodule WandererApp.Api.AccessListMember do end end + postgres do + references do + reference :access_list, on_delete: :delete + end + end + identities do identity :uniq_acl_character_id, [:access_list_id, :eve_character_id] do pre_check?(true) diff --git a/lib/wanderer_app/api/map_access_list.ex b/lib/wanderer_app/api/map_access_list.ex index 61302ec7..98b3bb28 100644 --- a/lib/wanderer_app/api/map_access_list.ex +++ b/lib/wanderer_app/api/map_access_list.ex @@ -44,6 +44,13 @@ defmodule WandererApp.Api.MapAccessList do belongs_to :access_list, WandererApp.Api.AccessList, primary_key?: true, allow_nil?: false end + postgres do + references do + reference :map, on_delete: :delete + reference :access_list, on_delete: :delete + end + end + identities do identity :unique_map_acl, [:map_id, :access_list_id] do pre_check?(false) diff --git a/lib/wanderer_app_web/live/access_lists/access_lists_live.ex b/lib/wanderer_app_web/live/access_lists/access_lists_live.ex index 428e66f6..a0e38b1e 100755 --- a/lib/wanderer_app_web/live/access_lists/access_lists_live.ex +++ b/lib/wanderer_app_web/live/access_lists/access_lists_live.ex @@ -238,8 +238,8 @@ defmodule WandererAppWeb.AccessListsLive do def handle_event("delete-acl", %{"id" => acl_id} = _params, socket) do case socket.assigns.access_lists |> Enum.find(&(&1.id == acl_id)) - |> WandererApp.Api.AccessList.destroy() do - {:ok, _acl} -> + |> WandererApp.Api.AccessList.destroy!() do + :ok -> Phoenix.PubSub.broadcast( WandererApp.PubSub, "acls:#{acl_id}", @@ -252,7 +252,7 @@ defmodule WandererAppWeb.AccessListsLive do socket |> assign(access_lists: access_lists |> Enum.map(fn acl -> map_ui_acl(acl, nil) end))} - _error -> + error -> {:noreply, socket |> put_flash( @@ -261,7 +261,7 @@ defmodule WandererAppWeb.AccessListsLive do )} end rescue - _ -> + _error -> {:noreply, socket |> put_flash( diff --git a/priv/repo/migrations/20240922090429_install_ash-functions_extension_4.exs b/priv/repo/migrations/20240922090429_install_ash-functions_extension_4.exs new file mode 100644 index 00000000..a84cbb9b --- /dev/null +++ b/priv/repo/migrations/20240922090429_install_ash-functions_extension_4.exs @@ -0,0 +1,54 @@ +defmodule WandererApp.Repo.Migrations.InstallAshFunctionsExtension420240922090427 do + @moduledoc """ + Installs any extensions that are mentioned in the repo's `installed_extensions/0` callback + + This file was autogenerated with `mix ash_postgres.generate_migrations` + """ + + use Ecto.Migration + + def up do + execute(""" + CREATE OR REPLACE FUNCTION uuid_generate_v7() + RETURNS UUID + AS $$ + DECLARE + timestamp TIMESTAMPTZ; + microseconds INT; + BEGIN + timestamp = clock_timestamp(); + microseconds = (cast(extract(microseconds FROM timestamp)::INT - (floor(extract(milliseconds FROM timestamp))::INT * 1000) AS DOUBLE PRECISION) * 4.096)::INT; + + RETURN encode( + set_byte( + set_byte( + overlay(uuid_send(gen_random_uuid()) placing substring(int8send(floor(extract(epoch FROM timestamp) * 1000)::BIGINT) FROM 3) FROM 1 FOR 6 + ), + 6, (b'0111' || (microseconds >> 8)::bit(4))::bit(8)::int + ), + 7, microseconds::bit(8)::int + ), + 'hex')::UUID; + END + $$ + LANGUAGE PLPGSQL + VOLATILE; + """) + + execute(""" + CREATE OR REPLACE FUNCTION timestamp_from_uuid_v7(_uuid uuid) + RETURNS TIMESTAMP WITHOUT TIME ZONE + AS $$ + SELECT to_timestamp(('x0000' || substr(_uuid::TEXT, 1, 8) || substr(_uuid::TEXT, 10, 4))::BIT(64)::BIGINT::NUMERIC / 1000); + $$ + LANGUAGE SQL + IMMUTABLE PARALLEL SAFE STRICT; + """) + end + + def down do + # Uncomment this if you actually want to uninstall the extensions + # when this migration is rolled back: + execute("DROP FUNCTION IF EXISTS uuid_generate_v7(), timestamp_from_uuid_v7(uuid)") + end +end diff --git a/priv/repo/migrations/20240922090430_add_map_acl_fk_check.exs b/priv/repo/migrations/20240922090430_add_map_acl_fk_check.exs new file mode 100644 index 00000000..ac2e3a94 --- /dev/null +++ b/priv/repo/migrations/20240922090430_add_map_acl_fk_check.exs @@ -0,0 +1,100 @@ +defmodule WandererApp.Repo.Migrations.AddMapAclFkCheck do + @moduledoc """ + Updates resources based on their most recent snapshots. + + This file was autogenerated with `mix ash_postgres.generate_migrations` + """ + + use Ecto.Migration + + def up do + drop constraint(:map_access_lists_v1, "map_access_lists_v1_access_list_id_fkey") + + drop constraint(:map_access_lists_v1, "map_access_lists_v1_map_id_fkey") + + alter table(:map_access_lists_v1) do + modify :map_id, + references(:maps_v1, + column: :id, + name: "map_access_lists_v1_map_id_fkey", + type: :uuid, + prefix: "public", + on_delete: :delete_all + ) + end + + drop constraint(:access_list_members_v1, "access_list_members_v1_access_list_id_fkey") + + alter table(:access_list_members_v1) do + modify :access_list_id, + references(:access_lists_v1, + column: :id, + name: "access_list_members_v1_access_list_id_fkey", + type: :uuid, + prefix: "public", + on_delete: :delete_all + ) + end + + execute( + "ALTER TABLE access_list_members_v1 alter CONSTRAINT access_list_members_v1_access_list_id_fkey NOT DEFERRABLE" + ) + + execute( + "ALTER TABLE map_access_lists_v1 alter CONSTRAINT map_access_lists_v1_map_id_fkey NOT DEFERRABLE" + ) + + alter table(:map_access_lists_v1) do + modify :access_list_id, + references(:access_lists_v1, + column: :id, + name: "map_access_lists_v1_access_list_id_fkey", + type: :uuid, + prefix: "public", + on_delete: :delete_all + ) + end + + execute( + "ALTER TABLE map_access_lists_v1 alter CONSTRAINT map_access_lists_v1_access_list_id_fkey NOT DEFERRABLE" + ) + end + + def down do + drop constraint(:map_access_lists_v1, "map_access_lists_v1_access_list_id_fkey") + + alter table(:map_access_lists_v1) do + modify :access_list_id, + references(:access_lists_v1, + column: :id, + name: "map_access_lists_v1_access_list_id_fkey", + type: :uuid, + prefix: "public" + ) + end + + drop constraint(:access_list_members_v1, "access_list_members_v1_access_list_id_fkey") + + alter table(:access_list_members_v1) do + modify :access_list_id, + references(:access_lists_v1, + column: :id, + name: "access_list_members_v1_access_list_id_fkey", + type: :uuid, + prefix: "public" + ) + end + + drop constraint(:map_access_lists_v1, "map_access_lists_v1_map_id_fkey") + + alter table(:map_access_lists_v1) do + modify :map_id, + references(:maps_v1, + column: :id, + name: "map_access_lists_v1_map_id_fkey", + type: :uuid, + prefix: "public" + ) + end + end +end diff --git a/priv/resource_snapshots/repo/access_list_members_v1/20240922090430.json b/priv/resource_snapshots/repo/access_list_members_v1/20240922090430.json new file mode 100644 index 00000000..79c89462 --- /dev/null +++ b/priv/resource_snapshots/repo/access_list_members_v1/20240922090430.json @@ -0,0 +1,183 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "fragment(\"gen_random_uuid()\")", + "generated?": false, + "primary_key?": true, + "references": null, + "size": null, + "source": "id", + "type": "uuid" + }, + { + "allow_nil?": false, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "name", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "eve_character_id", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "eve_corporation_id", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "eve_alliance_id", + "type": "text" + }, + { + "allow_nil?": true, + "default": "\"viewer\"", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "role", + "type": "text" + }, + { + "allow_nil?": false, + "default": "fragment(\"(now() AT TIME ZONE 'utc')\")", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "inserted_at", + "type": "utc_datetime_usec" + }, + { + "allow_nil?": false, + "default": "fragment(\"(now() AT TIME ZONE 'utc')\")", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "updated_at", + "type": "utc_datetime_usec" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "access_list_members_v1_access_list_id_fkey", + "on_delete": "delete", + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "access_lists_v1" + }, + "size": null, + "source": "access_list_id", + "type": "uuid" + } + ], + "base_filter": null, + "check_constraints": [], + "custom_indexes": [], + "custom_statements": [], + "has_create_action": true, + "hash": "C513B5FDD62707C1E7491D194C5A33DB6A8F060DC7FA0BD6AECA2A8BE9EAD65E", + "identities": [ + { + "all_tenants?": false, + "base_filter": null, + "index_name": "access_list_members_v1_uniq_acl_alliance_id_index", + "keys": [ + { + "type": "atom", + "value": "access_list_id" + }, + { + "type": "atom", + "value": "eve_alliance_id" + } + ], + "name": "uniq_acl_alliance_id", + "nils_distinct?": true, + "where": null + }, + { + "all_tenants?": false, + "base_filter": null, + "index_name": "access_list_members_v1_uniq_acl_character_id_index", + "keys": [ + { + "type": "atom", + "value": "access_list_id" + }, + { + "type": "atom", + "value": "eve_character_id" + } + ], + "name": "uniq_acl_character_id", + "nils_distinct?": true, + "where": null + }, + { + "all_tenants?": false, + "base_filter": null, + "index_name": "access_list_members_v1_uniq_acl_corporation_id_index", + "keys": [ + { + "type": "atom", + "value": "access_list_id" + }, + { + "type": "atom", + "value": "eve_corporation_id" + } + ], + "name": "uniq_acl_corporation_id", + "nils_distinct?": true, + "where": null + } + ], + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "repo": "Elixir.WandererApp.Repo", + "schema": null, + "table": "access_list_members_v1" +} \ No newline at end of file diff --git a/priv/resource_snapshots/repo/extensions.json b/priv/resource_snapshots/repo/extensions.json index b9b00f15..c7b52544 100644 --- a/priv/resource_snapshots/repo/extensions.json +++ b/priv/resource_snapshots/repo/extensions.json @@ -1,5 +1,5 @@ { - "ash_functions_version": 3, + "ash_functions_version": 4, "installed": [ "ash-functions" ] diff --git a/priv/resource_snapshots/repo/map_access_lists_v1/20240922090430.json b/priv/resource_snapshots/repo/map_access_lists_v1/20240922090430.json new file mode 100644 index 00000000..4f4875b3 --- /dev/null +++ b/priv/resource_snapshots/repo/map_access_lists_v1/20240922090430.json @@ -0,0 +1,126 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "fragment(\"gen_random_uuid()\")", + "generated?": false, + "primary_key?": true, + "references": null, + "size": null, + "source": "id", + "type": "uuid" + }, + { + "allow_nil?": false, + "default": "fragment(\"(now() AT TIME ZONE 'utc')\")", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "inserted_at", + "type": "utc_datetime_usec" + }, + { + "allow_nil?": false, + "default": "fragment(\"(now() AT TIME ZONE 'utc')\")", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "updated_at", + "type": "utc_datetime_usec" + }, + { + "allow_nil?": false, + "default": "nil", + "generated?": false, + "primary_key?": true, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "map_access_lists_v1_map_id_fkey", + "on_delete": "delete", + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "maps_v1" + }, + "size": null, + "source": "map_id", + "type": "uuid" + }, + { + "allow_nil?": false, + "default": "nil", + "generated?": false, + "primary_key?": true, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "map_access_lists_v1_access_list_id_fkey", + "on_delete": "delete", + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "access_lists_v1" + }, + "size": null, + "source": "access_list_id", + "type": "uuid" + } + ], + "base_filter": null, + "check_constraints": [], + "custom_indexes": [], + "custom_statements": [], + "has_create_action": true, + "hash": "1790C0240D55A6A1F6346B22E98AED5387F62E11BB258541CC1F95679C955F42", + "identities": [ + { + "all_tenants?": false, + "base_filter": null, + "index_name": "map_access_lists_v1_unique_map_acl_index", + "keys": [ + { + "type": "atom", + "value": "map_id" + }, + { + "type": "atom", + "value": "access_list_id" + } + ], + "name": "unique_map_acl", + "nils_distinct?": true, + "where": null + } + ], + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "repo": "Elixir.WandererApp.Repo", + "schema": null, + "table": "map_access_lists_v1" +} \ No newline at end of file