diff --git a/assets/js/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/hooks/useSystemSignaturesData.ts b/assets/js/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/hooks/useSystemSignaturesData.ts index 5f05a3fc..3aeddcb1 100644 --- a/assets/js/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/hooks/useSystemSignaturesData.ts +++ b/assets/js/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/hooks/useSystemSignaturesData.ts @@ -70,7 +70,7 @@ export const useSystemSignaturesData = ({ ? signaturesRef.current.filter(sig => !sig.pendingDeletion) : signaturesRef.current.filter(sig => !sig.pendingDeletion || !sig.pendingAddition); - const { added, updated, removed } = getActualSigs(currentNonPending, incomingSignatures, !lazyDeleteValue, true); + const { added, updated, removed } = getActualSigs(currentNonPending, incomingSignatures, !lazyDeleteValue, false); if (removed.length > 0) { await processRemovedSignatures(removed, added, updated); diff --git a/lib/wanderer_app/api/map_system_signature.ex b/lib/wanderer_app/api/map_system_signature.ex index 1925307a..2c1e642e 100644 --- a/lib/wanderer_app/api/map_system_signature.ex +++ b/lib/wanderer_app/api/map_system_signature.ex @@ -25,9 +25,18 @@ defmodule WandererApp.Api.MapSystemSignature do define(:by_system_id, action: :by_system_id, args: [:system_id]) define(:by_system_id_all, action: :by_system_id_all, args: [:system_id]) - define(:by_system_id_and_eve_ids, action: :by_system_id_and_eve_ids, args: [:system_id, :eve_ids]) + + define(:by_system_id_and_eve_ids, + action: :by_system_id_and_eve_ids, + args: [:system_id, :eve_ids] + ) + define(:by_linked_system_id, action: :by_linked_system_id, args: [:linked_system_id]) - define(:by_deleted_and_updated_before!, action: :by_deleted_and_updated_before, args: [:deleted, :updated_before]) + + define(:by_deleted_and_updated_before!, + action: :by_deleted_and_updated_before, + args: [:deleted, :updated_before] + ) end actions do @@ -88,7 +97,8 @@ defmodule WandererApp.Api.MapSystemSignature do :group, :type, :custom_info, - :deleted + :deleted, + :update_forced_at ] primary? true @@ -177,6 +187,10 @@ defmodule WandererApp.Api.MapSystemSignature do default false end + attribute :update_forced_at, :utc_datetime do + allow_nil? true + end + create_timestamp(:inserted_at) update_timestamp(:updated_at) end @@ -192,21 +206,20 @@ defmodule WandererApp.Api.MapSystemSignature do end @derive {Jason.Encoder, - only: [ - :id, - :system_id, - :eve_id, - :character_eve_id, - :name, - :description, - :type, - :linked_system_id, - :kind, - :group, - :custom_info, - :deleted, - :inserted_at, - :updated_at - ] - } + only: [ + :id, + :system_id, + :eve_id, + :character_eve_id, + :name, + :description, + :type, + :linked_system_id, + :kind, + :group, + :custom_info, + :deleted, + :inserted_at, + :updated_at + ]} end diff --git a/lib/wanderer_app/map/server/map_server_signatures_impl.ex b/lib/wanderer_app/map/server/map_server_signatures_impl.ex index 7792e5e1..0a610abe 100644 --- a/lib/wanderer_app/map/server/map_server_signatures_impl.ex +++ b/lib/wanderer_app/map/server/map_server_signatures_impl.ex @@ -25,7 +25,10 @@ defmodule WandererApp.Map.Server.SignaturesImpl do ) when not is_nil(char_id) do with {:ok, system} <- - MapSystem.read_by_map_and_solar_system(%{map_id: map_id, solar_system_id: system_solar_id}), + MapSystem.read_by_map_and_solar_system(%{ + map_id: map_id, + solar_system_id: system_solar_id + }), {:ok, %{eve_id: char_eve_id}} <- Character.get_character(char_id) do do_update_signatures( state, @@ -84,9 +87,11 @@ defmodule WandererApp.Map.Server.SignaturesImpl do # 3. Additions & restorations added_eve_ids = Enum.map(added_sigs, & &1.eve_id) - existing_index = MapSystemSignature.by_system_id_all!(system.id) - |> Enum.filter(&(&1.eve_id in added_eve_ids)) - |> Map.new(&{&1.eve_id, &1}) + + existing_index = + MapSystemSignature.by_system_id_all!(system.id) + |> Enum.filter(&(&1.eve_id in added_eve_ids)) + |> Map.new(&{&1.eve_id, &1}) added_sigs |> Enum.each(fn sig -> @@ -97,7 +102,16 @@ defmodule WandererApp.Map.Server.SignaturesImpl do %MapSystemSignature{deleted: true} = deleted_sig -> MapSystemSignature.update!( deleted_sig, - Map.take(sig, [:name, :description, :kind, :group, :type, :custom_info, :deleted]) + Map.take(sig, [ + :name, + :description, + :kind, + :group, + :type, + :custom_info, + :deleted, + :update_forced_at + ]) ) _ -> @@ -107,7 +121,12 @@ defmodule WandererApp.Map.Server.SignaturesImpl do # 4. Activity tracking if added_ids != [] do - track_activity(:signatures_added, state.map_id, system.solar_system_id, user_id, character_eve_id, + track_activity( + :signatures_added, + state.map_id, + system.solar_system_id, + user_id, + character_eve_id, added_ids ) end @@ -152,8 +171,13 @@ defmodule WandererApp.Map.Server.SignaturesImpl do defp apply_update_signature(%MapSystemSignature{} = existing, update_params) when not is_nil(update_params) do - case MapSystemSignature.update(existing, update_params) do - {:ok, _} -> :ok + case MapSystemSignature.update( + existing, + update_params |> Map.put(:update_forced_at, DateTime.utc_now()) + ) do + {:ok, _updated} -> + :ok + {:error, reason} -> Logger.error("Failed to update signature #{existing.id}: #{inspect(reason)}") end diff --git a/priv/repo/migrations/20250524170825_add_sig_update_forced_at.exs b/priv/repo/migrations/20250524170825_add_sig_update_forced_at.exs new file mode 100644 index 00000000..772d7dee --- /dev/null +++ b/priv/repo/migrations/20250524170825_add_sig_update_forced_at.exs @@ -0,0 +1,21 @@ +defmodule WandererApp.Repo.Migrations.AddSigUpdateForcedAt 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 + alter table(:map_system_signatures_v1) do + add :update_forced_at, :utc_datetime + end + end + + def down do + alter table(:map_system_signatures_v1) do + remove :update_forced_at + end + end +end diff --git a/priv/resource_snapshots/repo/map_system_signatures_v1/20250524170825.json b/priv/resource_snapshots/repo/map_system_signatures_v1/20250524170825.json new file mode 100644 index 00000000..634c58a4 --- /dev/null +++ b/priv/resource_snapshots/repo/map_system_signatures_v1/20250524170825.json @@ -0,0 +1,207 @@ +{ + "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": "eve_id", + "type": "text" + }, + { + "allow_nil?": false, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "character_eve_id", + "type": "text" + }, + { + "allow_nil?": true, + "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": "description", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "type", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "linked_system_id", + "type": "bigint" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "kind", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "group", + "type": "text" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "custom_info", + "type": "text" + }, + { + "allow_nil?": false, + "default": "false", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "deleted", + "type": "boolean" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "update_forced_at", + "type": "utc_datetime" + }, + { + "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": "map_system_signatures_v1_system_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "map_system_v1" + }, + "size": null, + "source": "system_id", + "type": "uuid" + } + ], + "base_filter": null, + "check_constraints": [], + "custom_indexes": [], + "custom_statements": [], + "has_create_action": true, + "hash": "915C0896211ECCB6C38871664117E7D470C794825536E7F0887DC5B92681F17B", + "identities": [ + { + "all_tenants?": false, + "base_filter": null, + "index_name": "map_system_signatures_v1_uniq_system_eve_id_index", + "keys": [ + { + "type": "atom", + "value": "system_id" + }, + { + "type": "atom", + "value": "eve_id" + } + ], + "name": "uniq_system_eve_id", + "nils_distinct?": true, + "where": null + } + ], + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "repo": "Elixir.WandererApp.Repo", + "schema": null, + "table": "map_system_signatures_v1" +} \ No newline at end of file