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 %}