fix(radio): invalidate contact-map cache on edits, not just inserts
`apply_edit_to_contact/2` is the path for both owner direct-edits and admin reviewed-edits. The public contact-map + total-count + gzipped controller payload caches are built from `private == false` rows, but only the insert path was clearing them — every other update left /api/contacts/map and /contacts/map serving the previous snapshot for up to 10 minutes. A `private: false -> true` flip on a contact already present in the cached payload was a temporary privacy leak; grid corrections, callsign changes, and flagged_invalid flips silently diverged from the live row. Extracts the three `Cache.invalidate` calls into `invalidate_contact_map_caches/0` and runs it from both `apply_edit_to_contact/2` and the existing insert path so the public view stays in sync.
This commit is contained in:
parent
ff5b0acf98
commit
c17f912622
2 changed files with 40 additions and 3 deletions
|
|
@ -641,9 +641,7 @@ defmodule Microwaveprop.Radio do
|
|||
|> Repo.insert()
|
||||
|
||||
with {:ok, _} <- result do
|
||||
Cache.invalidate(@count_cache_key)
|
||||
Cache.invalidate(@map_payload_cache_key)
|
||||
Cache.invalidate({MicrowavepropWeb.ContactMapController, :gzipped_payload})
|
||||
invalidate_contact_map_caches()
|
||||
end
|
||||
|
||||
result
|
||||
|
|
@ -1095,9 +1093,24 @@ defmodule Microwaveprop.Radio do
|
|||
|
||||
maybe_enqueue_terrain_for_heights(updated, proposed_changes)
|
||||
|
||||
# Public contact-map + count caches are built from `private == false`
|
||||
# rows. A grid correction, callsign change, flagged_invalid flip, or
|
||||
# a `private: false -> true` toggle on an already-mapped contact all
|
||||
# change what /api/contacts/map and /contacts/map should return —
|
||||
# private flips in particular are a privacy leak until the 10-minute
|
||||
# TTL expires. Invalidate on every direct update.
|
||||
invalidate_contact_map_caches()
|
||||
|
||||
updated
|
||||
end
|
||||
|
||||
defp invalidate_contact_map_caches do
|
||||
Cache.invalidate(@count_cache_key)
|
||||
Cache.invalidate(@map_payload_cache_key)
|
||||
Cache.invalidate({MicrowavepropWeb.ContactMapController, :gzipped_payload})
|
||||
:ok
|
||||
end
|
||||
|
||||
defp maybe_enqueue_terrain_for_heights(contact, proposed) do
|
||||
if Map.has_key?(proposed, "height1_ft") or Map.has_key?(proposed, "height2_ft") do
|
||||
ContactWeatherEnqueueWorker.enqueue_for_contact(contact, [:terrain])
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ defmodule Microwaveprop.Radio.ContactEditTest do
|
|||
use Microwaveprop.DataCase, async: true
|
||||
|
||||
alias Microwaveprop.Accounts
|
||||
alias Microwaveprop.Cache
|
||||
alias Microwaveprop.Radio
|
||||
alias Microwaveprop.Radio.Contact
|
||||
alias Microwaveprop.Radio.ContactEdit
|
||||
|
|
@ -481,6 +482,29 @@ defmodule Microwaveprop.Radio.ContactEditTest do
|
|||
{:ok, updated} = Radio.apply_owner_edit(contact, user, %{"private" => "true"})
|
||||
assert updated.private == true
|
||||
end
|
||||
|
||||
test "applying an edit invalidates the public contact-map caches", %{user: user} do
|
||||
contact = owned_contact(user)
|
||||
|
||||
# Pre-seed the same three cache keys the insert path invalidates.
|
||||
# If apply_edit_to_contact forgets to invalidate, /api/contacts/map
|
||||
# and /contacts/map keep serving stale (and for private flips,
|
||||
# privacy-leaking) data for up to 10 minutes.
|
||||
sentinel = :stale_payload
|
||||
ten_min = 10 * 60 * 1_000
|
||||
|
||||
Cache.put({Radio, :total_contact_count}, sentinel, ten_min)
|
||||
Cache.put({Radio, :contact_map_payload}, sentinel, ten_min)
|
||||
Cache.put({MicrowavepropWeb.ContactMapController, :gzipped_payload}, sentinel, ten_min)
|
||||
|
||||
{:ok, _} = Radio.apply_owner_edit(contact, user, %{"private" => true})
|
||||
|
||||
assert :ets.lookup(:microwaveprop_cache, {Radio, :total_contact_count}) == []
|
||||
assert :ets.lookup(:microwaveprop_cache, {Radio, :contact_map_payload}) == []
|
||||
|
||||
assert :ets.lookup(:microwaveprop_cache, {MicrowavepropWeb.ContactMapController, :gzipped_payload}) ==
|
||||
[]
|
||||
end
|
||||
end
|
||||
|
||||
describe "Radio.owner?/2" do
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue