mirror of
https://git.ianrenton.com/ian/spothole.git
synced 2026-09-20 22:37:44 +00:00
Giant refactor to rebrand "SIG" as "Activity" anywhere that doesn't touch API or config file (which is to be addressed in a future breaking change). #147
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
from dataclasses import dataclass, field
|
||||
|
||||
from core.enums import ActivityRefType, ActivityType
|
||||
|
||||
|
||||
@dataclass
|
||||
class Activity:
|
||||
"""Data class that defines an Activity (formerly referred to as a "Special Interest Group" or "SIG", a term
|
||||
which is still used for the `sig` field name in the API for backwards compatibility). Each contains a name and
|
||||
a longer form description. They also contain comment_names which attempts to separate out the way people might
|
||||
refer to it in cluster comments from how it is referred to in the UI & API. (For example, "TOTA" in cluster
|
||||
spot comments almost always means Towers on the Air, but no single programme is referred to in the UI as "TOTA"
|
||||
as it's ambiguous between Towers, Toilets and Tiles. And while Beaches got the name "BOTA" first, "BOTA" spots
|
||||
are much more likely to be bunkers.) Finally, there is a ref_regex which provides a regular expression to
|
||||
match what references (such as parks and summits) look like for that programme."""
|
||||
|
||||
# Activity name as used in the UI and API, e.g. "Towers"
|
||||
name: str
|
||||
# Description, e.g. "Towers on the Air"
|
||||
description: str
|
||||
# Type, either Worldwide, Regional or Event. Used for sorting in the web UI.
|
||||
# Note: this field is still named "sig_type" in the API for backwards compatibility.
|
||||
sig_type: ActivityType
|
||||
# Identifies that the activity's reference ID structure defined by its regex is unique across all programmes and
|
||||
# anything else we expect a user to put in a spot comment, and therefore we can pull references out of
|
||||
# spot comments without also needing to see the activity name first. For example, "OHFF-1234" or "B/G-1234" are
|
||||
# obviously WWFF and WWBOTA, nothing else looks like those. But "SZ09" could be WAB or Tiles, "GB1234" could
|
||||
# conceivably be POTA or ILLW, etc.
|
||||
refs_globally_unique: bool
|
||||
# Activity names as they might appear in cluster spot comments, e.g. ["TOTA"]
|
||||
comment_names: list[str] = field(default_factory=list)
|
||||
# Reference type, what gets activated e.g. Park, Summit. May be None if the activity is for multiple types of
|
||||
# things, in which case the spot data will have to provide this instead.
|
||||
ref_type: ActivityRefType | None = None
|
||||
# Regex matcher for references, e.g. for POTA r"[A-Z]{2}\-\d+".
|
||||
ref_regex: str | None = None
|
||||
# Icon to use in the UI when referencing this activity. Chosen from the Font Awesome set.
|
||||
icon: str | None = None
|
||||
# Emoji flag for the country or region where this activity is relevant, if any. If None, this implies the
|
||||
# activity is in worldwide usage.
|
||||
region_flag: str | None = None
|
||||
@@ -1,24 +1,24 @@
|
||||
from dataclasses import dataclass
|
||||
|
||||
from core.enums import SIGRefType
|
||||
from core.enums import ActivityRefType
|
||||
|
||||
|
||||
@dataclass
|
||||
class SIGRef:
|
||||
"""Data class that defines a Special Interest Group "info" or reference. As well as the basic reference ID we include a
|
||||
class ActivityRef:
|
||||
"""Data class that defines an Activity "info" or reference. As well as the basic reference ID we include a
|
||||
name and a lookup URL."""
|
||||
|
||||
# SIG that this reference is in, e.g. "POTA".
|
||||
# Activity that this reference is in, e.g. "POTA". Still named "sig" for backwards compatibility with the API.
|
||||
sig: str
|
||||
# Reference ID, e.g. "GB-0001".
|
||||
id: str | None = None
|
||||
# Name of the reference, e.g. "Null Country Park", if known.
|
||||
name: str | None = None
|
||||
# Type of the reference, e.g. "Park", if known.
|
||||
ref_type: SIGRefType | None = None
|
||||
ref_type: ActivityRefType | None = None
|
||||
# URL to look up more information about the reference, if known.
|
||||
url: str | None = None
|
||||
# Icon to use for the reference, derived from the SIG. Chosen from the Font Awesome set.
|
||||
# Icon to use for the reference, derived from the activity. Chosen from the Font Awesome set.
|
||||
icon: str | None = None
|
||||
# Latitude of the reference, in degrees, if known.
|
||||
latitude: float | None = None
|
||||
+13
-12
@@ -6,9 +6,9 @@ from datetime import datetime, timedelta
|
||||
|
||||
import pytz
|
||||
|
||||
from core.activity_lookup_helper import populate_missing_activity_ref_info
|
||||
from core.call_lookup_helper import get_call_info
|
||||
from core.enums import AlertType, Continent
|
||||
from core.sig_lookup_helper import populate_missing_sig_ref_info
|
||||
from core.utils import get_flag_for_dxcc
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -59,11 +59,12 @@ class Alert:
|
||||
# A URL link to more information, if any
|
||||
url: str | None = None
|
||||
|
||||
# Special Interest Group info
|
||||
# Activity info
|
||||
|
||||
# Special Interest Group (SIG), e.g. outdoor activity programme such as POTA
|
||||
# Activity (e.g. outdoor activity programme such as POTA). Still named "sig" for API backwards compatibility.
|
||||
sig: str | None = None
|
||||
# SIG references. We allow multiple here for e.g. n-fer activations, unlike ADIF SIG_INFO
|
||||
# Activity references. We allow multiple here for e.g. n-fer activations, unlike ADIF SIG_INFO. Still named
|
||||
# "sig_refs" for API backwards compatibility.
|
||||
sig_refs: list = field(default_factory=list)
|
||||
|
||||
# Timing info
|
||||
@@ -125,15 +126,15 @@ class Alert:
|
||||
if self.dx_dxcc_id and not self.dx_flag:
|
||||
self.dx_flag = get_flag_for_dxcc(self.dx_dxcc_id)
|
||||
|
||||
# Fetch SIG data. In case a particular API doesn't provide a full set of name, lat, lon & grid for a reference
|
||||
# in its initial call, we use this code to populate the rest of the data. This includes working out grid refs
|
||||
# from WAB and WAI, which count as a SIG even though there's no real lookup, just maths
|
||||
# Fetch activity data. In case a particular API doesn't provide a full set of name, lat, lon & grid for a
|
||||
# reference in its initial call, we use this code to populate the rest of the data. This includes working
|
||||
# out grid refs from WAB and WAI, which count as an activity even though there's no real lookup, just maths
|
||||
if self.sig_refs:
|
||||
for sig_ref in self.sig_refs:
|
||||
populate_missing_sig_ref_info(sig_ref)
|
||||
for activity_ref in self.sig_refs:
|
||||
populate_missing_activity_ref_info(activity_ref)
|
||||
|
||||
# If the spot itself doesn't have a SIG yet, but we have at least one SIG reference, take that reference's SIG
|
||||
# and apply it to the whole spot.
|
||||
# If the spot itself doesn't have an activity yet, but we have at least one activity reference, take that
|
||||
# reference's activity and apply it to the whole spot.
|
||||
if self.sig_refs and self.sig_refs[0] and not self.sig:
|
||||
self.sig = self.sig_refs[0].sig
|
||||
|
||||
@@ -152,7 +153,7 @@ class Alert:
|
||||
if self.dx_calls and not self.dx_names:
|
||||
self.dx_names = [get_call_info(c, credentials).name for c in self.dx_calls]
|
||||
|
||||
# Icon for the spot should be the icon of the first SIG ref if present, otherwise a radio tower
|
||||
# Icon for the spot should be the icon of the first activity ref if present, otherwise a radio tower
|
||||
self.icon = "fa-tower-cell"
|
||||
if self.alert_type == AlertType.DXPEDITION:
|
||||
self.icon = "fa-globe-africa"
|
||||
|
||||
+2
-2
@@ -7,8 +7,8 @@ from core.enums import Continent, LocationSourceForCallsign
|
||||
class Callsign:
|
||||
"""Data class that defines a callsign and the data associated with it. This will have been retrieved by a callsign
|
||||
lookup provider using data files or online lookup. This can be used to infer missing data for a spot, though if the
|
||||
spot has a SIG (e.g. POTA) reference this data for their home location (or even just their country) will be less
|
||||
accurate and should not be used in preference to that."""
|
||||
spot has an activity (e.g. POTA) reference this data for their home location (or even just their country) will be
|
||||
less accurate and should not be used in preference to that."""
|
||||
|
||||
# Callsign as spotted
|
||||
call: str
|
||||
|
||||
-39
@@ -1,39 +0,0 @@
|
||||
from dataclasses import dataclass, field
|
||||
|
||||
from core.enums import SIGRefType, SIGType
|
||||
|
||||
|
||||
@dataclass
|
||||
class SIG:
|
||||
"""Data class that defines a Special Interest Group. Each contains a name and a longer form description.
|
||||
They also contain comment_names which attempts to separate out the way people might refer to it in
|
||||
cluster comments from how it is referred to in the UI & API. (For example, "TOTA" in cluster spot comments
|
||||
almost always means Towers on the Air, but no single programme is referred to in the UI as "TOTA" as
|
||||
it's ambiguous between Towers, Toilets and Tiles. And while Beaches got the name "BOTA" first, "BOTA" spots
|
||||
are much more likely to be bunkers.) Finally, there is a ref_regex which provides a regular expression to
|
||||
match what references (such as parks and summits) look like for that programme."""
|
||||
|
||||
# SIG name as used in the UI and API, e.g. "Towers"
|
||||
name: str
|
||||
# Description, e.g. "Towers on the Air"
|
||||
description: str
|
||||
# Type, either Worldwide, Regional or Event. Used for sorting in the web UI.
|
||||
sig_type: SIGType
|
||||
# Identifies that the SIG's reference ID structure defined by its regex is unique across all programmes and
|
||||
# anything else we expect a user to put in a spot comment, and therefore we can pull references out of
|
||||
# spot comments without also needing to see the SIG name first. For example, "OHFF-1234" or "B/G-1234" are
|
||||
# obviously WWFF and WWBOTA, nothing else looks like those. But "SZ09" could be WAB or Tiles, "GB1234" could
|
||||
# conceivably be POTA or ILLW, etc.
|
||||
refs_globally_unique: bool
|
||||
# SIG names as they might appear in cluster spot comments, e.g. ["TOTA"]
|
||||
comment_names: list[str] = field(default_factory=list)
|
||||
# Reference type, what gets activated e.g. Park, Summit. May be None if the SIG is for multiple types of things, in
|
||||
# which case the spot data will have to provide this instead.
|
||||
ref_type: SIGRefType | None = None
|
||||
# Regex matcher for references, e.g. for POTA r"[A-Z]{2}\-\d+".
|
||||
ref_regex: str | None = None
|
||||
# Icon to use in the UI when referencing this SIG. Chosen from the Font Awesome set.
|
||||
icon: str | None = None
|
||||
# Emoji flag for the country or region where this SIG is relevant, if any. If None, this implies the SIG is in
|
||||
# worldwide usage.
|
||||
region_flag: str | None = None
|
||||
+91
-74
@@ -9,18 +9,18 @@ from math import isnan
|
||||
import pytz
|
||||
from pyhamtools.locator import latlong_to_locator, locator_to_latlong
|
||||
|
||||
from core.activity_lookup_helper import populate_missing_activity_ref_info
|
||||
from core.activity_utils import (
|
||||
ANY_ACTIVITY_REGEX,
|
||||
get_activity_name_from_comment_name,
|
||||
get_ref_regex_for_activity,
|
||||
)
|
||||
from core.call_lookup_helper import get_call_info
|
||||
from core.config import MAX_SPOT_AGE
|
||||
from core.constants import PROPAGATION_MODES, SIGS
|
||||
from core.constants import ACTIVITIES, PROPAGATION_MODES
|
||||
from core.data_store import DATA_STORE
|
||||
from core.enums import Continent, LocationSourceForSpot, Mode, ModeSource, ModeType
|
||||
from core.geo_utils import lat_lon_to_cq_zone, lat_lon_to_itu_zone
|
||||
from core.sig_lookup_helper import populate_missing_sig_ref_info
|
||||
from core.sig_utils import (
|
||||
ANY_SIG_REGEX,
|
||||
get_ref_regex_for_sig,
|
||||
get_sig_name_from_comment_name,
|
||||
)
|
||||
from core.utils import (
|
||||
get_flag_for_dxcc,
|
||||
infer_band_from_freq,
|
||||
@@ -28,7 +28,7 @@ from core.utils import (
|
||||
infer_mode_from_frequency,
|
||||
infer_mode_type_from_mode,
|
||||
)
|
||||
from data.sig_ref import SIGRef
|
||||
from data.activity_ref import ActivityRef
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -46,8 +46,8 @@ class Spot:
|
||||
dx_call: str | None = None
|
||||
# Name of the operator that has been spotted
|
||||
dx_name: str | None = None
|
||||
# QTH of the operator that has been spotted. This could be from any SIG refs or could be from online lookup of their
|
||||
# home QTH.
|
||||
# QTH of the operator that has been spotted. This could be from any activity refs or could be from online lookup of
|
||||
# their home QTH.
|
||||
dx_qth: str | None = None
|
||||
# Country of the DX operator
|
||||
dx_country: str | None = None
|
||||
@@ -73,8 +73,8 @@ class Spot:
|
||||
# DX Location source. Indicates how accurate the location might be.
|
||||
dx_location_source: LocationSourceForSpot | None = None
|
||||
# DX Location good. Indicates that the software thinks the location data is good enough to plot on a map. This is
|
||||
# true if the location source is "SPOT", "SIG REF LOOKUP" or "GRID", or if the location source is "HOME QTH" and the
|
||||
# DX callsign doesn't have a suffix like /P.
|
||||
# true if the location source is "SPOT", "SIG REF LOOKUP" or "GRID", or if the location source is "HOME QTH" and
|
||||
# the DX callsign doesn't have a suffix like /P. (Location source retains "SIG" wording for API compatibility.)
|
||||
dx_location_good: bool = False
|
||||
|
||||
# DE (Spotter) info
|
||||
@@ -120,11 +120,12 @@ class Spot:
|
||||
# QRT state. Some APIs return spots marked as QRT. Otherwise we can check the comments.
|
||||
qrt: bool = False
|
||||
|
||||
# Special Interest Group info
|
||||
# Activity info
|
||||
|
||||
# Special Interest Group (SIG), e.g. outdoor activity programme such as POTA
|
||||
# Activity (e.g. outdoor activity programme such as POTA). Still named "sig" for API backwards compatibility.
|
||||
sig: str | None = None
|
||||
# SIG references. We allow multiple here for e.g. n-fer activations, unlike ADIF SIG_INFO
|
||||
# Activity references. We allow multiple here for e.g. n-fer activations, unlike ADIF SIG_INFO. Still named
|
||||
# "sig_refs" for API backwards compatibility.
|
||||
sig_refs: list = field(default_factory=list)
|
||||
|
||||
# Timing info
|
||||
@@ -158,7 +159,10 @@ class Spot:
|
||||
objects such as the sig_refs list.."""
|
||||
|
||||
if self.sig_refs:
|
||||
self.sig_refs = [sig_ref if isinstance(sig_ref, SIGRef) else SIGRef(**sig_ref) for sig_ref in self.sig_refs]
|
||||
self.sig_refs = [
|
||||
activity_ref if isinstance(activity_ref, ActivityRef) else ActivityRef(**activity_ref)
|
||||
for activity_ref in self.sig_refs
|
||||
]
|
||||
|
||||
def infer_missing(self, credentials=None):
|
||||
"""Infer missing parameters where possible"""
|
||||
@@ -262,76 +266,89 @@ class Spot:
|
||||
if self.dx_latitude or self.dx_grid:
|
||||
self.dx_location_source = LocationSourceForSpot.SPOT
|
||||
|
||||
# Set the top-level "SIG" if it is missing but we have at least one SIG ref.
|
||||
# Set the top-level activity if it is missing but we have at least one activity ref.
|
||||
if not self.sig and self.sig_refs:
|
||||
self.sig = self.sig_refs[0].sig.upper()
|
||||
|
||||
# See if we already have a SIG reference, but the comment looks like it contains more for the same SIG. This
|
||||
# should catch e.g. POTA comments like "2-fer: GB-0001 GB-0002".
|
||||
# See if we already have an activity reference, but the comment looks like it contains more for the same
|
||||
# activity. This should catch e.g. POTA comments like "2-fer: GB-0001 GB-0002".
|
||||
if self.comment and self.sig_refs and self.sig_refs[0].sig:
|
||||
sig = self.sig_refs[0].sig.upper()
|
||||
regex = get_ref_regex_for_sig(sig)
|
||||
activity = self.sig_refs[0].sig.upper()
|
||||
regex = get_ref_regex_for_activity(activity)
|
||||
if regex:
|
||||
all_comment_ref_matches = re.finditer(r"(^|\W)(" + regex + r")($|\W)", self.comment, re.IGNORECASE)
|
||||
for ref_match in all_comment_ref_matches:
|
||||
self._append_sig_ref_if_missing(SIGRef(id=ref_match.group(2).upper(), sig=sig))
|
||||
self._append_activity_ref_if_missing(ActivityRef(id=ref_match.group(2).upper(), sig=activity))
|
||||
|
||||
# See if the comment looks like it contains any SIGs (and optionally SIG references) that we can
|
||||
# add to the spot. This should catch cluster spot comments like "POTA GB-0001 WWFF GFF-0001" and e.g. POTA
|
||||
# comments like "also WWFF GFF-0001".
|
||||
# See if the comment looks like it contains any activities (and optionally activity references) that we
|
||||
# can add to the spot. This should catch cluster spot comments like "POTA GB-0001 WWFF GFF-0001" and e.g.
|
||||
# POTA comments like "also WWFF GFF-0001".
|
||||
if self.comment:
|
||||
sig_matches = re.finditer(r"(^|\W)" + ANY_SIG_REGEX + r"($|\W)", self.comment, re.IGNORECASE)
|
||||
for sig_match in sig_matches:
|
||||
# First of all, if we haven't got a SIG for this spot set yet, now we have. This covers things like cluster
|
||||
# spots where the comment is just "POTA".
|
||||
found_sig = get_sig_name_from_comment_name(sig_match.group(2))
|
||||
activity_matches = re.finditer(r"(^|\W)" + ANY_ACTIVITY_REGEX + r"($|\W)", self.comment, re.IGNORECASE)
|
||||
for activity_match in activity_matches:
|
||||
# First of all, if we haven't got an activity for this spot set yet, now we have. This covers
|
||||
# things like cluster spots where the comment is just "POTA".
|
||||
found_activity = get_activity_name_from_comment_name(activity_match.group(2))
|
||||
if not self.sig:
|
||||
self.sig = found_sig
|
||||
self.sig = found_activity
|
||||
|
||||
# Now look to see if that SIG name was followed by something that looks like a reference ID for that SIG.
|
||||
# If so, add that to the sig_refs list for this spot.
|
||||
ref_regex = get_ref_regex_for_sig(found_sig)
|
||||
# Now look to see if that activity name was followed by something that looks like a reference ID
|
||||
# for that activity. If so, add that to the sig_refs list for this spot.
|
||||
ref_regex = get_ref_regex_for_activity(found_activity)
|
||||
if ref_regex:
|
||||
ref_matches = re.finditer(
|
||||
r"(^|\W)" + found_sig + r"([ -])(" + ref_regex + r")($|\W)",
|
||||
r"(^|\W)" + found_activity + 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))
|
||||
self._append_activity_ref_if_missing(
|
||||
ActivityRef(id=ref_match.group(3).upper(), sig=found_activity)
|
||||
)
|
||||
|
||||
# See if the comment looks like it contains any SIG references *without* the corresponding SIG name, but
|
||||
# where the SIG reference is unique-looking enough that we can't confuse it with any other SIG.
|
||||
# See if the comment looks like it contains any activity references *without* the corresponding activity
|
||||
# name, but where the activity reference is unique-looking enough that we can't confuse it with any other
|
||||
# activity.
|
||||
if self.comment:
|
||||
for sig in SIGS:
|
||||
if sig.refs_globally_unique and sig.ref_regex:
|
||||
ref_matches = re.finditer(r"(^|\W)(" + sig.ref_regex + r")($|\W)", self.comment, re.IGNORECASE)
|
||||
for activity in ACTIVITIES:
|
||||
if activity.refs_globally_unique and activity.ref_regex:
|
||||
ref_matches = re.finditer(
|
||||
r"(^|\W)(" + activity.ref_regex + r")($|\W)", self.comment, re.IGNORECASE
|
||||
)
|
||||
for ref_match in ref_matches:
|
||||
# First of all, if we haven't got a SIG for this spot set yet, now we have. This covers things
|
||||
# like cluster spots where the comment is just "OHFF-1234", now we know it's WWFF.
|
||||
# First of all, if we haven't got an activity for this spot set yet, now we have. This
|
||||
# covers things like cluster spots where the comment is just "OHFF-1234", now we know
|
||||
# it's WWFF.
|
||||
if not self.sig:
|
||||
self.sig = sig.name
|
||||
self._append_sig_ref_if_missing(SIGRef(id=ref_match.group(2).upper(), sig=sig.name))
|
||||
self.sig = activity.name
|
||||
self._append_activity_ref_if_missing(
|
||||
ActivityRef(id=ref_match.group(2).upper(), sig=activity.name)
|
||||
)
|
||||
|
||||
# Fetch SIG data. In case a particular API doesn't provide a full set of name, lat, lon & grid for a reference
|
||||
# in its initial call, we use this code to populate the rest of the data. This includes working out grid refs
|
||||
# from WAB and WAI, which count as a SIG even though there's no real lookup, just maths
|
||||
# Fetch activity data. In case a particular API doesn't provide a full set of name, lat, lon & grid for a
|
||||
# reference in its initial call, we use this code to populate the rest of the data. This includes working
|
||||
# out grid refs from WAB and WAI, which count as an activity even though there's no real lookup, just maths
|
||||
if self.sig_refs:
|
||||
for sig_ref in self.sig_refs:
|
||||
sig_ref = populate_missing_sig_ref_info(sig_ref)
|
||||
# If the spot itself doesn't have location yet, but the SIG ref does, extract it
|
||||
if sig_ref.grid and not self.dx_grid:
|
||||
self.dx_grid = sig_ref.grid
|
||||
if sig_ref.latitude and not self.dx_latitude and sig_ref.longitude and not self.dx_longitude:
|
||||
self.dx_latitude = sig_ref.latitude
|
||||
self.dx_longitude = sig_ref.longitude
|
||||
for activity_ref in self.sig_refs:
|
||||
activity_ref = populate_missing_activity_ref_info(activity_ref)
|
||||
# If the spot itself doesn't have location yet, but the activity ref does, extract it
|
||||
if activity_ref.grid and not self.dx_grid:
|
||||
self.dx_grid = activity_ref.grid
|
||||
if (
|
||||
activity_ref.latitude
|
||||
and not self.dx_latitude
|
||||
and activity_ref.longitude
|
||||
and not self.dx_longitude
|
||||
):
|
||||
self.dx_latitude = activity_ref.latitude
|
||||
self.dx_longitude = activity_ref.longitude
|
||||
if self.sig == "WAB" or self.sig == "WAI" or self.sig == "Tiles":
|
||||
self.dx_location_source = LocationSourceForSpot.GRID
|
||||
else:
|
||||
self.dx_location_source = LocationSourceForSpot.SIG_REF_LOOKUP
|
||||
|
||||
# If the spot itself doesn't have a SIG yet, but we have at least one SIG reference, take that reference's SIG
|
||||
# and apply it to the whole spot.
|
||||
# If the spot itself doesn't have an activity yet, but we have at least one activity reference, take that
|
||||
# reference's activity and apply it to the whole spot.
|
||||
if self.sig_refs and not self.sig:
|
||||
self.sig = self.sig_refs[0].sig
|
||||
|
||||
@@ -360,17 +377,17 @@ class Spot:
|
||||
self.propagation_mode = mode_tag
|
||||
logger.info(f"Seen a new propagation mode tag not yet in the system: {mode_tag}")
|
||||
|
||||
# Set SIGs based on propagation mode
|
||||
# Set activities based on propagation mode
|
||||
if self.propagation_mode == "Satellite":
|
||||
if not self.sig:
|
||||
self.sig = "AMSAT"
|
||||
if not any(sig_ref.sig == "AMSAT" for sig_ref in self.sig_refs):
|
||||
self.sig_refs.append(SIGRef(sig="AMSAT"))
|
||||
if not any(activity_ref.sig == "AMSAT" for activity_ref in self.sig_refs):
|
||||
self.sig_refs.append(ActivityRef(sig="AMSAT"))
|
||||
if self.propagation_mode == "Earth-Moon-Earth":
|
||||
if not self.sig:
|
||||
self.sig = "EME"
|
||||
if not any(sig_ref.sig == "EME" for sig_ref in self.sig_refs):
|
||||
self.sig_refs.append(SIGRef(sig="EME"))
|
||||
if not any(activity_ref.sig == "EME" for activity_ref in self.sig_refs):
|
||||
self.sig_refs.append(ActivityRef(sig="EME"))
|
||||
|
||||
# Parse "de_grid -> dx_grid" structures from the comment
|
||||
if self.comment:
|
||||
@@ -426,8 +443,8 @@ class Spot:
|
||||
self.dx_grid = dx_call_info.grid
|
||||
self.dx_location_source = dx_call_info.location_source
|
||||
|
||||
# Determine a "QTH" string. If we have a SIG ref, pick the first one and turn it into a suitable string,
|
||||
# otherwise see what they have set on an online lookup service.
|
||||
# Determine a "QTH" string. If we have an activity ref, pick the first one and turn it into a suitable
|
||||
# string, otherwise see what they have set on an online lookup service.
|
||||
if self.sig_refs:
|
||||
qth = self.sig_refs[0].id
|
||||
if self.sig_refs[0].name:
|
||||
@@ -482,7 +499,7 @@ class Spot:
|
||||
self.de_longitude = de_call_info.longitude
|
||||
self.de_grid = de_call_info.grid
|
||||
|
||||
# Icon for the spot should be the icon of the first SIG ref if present, otherwise a radio tower
|
||||
# Icon for the spot should be the icon of the first activity ref if present, otherwise a radio tower
|
||||
self.icon = "fa-tower-cell"
|
||||
if self.sig_refs and self.sig_refs[0].icon:
|
||||
self.icon = self.sig_refs[0].icon
|
||||
@@ -495,17 +512,17 @@ class Spot:
|
||||
|
||||
return json.dumps(self, default=lambda o: o.__dict__, sort_keys=True)
|
||||
|
||||
def _append_sig_ref_if_missing(self, new_sig_ref):
|
||||
"""Append a sig_ref to the list, so long as it's not already there."""
|
||||
def _append_activity_ref_if_missing(self, new_activity_ref):
|
||||
"""Append an activity ref to the list, so long as it's not already there."""
|
||||
|
||||
new_sig_ref.id = new_sig_ref.id.strip().upper()
|
||||
new_sig_ref.sig = new_sig_ref.sig.strip().upper()
|
||||
if new_sig_ref.id == "":
|
||||
new_activity_ref.id = new_activity_ref.id.strip().upper()
|
||||
new_activity_ref.sig = new_activity_ref.sig.strip().upper()
|
||||
if new_activity_ref.id == "":
|
||||
return
|
||||
for sig_ref in self.sig_refs:
|
||||
if sig_ref.id == new_sig_ref.id and sig_ref.sig == new_sig_ref.sig:
|
||||
for activity_ref in self.sig_refs:
|
||||
if activity_ref.id == new_activity_ref.id and activity_ref.sig == new_activity_ref.sig:
|
||||
return
|
||||
self.sig_refs.append(new_sig_ref)
|
||||
self.sig_refs.append(new_activity_ref)
|
||||
|
||||
def expired(self):
|
||||
"""Decide if this spot has expired (in which case it should not be added to the system in the first place, and not
|
||||
|
||||
Reference in New Issue
Block a user