From 6a4b0bed959f899cfa56223db1d44e5b89eb84a7 Mon Sep 17 00:00:00 2001 From: Ian Renton Date: Thu, 13 Aug 2026 06:45:27 +0100 Subject: [PATCH] Fix extra duplicates showing for spots and alerts --- data/alert.py | 19 ++++++++----------- data/spot.py | 22 ++++++++++------------ templates/add_spot.html | 2 +- templates/alerts.html | 2 +- templates/bands.html | 4 ++-- templates/base.html | 10 +++++----- templates/conditions.html | 2 +- templates/map.html | 4 ++-- templates/spots.html | 4 ++-- templates/status.html | 2 +- 10 files changed, 33 insertions(+), 38 deletions(-) diff --git a/data/alert.py b/data/alert.py index 0002519..fd8c4eb 100644 --- a/data/alert.py +++ b/data/alert.py @@ -113,18 +113,15 @@ class Alert: if self.sig_refs and len(self.sig_refs) > 0 and self.sig_refs[0] and not self.sig: self.sig = self.sig_refs[0].sig - # Always create an ID based on a hash of every parameter *except* received_time. This is used as the index - # to a map, which as a byproduct avoids us having multiple duplicate copies of the object that are identical - # apart from that they were retrieved from the API at different times. Note that the simple Python hash() - # function includes a seed randomly generated at runtime; this is therefore not consistent between runs. But we - # use diskcache to store our data between runs, so we use SHA256 which does not include this random element. - # The ID is computed before the online lookups below so that it is stable regardless of whether credentials - # are provided, allowing the enriched API response to be matched to the stored alert by ID. + # Create an ID based on the source and source ID if possible, as these guaranee uniqueness. If there is no + # source ID, use a combination of callsign and start time. Excluding things like the comment here allows for + # user updates of their alert comments without duplicating in the system. if not self.id: - self_copy = copy.deepcopy(self) - self_copy.received_time = 0 - self_copy.received_time_iso = "" - self.id = hashlib.sha256(str(self_copy).encode("utf-8")).hexdigest() + if self.source and self.source_id: + self.id = hashlib.sha256(str({"s": self.source, "sid": self.source_id}).encode("utf-8")).hexdigest() + else: + self.id = hashlib.sha256( + str({"s": self.source, "c": self.dx_calls, "t": self.start_time}).encode("utf-8")).hexdigest() # DX operator name lookup, using QRZ.com/HamQTH. if self.dx_calls and not self.dx_names: diff --git a/data/spot.py b/data/spot.py index f9730a6..2423881 100644 --- a/data/spot.py +++ b/data/spot.py @@ -279,7 +279,8 @@ class Spot: # If so, add that to the sig_refs list for this spot. ref_regex = get_ref_regex_for_sig(found_sig) if ref_regex: - ref_matches = re.finditer(r"(^|\W)" + found_sig + r"([ -])(" + ref_regex + r")($|\W)", self.comment, + ref_matches = re.finditer(r"(^|\W)" + found_sig + r"([ -])(" + ref_regex + r")($|\W)", + self.comment, re.IGNORECASE) for ref_match in ref_matches: self._append_sig_ref_if_missing(SIGRef(id=ref_match.group(3).upper(), sig=found_sig)) @@ -361,18 +362,15 @@ class Spot: if self.comment and not self.qrt: self.qrt = "QRT" in self.comment.upper() - # Always create an ID based on a hash of every parameter *except* received_time. This is used as the index - # to a map, which as a byproduct avoids us having multiple duplicate copies of the object that are identical - # apart from that they were retrieved from the API at different times. Note that the simple Python hash() - # function includes a seed randomly generated at runtime; this is therefore not consistent between runs. But we - # use diskcache to store our data between runs, so we use SHA256 which does not include this random element. - # The ID is computed before the online lookups below so that it is stable regardless of whether credentials - # are provided, allowing the enriched API response to be matched to the stored spot by ID. + # Create an ID based on the source and source ID if possible, as these guaranee uniqueness. If there is no + # source ID, use a combination of callsign and spot time. Spot time is down to the second or even the + # millisecond, so we can be reasonably sure two spots that match are the same spot. if not self.id: - self_copy = copy.deepcopy(self) - self_copy.received_time = 0 - self_copy.received_time_iso = "" - self.id = hashlib.sha256(str(self_copy).encode("utf-8")).hexdigest() + if self.source and self.source_id: + self.id = hashlib.sha256(str({"s": self.source, "sid": self.source_id}).encode("utf-8")).hexdigest() + else: + self.id = hashlib.sha256( + str({"s": self.source, "c": self.dx_call, "t": self.time}).encode("utf-8")).hexdigest() # DX operator details lookup. This should be the last resort compared to taking the data from the actual # spotting service, e.g. we don't want to accidentally use a user's QRZ.com home lat/lon or DXCC lat/lon diff --git a/templates/add_spot.html b/templates/add_spot.html index 36b7123..48575e8 100644 --- a/templates/add_spot.html +++ b/templates/add_spot.html @@ -76,7 +76,7 @@ - + diff --git a/templates/alerts.html b/templates/alerts.html index 773a07a..4da5b57 100644 --- a/templates/alerts.html +++ b/templates/alerts.html @@ -82,7 +82,7 @@ - + diff --git a/templates/bands.html b/templates/bands.html index e8d9557..49fc35a 100644 --- a/templates/bands.html +++ b/templates/bands.html @@ -79,8 +79,8 @@ - - + + diff --git a/templates/base.html b/templates/base.html index 79fcf9f..b132f47 100644 --- a/templates/base.html +++ b/templates/base.html @@ -1,6 +1,6 @@ {% extends "skeleton.html" %} {% block head_extra %} - + @@ -10,10 +10,10 @@ - - - - + + + + {% end %} {% block body %}
diff --git a/templates/conditions.html b/templates/conditions.html index d2fd2a9..8f08c4d 100644 --- a/templates/conditions.html +++ b/templates/conditions.html @@ -284,7 +284,7 @@
- + diff --git a/templates/map.html b/templates/map.html index 8daa6fd..6b5fa11 100644 --- a/templates/map.html +++ b/templates/map.html @@ -112,8 +112,8 @@ - - + + diff --git a/templates/spots.html b/templates/spots.html index cad1e06..ebe6f3b 100644 --- a/templates/spots.html +++ b/templates/spots.html @@ -118,8 +118,8 @@ - - + + diff --git a/templates/status.html b/templates/status.html index 4fd2638..3a6a8ad 100644 --- a/templates/status.html +++ b/templates/status.html @@ -81,7 +81,7 @@ - +