mirror of
https://git.ianrenton.com/ian/spothole.git
synced 2026-09-20 14:27:42 +00:00
Now that SIGs are rebranded as Activities, we can merge DXpedition and Contest into that without it being too weird, and get rid of AlertType #147
This commit is contained in:
@@ -11,6 +11,15 @@ def get_ref_regex_for_activity(activity):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def get_icon_for_activity(activity):
|
||||||
|
"""Utility function to get the icon for a named activity. If no match is found, None will be returned."""
|
||||||
|
|
||||||
|
for a in ACTIVITIES:
|
||||||
|
if a.name.upper() == activity.upper():
|
||||||
|
return a.icon
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
def get_activity_name_from_comment_name(activity):
|
def get_activity_name_from_comment_name(activity):
|
||||||
"""Utility function to get the name of an activity from its "comment name". Generally these will be the same
|
"""Utility function to get the name of an activity from its "comment name". Generally these will be the same
|
||||||
but there are some cases (e.g. is "TOTA" Towers, Tiles or Toilets?) where we need to transform one to the
|
but there are some cases (e.g. is "TOTA" Towers, Tiles or Toilets?) where we need to transform one to the
|
||||||
|
|||||||
@@ -12,6 +12,22 @@ HAMQTH_PRG = f"Spothole v{SOFTWARE_VERSION} operated by {SERVER_OWNER_CALLSIGN}"
|
|||||||
|
|
||||||
# Activities
|
# Activities
|
||||||
ACTIVITIES = [
|
ACTIVITIES = [
|
||||||
|
Activity(
|
||||||
|
name="Contest",
|
||||||
|
comment_names=["CONTEST"],
|
||||||
|
description="Contest",
|
||||||
|
sig_type=ActivityType.TRADITIONAL,
|
||||||
|
icon="fa-trophy",
|
||||||
|
refs_globally_unique=False,
|
||||||
|
),
|
||||||
|
Activity(
|
||||||
|
name="DXpedition",
|
||||||
|
comment_names=[],
|
||||||
|
description="Radio expedition to a remote location",
|
||||||
|
sig_type=ActivityType.TRADITIONAL,
|
||||||
|
icon="fa-book-atlas",
|
||||||
|
refs_globally_unique=False,
|
||||||
|
),
|
||||||
Activity(
|
Activity(
|
||||||
name="Satellite",
|
name="Satellite",
|
||||||
comment_names=[],
|
comment_names=[],
|
||||||
|
|||||||
@@ -112,15 +112,6 @@ class ActivityRefType(str, Enum):
|
|||||||
TOILET = "TOILET"
|
TOILET = "TOILET"
|
||||||
|
|
||||||
|
|
||||||
class AlertType(str, Enum):
|
|
||||||
"""Type of an alert."""
|
|
||||||
|
|
||||||
XOTA = "XOTA"
|
|
||||||
SATELLITE = "SATELLITE"
|
|
||||||
DXPEDITION = "DXPEDITION"
|
|
||||||
CONTEST = "CONTEST"
|
|
||||||
|
|
||||||
|
|
||||||
class ActivityType(str, Enum):
|
class ActivityType(str, Enum):
|
||||||
"""Type of an activity. Used to group them in the web UI."""
|
"""Type of an activity. Used to group them in the web UI."""
|
||||||
|
|
||||||
|
|||||||
+5
-12
@@ -7,8 +7,9 @@ from datetime import datetime, timedelta
|
|||||||
import pytz
|
import pytz
|
||||||
|
|
||||||
from core.activity_lookup_helper import populate_missing_activity_ref_info
|
from core.activity_lookup_helper import populate_missing_activity_ref_info
|
||||||
|
from core.activity_utils import get_icon_for_activity
|
||||||
from core.call_lookup_helper import get_call_info
|
from core.call_lookup_helper import get_call_info
|
||||||
from core.enums import AlertType, Continent
|
from core.enums import Continent
|
||||||
from core.utils import get_flag_for_dxcc
|
from core.utils import get_flag_for_dxcc
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@@ -54,8 +55,6 @@ class Alert:
|
|||||||
end_time_iso: str | None = None
|
end_time_iso: str | None = None
|
||||||
# Comment made by the alerter, if any
|
# Comment made by the alerter, if any
|
||||||
comment: str | None = None
|
comment: str | None = None
|
||||||
# The type of alert this is: xOTA, DXpedition, or Contest.
|
|
||||||
alert_type: AlertType | None = None
|
|
||||||
# A URL link to more information, if any
|
# A URL link to more information, if any
|
||||||
url: str | None = None
|
url: str | None = None
|
||||||
|
|
||||||
@@ -153,16 +152,10 @@ class Alert:
|
|||||||
if self.dx_calls and not self.dx_names:
|
if self.dx_calls and not self.dx_names:
|
||||||
self.dx_names = [get_call_info(c, credentials).name for c in self.dx_calls]
|
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 activity ref if present, otherwise a radio tower
|
# Icon for the alert should be the icon of its activity if known, otherwise a radio tower
|
||||||
self.icon = "fa-tower-cell"
|
self.icon = "fa-tower-cell"
|
||||||
if self.alert_type == AlertType.DXPEDITION:
|
if self.sig and (activity_icon := get_icon_for_activity(self.sig)):
|
||||||
self.icon = "fa-globe-africa"
|
self.icon = activity_icon
|
||||||
elif self.alert_type == AlertType.CONTEST:
|
|
||||||
self.icon = "fa-trophy"
|
|
||||||
elif self.alert_type == AlertType.SATELLITE:
|
|
||||||
self.icon = "fa-satellite"
|
|
||||||
elif self.sig_refs and self.sig_refs[0].icon:
|
|
||||||
self.icon = self.sig_refs[0].icon
|
|
||||||
|
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.exception("Exception while inferring missing data from spot")
|
logger.exception("Exception while inferring missing data from spot")
|
||||||
|
|||||||
+8
-13
@@ -13,6 +13,7 @@ from core.activity_lookup_helper import populate_missing_activity_ref_info
|
|||||||
from core.activity_utils import (
|
from core.activity_utils import (
|
||||||
ANY_ACTIVITY_REGEX,
|
ANY_ACTIVITY_REGEX,
|
||||||
get_activity_name_from_comment_name,
|
get_activity_name_from_comment_name,
|
||||||
|
get_icon_for_activity,
|
||||||
get_ref_regex_for_activity,
|
get_ref_regex_for_activity,
|
||||||
)
|
)
|
||||||
from core.call_lookup_helper import get_call_info
|
from core.call_lookup_helper import get_call_info
|
||||||
@@ -378,16 +379,10 @@ class Spot:
|
|||||||
logger.info(f"Seen a new propagation mode tag not yet in the system: {mode_tag}")
|
logger.info(f"Seen a new propagation mode tag not yet in the system: {mode_tag}")
|
||||||
|
|
||||||
# Set activities based on propagation mode
|
# Set activities based on propagation mode
|
||||||
if self.propagation_mode == "Satellite":
|
if self.propagation_mode == "Satellite" and not self.sig:
|
||||||
if not self.sig:
|
self.sig = "Satellite"
|
||||||
self.sig = "AMSAT"
|
if self.propagation_mode == "Earth-Moon-Earth" and not self.sig:
|
||||||
if not any(activity_ref.sig == "AMSAT" for activity_ref in self.sig_refs):
|
self.sig = "EME"
|
||||||
self.sig_refs.append(ActivityRef(sig="AMSAT"))
|
|
||||||
if self.propagation_mode == "Earth-Moon-Earth":
|
|
||||||
if not self.sig:
|
|
||||||
self.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
|
# Parse "de_grid -> dx_grid" structures from the comment
|
||||||
if self.comment:
|
if self.comment:
|
||||||
@@ -499,10 +494,10 @@ class Spot:
|
|||||||
self.de_longitude = de_call_info.longitude
|
self.de_longitude = de_call_info.longitude
|
||||||
self.de_grid = de_call_info.grid
|
self.de_grid = de_call_info.grid
|
||||||
|
|
||||||
# Icon for the spot should be the icon of the first activity ref if present, otherwise a radio tower
|
# Icon for the spot should be the icon of its activity if known, otherwise a radio tower
|
||||||
self.icon = "fa-tower-cell"
|
self.icon = "fa-tower-cell"
|
||||||
if self.sig_refs and self.sig_refs[0].icon:
|
if self.sig and (activity_icon := get_icon_for_activity(self.sig)):
|
||||||
self.icon = self.sig_refs[0].icon
|
self.icon = activity_icon
|
||||||
|
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.exception("Exception while inferring missing data from spot")
|
logger.exception("Exception while inferring missing data from spot")
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ from datetime import datetime, timedelta
|
|||||||
import pytz
|
import pytz
|
||||||
from bs4 import BeautifulSoup
|
from bs4 import BeautifulSoup
|
||||||
|
|
||||||
from core.enums import AlertType
|
|
||||||
from data.activity_ref import ActivityRef
|
from data.activity_ref import ActivityRef
|
||||||
from data.alert import Alert
|
from data.alert import Alert
|
||||||
from providers.alert.http_alert_provider import HTTPAlertProvider
|
from providers.alert.http_alert_provider import HTTPAlertProvider
|
||||||
@@ -56,9 +55,9 @@ class BOTA(HTTPAlertProvider):
|
|||||||
alert = Alert(
|
alert = Alert(
|
||||||
source=self.name,
|
source=self.name,
|
||||||
dx_calls=[dx_call],
|
dx_calls=[dx_call],
|
||||||
|
sig="BOTA",
|
||||||
sig_refs=[ActivityRef(id=ref_name, sig="BOTA")],
|
sig_refs=[ActivityRef(id=ref_name, sig="BOTA")],
|
||||||
start_time=date_time.timestamp(),
|
start_time=date_time.timestamp(),
|
||||||
alert_type=AlertType.XOTA,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
new_alerts.append(alert)
|
new_alerts.append(alert)
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ from datetime import datetime
|
|||||||
|
|
||||||
import pytz
|
import pytz
|
||||||
|
|
||||||
from core.enums import AlertType
|
|
||||||
from data.activity_ref import ActivityRef
|
from data.activity_ref import ActivityRef
|
||||||
from data.alert import Alert
|
from data.alert import Alert
|
||||||
from providers.alert.http_alert_provider import HTTPAlertProvider
|
from providers.alert.http_alert_provider import HTTPAlertProvider
|
||||||
@@ -35,10 +34,11 @@ class Hamsat(HTTPAlertProvider):
|
|||||||
dx_calls=[source_alert["callsign"].upper()],
|
dx_calls=[source_alert["callsign"].upper()],
|
||||||
freqs_modes=freqs_modes,
|
freqs_modes=freqs_modes,
|
||||||
comment=source_alert["comment"],
|
comment=source_alert["comment"],
|
||||||
|
sig="Satellite",
|
||||||
# Fudge an activity ref to provide the remaining bits of data we need: the satellite and the operator's grid
|
# Fudge an activity ref to provide the remaining bits of data we need: the satellite and the operator's grid
|
||||||
sig_refs=[
|
sig_refs=[
|
||||||
ActivityRef(
|
ActivityRef(
|
||||||
sig="AMSAT",
|
sig="Satellite",
|
||||||
id=f"{source_alert['satellite']['name']} from {source_alert['grids'][0]}",
|
id=f"{source_alert['satellite']['name']} from {source_alert['grids'][0]}",
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
@@ -48,7 +48,6 @@ class Hamsat(HTTPAlertProvider):
|
|||||||
end_time=datetime.strptime(source_alert["los_at"], "%Y-%m-%dT%H:%M:%SZ")
|
end_time=datetime.strptime(source_alert["los_at"], "%Y-%m-%dT%H:%M:%SZ")
|
||||||
.replace(tzinfo=pytz.UTC)
|
.replace(tzinfo=pytz.UTC)
|
||||||
.timestamp(),
|
.timestamp(),
|
||||||
alert_type=AlertType.SATELLITE,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Add to our list
|
# Add to our list
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import pytz
|
|||||||
from rss_parser import Parser
|
from rss_parser import Parser
|
||||||
from rss_parser.models.rss import RSS
|
from rss_parser.models.rss import RSS
|
||||||
|
|
||||||
from core.enums import AlertType
|
|
||||||
from data.alert import Alert
|
from data.alert import Alert
|
||||||
from providers.alert.http_alert_provider import HTTPAlertProvider
|
from providers.alert.http_alert_provider import HTTPAlertProvider
|
||||||
|
|
||||||
@@ -89,7 +88,7 @@ class NG3K(HTTPAlertProvider):
|
|||||||
comment=f"{by}; {comment}; {qsl_info}",
|
comment=f"{by}; {comment}; {qsl_info}",
|
||||||
start_time=start_timestamp,
|
start_time=start_timestamp,
|
||||||
end_time=end_timestamp,
|
end_time=end_timestamp,
|
||||||
alert_type=AlertType.DXPEDITION,
|
sig="DXpedition",
|
||||||
)
|
)
|
||||||
|
|
||||||
# Add to our list.
|
# Add to our list.
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ from datetime import datetime
|
|||||||
|
|
||||||
import pytz
|
import pytz
|
||||||
|
|
||||||
from core.enums import AlertType
|
|
||||||
from data.activity_ref import ActivityRef
|
from data.activity_ref import ActivityRef
|
||||||
from data.alert import Alert
|
from data.alert import Alert
|
||||||
from providers.alert.http_alert_provider import HTTPAlertProvider
|
from providers.alert.http_alert_provider import HTTPAlertProvider
|
||||||
@@ -50,9 +49,9 @@ class ParksNPeaks(HTTPAlertProvider):
|
|||||||
dx_calls=[source_alert["CallSign"].upper()],
|
dx_calls=[source_alert["CallSign"].upper()],
|
||||||
freqs_modes=f"{source_alert['Freq']} {source_alert['MODE']}",
|
freqs_modes=f"{source_alert['Freq']} {source_alert['MODE']}",
|
||||||
comment=source_alert["Comments"],
|
comment=source_alert["Comments"],
|
||||||
|
sig=activity,
|
||||||
sig_refs=activity_refs,
|
sig_refs=activity_refs,
|
||||||
start_time=start_time,
|
start_time=start_time,
|
||||||
alert_type=AlertType.XOTA,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Log a warning for the developer if PnP gives us an unknown programme we've never seen before
|
# Log a warning for the developer if PnP gives us an unknown programme we've never seen before
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ from datetime import datetime
|
|||||||
|
|
||||||
import pytz
|
import pytz
|
||||||
|
|
||||||
from core.enums import AlertType
|
|
||||||
from data.activity_ref import ActivityRef
|
from data.activity_ref import ActivityRef
|
||||||
from data.alert import Alert
|
from data.alert import Alert
|
||||||
from providers.alert.http_alert_provider import HTTPAlertProvider
|
from providers.alert.http_alert_provider import HTTPAlertProvider
|
||||||
@@ -28,6 +27,7 @@ class POTA(HTTPAlertProvider):
|
|||||||
dx_calls=[source_alert["activator"].upper()],
|
dx_calls=[source_alert["activator"].upper()],
|
||||||
freqs_modes=source_alert["frequencies"],
|
freqs_modes=source_alert["frequencies"],
|
||||||
comment=source_alert["comments"],
|
comment=source_alert["comments"],
|
||||||
|
sig="POTA",
|
||||||
sig_refs=[
|
sig_refs=[
|
||||||
ActivityRef(
|
ActivityRef(
|
||||||
id=source_alert["reference"],
|
id=source_alert["reference"],
|
||||||
@@ -45,7 +45,6 @@ class POTA(HTTPAlertProvider):
|
|||||||
end_time=datetime.strptime(source_alert["endDate"] + source_alert["endTime"], "%Y-%m-%d%H:%M")
|
end_time=datetime.strptime(source_alert["endDate"] + source_alert["endTime"], "%Y-%m-%d%H:%M")
|
||||||
.replace(tzinfo=pytz.UTC)
|
.replace(tzinfo=pytz.UTC)
|
||||||
.timestamp(),
|
.timestamp(),
|
||||||
alert_type=AlertType.XOTA,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Add to our list, but exclude any old spots that POTA can sometimes give us where even the end time is
|
# Add to our list, but exclude any old spots that POTA can sometimes give us where even the end time is
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import re
|
|||||||
|
|
||||||
from icalendar import Event
|
from icalendar import Event
|
||||||
|
|
||||||
from core.enums import AlertType, Continent
|
from core.enums import Continent
|
||||||
from data.alert import Alert
|
from data.alert import Alert
|
||||||
from providers.alert.ical_alert_provider import ICALAlertProvider
|
from providers.alert.ical_alert_provider import ICALAlertProvider
|
||||||
|
|
||||||
@@ -69,7 +69,7 @@ class RSGBICALAlertProvider(ICALAlertProvider):
|
|||||||
comment=summary,
|
comment=summary,
|
||||||
start_time=start_timestamp,
|
start_time=start_timestamp,
|
||||||
end_time=end_timestamp,
|
end_time=end_timestamp,
|
||||||
alert_type=AlertType.CONTEST,
|
sig="Contest",
|
||||||
)
|
)
|
||||||
|
|
||||||
return alert
|
return alert
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ from datetime import datetime
|
|||||||
|
|
||||||
import pytz
|
import pytz
|
||||||
|
|
||||||
from core.enums import AlertType
|
|
||||||
from data.activity_ref import ActivityRef
|
from data.activity_ref import ActivityRef
|
||||||
from data.alert import Alert
|
from data.alert import Alert
|
||||||
from providers.alert.http_alert_provider import HTTPAlertProvider
|
from providers.alert.http_alert_provider import HTTPAlertProvider
|
||||||
@@ -34,6 +33,7 @@ class SOTA(HTTPAlertProvider):
|
|||||||
dx_names=[source_alert["activatorName"].upper()],
|
dx_names=[source_alert["activatorName"].upper()],
|
||||||
freqs_modes=source_alert["frequency"],
|
freqs_modes=source_alert["frequency"],
|
||||||
comment=source_alert["comments"],
|
comment=source_alert["comments"],
|
||||||
|
sig="SOTA",
|
||||||
sig_refs=[
|
sig_refs=[
|
||||||
ActivityRef(
|
ActivityRef(
|
||||||
id=f"{source_alert['associationCode']}/{source_alert['summitCode']}",
|
id=f"{source_alert['associationCode']}/{source_alert['summitCode']}",
|
||||||
@@ -45,7 +45,6 @@ class SOTA(HTTPAlertProvider):
|
|||||||
start_time=datetime.strptime(source_alert["dateActivated"], "%Y-%m-%dT%H:%M:%SZ")
|
start_time=datetime.strptime(source_alert["dateActivated"], "%Y-%m-%dT%H:%M:%SZ")
|
||||||
.replace(tzinfo=pytz.UTC)
|
.replace(tzinfo=pytz.UTC)
|
||||||
.timestamp(),
|
.timestamp(),
|
||||||
alert_type=AlertType.XOTA,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Add to our list
|
# Add to our list
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
from icalendar import Event
|
from icalendar import Event
|
||||||
|
|
||||||
from core.enums import AlertType
|
|
||||||
from data.alert import Alert
|
from data.alert import Alert
|
||||||
from providers.alert.ical_alert_provider import ICALAlertProvider
|
from providers.alert.ical_alert_provider import ICALAlertProvider
|
||||||
|
|
||||||
@@ -35,7 +34,7 @@ class WA7BNM(ICALAlertProvider):
|
|||||||
url=url,
|
url=url,
|
||||||
start_time=start_timestamp,
|
start_time=start_timestamp,
|
||||||
end_time=end_timestamp,
|
end_time=end_timestamp,
|
||||||
alert_type=AlertType.CONTEST,
|
sig="Contest",
|
||||||
)
|
)
|
||||||
|
|
||||||
return alert
|
return alert
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ from datetime import datetime
|
|||||||
|
|
||||||
import pytz
|
import pytz
|
||||||
|
|
||||||
from core.enums import AlertType
|
|
||||||
from data.activity_ref import ActivityRef
|
from data.activity_ref import ActivityRef
|
||||||
from data.alert import Alert
|
from data.alert import Alert
|
||||||
from providers.alert.http_alert_provider import HTTPAlertProvider
|
from providers.alert.http_alert_provider import HTTPAlertProvider
|
||||||
@@ -28,6 +27,7 @@ class WWFF(HTTPAlertProvider):
|
|||||||
dx_calls=[source_alert["activator_call"].upper()],
|
dx_calls=[source_alert["activator_call"].upper()],
|
||||||
freqs_modes=f"{source_alert['band']} {source_alert['mode']}",
|
freqs_modes=f"{source_alert['band']} {source_alert['mode']}",
|
||||||
comment=source_alert["remarks"],
|
comment=source_alert["remarks"],
|
||||||
|
sig="WWFF",
|
||||||
sig_refs=[ActivityRef(id=source_alert["reference"], sig="WWFF")],
|
sig_refs=[ActivityRef(id=source_alert["reference"], sig="WWFF")],
|
||||||
start_time=datetime.strptime(source_alert["utc_start"], "%Y-%m-%d %H:%M:%S")
|
start_time=datetime.strptime(source_alert["utc_start"], "%Y-%m-%d %H:%M:%S")
|
||||||
.replace(tzinfo=pytz.UTC)
|
.replace(tzinfo=pytz.UTC)
|
||||||
@@ -35,7 +35,6 @@ class WWFF(HTTPAlertProvider):
|
|||||||
end_time=datetime.strptime(source_alert["utc_end"], "%Y-%m-%d %H:%M:%S")
|
end_time=datetime.strptime(source_alert["utc_end"], "%Y-%m-%d %H:%M:%S")
|
||||||
.replace(tzinfo=pytz.UTC)
|
.replace(tzinfo=pytz.UTC)
|
||||||
.timestamp(),
|
.timestamp(),
|
||||||
alert_type=AlertType.XOTA,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Add to our list
|
# Add to our list
|
||||||
|
|||||||
@@ -15,6 +15,11 @@ info:
|
|||||||
|
|
||||||
## Changelog
|
## Changelog
|
||||||
|
|
||||||
|
### 2.2
|
||||||
|
|
||||||
|
* Renamed AMSAT SIG to "Satellite" as AMSAT is a specific organisation not just a general term for satellite QSOs
|
||||||
|
* Removed `alert_type` from alert data. Contest, DXpedition and Satellite alerts now give those values in `sig` instead, alongside the existing outdoor activity programmes. Teeeeechnically a breaking change but AlertType is so new I doubt anyone is using it yet, so slipped this one in anyway. Sorry :)
|
||||||
|
|
||||||
### 2.1
|
### 2.1
|
||||||
|
|
||||||
* Added AMSAT, EME, DTMBA, FEA, BIWOTA, COTA & PGA SIGs
|
* Added AMSAT, EME, DTMBA, FEA, BIWOTA, COTA & PGA SIGs
|
||||||
@@ -952,14 +957,6 @@ components:
|
|||||||
- TOILET
|
- TOILET
|
||||||
example: PARK
|
example: PARK
|
||||||
|
|
||||||
AlertType:
|
|
||||||
type: string
|
|
||||||
enum:
|
|
||||||
- XOTA
|
|
||||||
- DXPEDITION
|
|
||||||
- CONTEST
|
|
||||||
example: XOTA
|
|
||||||
|
|
||||||
Continent:
|
Continent:
|
||||||
type: string
|
type: string
|
||||||
enum:
|
enum:
|
||||||
@@ -1489,9 +1486,6 @@ components:
|
|||||||
items:
|
items:
|
||||||
$ref: '#/components/schemas/ActivityRef'
|
$ref: '#/components/schemas/ActivityRef'
|
||||||
description: Activity references. We allow multiple here for e.g. n-fer activations, unlike ADIF SIG_INFO. Still named "sig_refs" in the API for backwards compatibility.
|
description: Activity references. We allow multiple here for e.g. n-fer activations, unlike ADIF SIG_INFO. Still named "sig_refs" in the API for backwards compatibility.
|
||||||
alert_type:
|
|
||||||
description: "The type of alert this is: xOTA, DXpedition, or Contest."
|
|
||||||
$ref: "#/components/schemas/AlertType"
|
|
||||||
url:
|
url:
|
||||||
type: string
|
type: string
|
||||||
description: A URL linking to more information about the alert, e.g. DXpedition or contest info.
|
description: A URL linking to more information about the alert, e.g. DXpedition or contest info.
|
||||||
|
|||||||
+14
-24
@@ -54,7 +54,7 @@ function updateTable() {
|
|||||||
const showDX = $("#tableShowDX")[0].checked;
|
const showDX = $("#tableShowDX")[0].checked;
|
||||||
const showFreqsModes = $("#tableShowFreqsModes")[0].checked;
|
const showFreqsModes = $("#tableShowFreqsModes")[0].checked;
|
||||||
const showComment = $("#tableShowComment")[0].checked;
|
const showComment = $("#tableShowComment")[0].checked;
|
||||||
const showType = $("#tableShowType")[0].checked;
|
const showActivity = $("#tableShowActivity")[0].checked;
|
||||||
const showRef = $("#tableShowRef")[0].checked;
|
const showRef = $("#tableShowRef")[0].checked;
|
||||||
|
|
||||||
// Populate table with headers
|
// Populate table with headers
|
||||||
@@ -75,11 +75,11 @@ function updateTable() {
|
|||||||
if (showComment) {
|
if (showComment) {
|
||||||
table.find('thead tr').append(`<th class='bg-primary-subtle hideonmobile'>Comment</th>`);
|
table.find('thead tr').append(`<th class='bg-primary-subtle hideonmobile'>Comment</th>`);
|
||||||
}
|
}
|
||||||
if (showType) {
|
if (showActivity) {
|
||||||
table.find('thead tr').append(`<th class='bg-primary-subtle hideonmobile'>Type</th>`);
|
table.find('thead tr').append(`<th class='bg-primary-subtle hideonmobile'>Activity</th>`);
|
||||||
}
|
}
|
||||||
if (showRef) {
|
if (showRef) {
|
||||||
table.find('thead tr').append(`<th class='bg-primary-subtle hideonmobile'>Ref.</th>`);
|
table.find('thead tr').append(`<th class='bg-primary-subtle hideonmobile'>Reference</th>`);
|
||||||
}
|
}
|
||||||
|
|
||||||
table.find('tbody').empty();
|
table.find('tbody').empty();
|
||||||
@@ -151,7 +151,7 @@ function addAlertRowsToTable(tbody, alerts) {
|
|||||||
const showDX = $("#tableShowDX")[0].checked;
|
const showDX = $("#tableShowDX")[0].checked;
|
||||||
const showFreqsModes = $("#tableShowFreqsModes")[0].checked;
|
const showFreqsModes = $("#tableShowFreqsModes")[0].checked;
|
||||||
const showComment = $("#tableShowComment")[0].checked;
|
const showComment = $("#tableShowComment")[0].checked;
|
||||||
const showType = $("#tableShowType")[0].checked;
|
const showActivity = $("#tableShowActivity")[0].checked;
|
||||||
const showRef = $("#tableShowRef")[0].checked;
|
const showRef = $("#tableShowRef")[0].checked;
|
||||||
|
|
||||||
// Get times for the alert, and convert to local time if necessary.
|
// Get times for the alert, and convert to local time if necessary.
|
||||||
@@ -210,14 +210,14 @@ function addAlertRowsToTable(tbody, alerts) {
|
|||||||
if (a["dx_calls"] != null) {
|
if (a["dx_calls"] != null) {
|
||||||
dx_calls_html = a["dx_calls"].map(call => `<a class='dx-link' href='https://qrz.com/db/${call}' target='_new'>${call}</a>`).join(", ");
|
dx_calls_html = a["dx_calls"].map(call => `<a class='dx-link' href='https://qrz.com/db/${call}' target='_new'>${call}</a>`).join(", ");
|
||||||
}
|
}
|
||||||
if (dx_calls_html === "" && a["alert_type"] === "CONTEST") {
|
if (dx_calls_html === "" && a["sig"] === "Contest") {
|
||||||
// Contest = true and no DX callsigns, so display "Contest"
|
// Contest = true and no DX callsigns, so display "Contest"
|
||||||
dx_calls_html = "Contest"
|
dx_calls_html = "Contest"
|
||||||
}
|
}
|
||||||
|
|
||||||
// Format DXpedition country
|
// Format DXpedition country
|
||||||
let dx_country_html = "";
|
let dx_country_html = "";
|
||||||
if (a["alert_type"] === "DXPEDITION" && a["dx_country"] != null && a["dx_country"] !== "") {
|
if (a["sig"] === "DXpedition" && a["dx_country"] != null && a["dx_country"] !== "") {
|
||||||
dx_country_html = `<br/>${a["dx_country"]}`;
|
dx_country_html = `<br/>${a["dx_country"]}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -250,20 +250,10 @@ function addAlertRowsToTable(tbody, alerts) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Type, activity or fallback to source
|
// Activity or fallback to "General DX"
|
||||||
let activityTypeText = a["source"];
|
let activityText = "General DX";
|
||||||
if (a["alert_type"] === "CONTEST") {
|
if (a["sig"]) {
|
||||||
activityTypeText = "Contest";
|
activityText = a["sig"];
|
||||||
} else if (a["alert_type"] === "DXPEDITION") {
|
|
||||||
activityTypeText = "DXpedition";
|
|
||||||
} else if (a["alert_type"] === "SATELLITE") {
|
|
||||||
activityTypeText = "Satellite";
|
|
||||||
} else if (a["alert_type"] === "XOTA") {
|
|
||||||
if (a["sig"]) {
|
|
||||||
activityTypeText = a["sig"];
|
|
||||||
} else {
|
|
||||||
activityTypeText = "xOTA";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Format activity refs
|
// Format activity refs
|
||||||
@@ -296,8 +286,8 @@ function addAlertRowsToTable(tbody, alerts) {
|
|||||||
if (showComment) {
|
if (showComment) {
|
||||||
$tr.append(`<td class='hideonmobile'>${commentText}</td>`);
|
$tr.append(`<td class='hideonmobile'>${commentText}</td>`);
|
||||||
}
|
}
|
||||||
if (showType) {
|
if (showActivity) {
|
||||||
$tr.append(`<td class='nowrap hideonmobile'><span class='icon-wrapper'><i class='fa-solid ${a["icon"]}'></i></span> ${activityTypeText}</td>`);
|
$tr.append(`<td class='nowrap hideonmobile'><span class='icon-wrapper'><i class='fa-solid ${a["icon"]}'></i></span> ${activityText}</td>`);
|
||||||
}
|
}
|
||||||
if (showRef) {
|
if (showRef) {
|
||||||
$tr.append(`<td class='hideonmobile'>${activityRefs}</td>`);
|
$tr.append(`<td class='hideonmobile'>${activityRefs}</td>`);
|
||||||
@@ -314,7 +304,7 @@ function addAlertRowsToTable(tbody, alerts) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const $td2 = $("<td colspan='100'>");
|
const $td2 = $("<td colspan='100'>");
|
||||||
if (showType) {
|
if (showActivity) {
|
||||||
$td2.append(`<span class='icon-wrapper'><i class='fa-solid ${a["icon"]}'></i></span> `);
|
$td2.append(`<span class='icon-wrapper'><i class='fa-solid ${a["icon"]}'></i></span> `);
|
||||||
}
|
}
|
||||||
if (showRef) {
|
if (showRef) {
|
||||||
|
|||||||
+13
-13
@@ -128,7 +128,7 @@ function updateTable() {
|
|||||||
const showComment = $("#tableShowComment")[0].checked;
|
const showComment = $("#tableShowComment")[0].checked;
|
||||||
const showBearing = $("#tableShowBearing")[0].checked && userPos != null;
|
const showBearing = $("#tableShowBearing")[0].checked && userPos != null;
|
||||||
const showDistance = $("#tableShowDistance")[0].checked && userPos != null;
|
const showDistance = $("#tableShowDistance")[0].checked && userPos != null;
|
||||||
const showType = $("#tableShowType")[0].checked;
|
const showActivity = $("#tableShowActivity")[0].checked;
|
||||||
const showRef = $("#tableShowRef")[0].checked;
|
const showRef = $("#tableShowRef")[0].checked;
|
||||||
const showDE = $("#tableShowDE")[0].checked;
|
const showDE = $("#tableShowDE")[0].checked;
|
||||||
const showWorkedCheckbox = $("#tableShowWorkedCheckbox")[0].checked;
|
const showWorkedCheckbox = $("#tableShowWorkedCheckbox")[0].checked;
|
||||||
@@ -157,11 +157,11 @@ function updateTable() {
|
|||||||
if (showDistance) {
|
if (showDistance) {
|
||||||
table.find('thead tr').append(`<th class='bg-primary-subtle hideonmobile'>Distance</th>`);
|
table.find('thead tr').append(`<th class='bg-primary-subtle hideonmobile'>Distance</th>`);
|
||||||
}
|
}
|
||||||
if (showType) {
|
if (showActivity) {
|
||||||
table.find('thead tr').append(`<th class='bg-primary-subtle hideonmobile'>Type</th>`);
|
table.find('thead tr').append(`<th class='bg-primary-subtle hideonmobile'>Activity</th>`);
|
||||||
}
|
}
|
||||||
if (showRef) {
|
if (showRef) {
|
||||||
table.find('thead tr').append(`<th class='bg-primary-subtle hideonmobile'>Ref.</th>`);
|
table.find('thead tr').append(`<th class='bg-primary-subtle hideonmobile'>Reference</th>`);
|
||||||
}
|
}
|
||||||
if (showDE) {
|
if (showDE) {
|
||||||
table.find('thead tr').append(`<th class='bg-primary-subtle hideonmobile'>DE</th>`);
|
table.find('thead tr').append(`<th class='bg-primary-subtle hideonmobile'>DE</th>`);
|
||||||
@@ -208,7 +208,7 @@ function createNewTableRowsForSpot(s, highlightNew) {
|
|||||||
const showComment = $("#tableShowComment")[0].checked;
|
const showComment = $("#tableShowComment")[0].checked;
|
||||||
const showBearing = $("#tableShowBearing")[0].checked && userPos != null;
|
const showBearing = $("#tableShowBearing")[0].checked && userPos != null;
|
||||||
const showDistance = $("#tableShowDistance")[0].checked && userPos != null;
|
const showDistance = $("#tableShowDistance")[0].checked && userPos != null;
|
||||||
const showType = $("#tableShowType")[0].checked;
|
const showActivity = $("#tableShowActivity")[0].checked;
|
||||||
const showRef = $("#tableShowRef")[0].checked;
|
const showRef = $("#tableShowRef")[0].checked;
|
||||||
const showDE = $("#tableShowDE")[0].checked;
|
const showDE = $("#tableShowDE")[0].checked;
|
||||||
const showWorkedCheckbox = $("#tableShowWorkedCheckbox")[0].checked;
|
const showWorkedCheckbox = $("#tableShowWorkedCheckbox")[0].checked;
|
||||||
@@ -327,10 +327,10 @@ function createNewTableRowsForSpot(s, highlightNew) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Format "type" (activity or fallback to source)
|
// Format activity
|
||||||
let typeText = s["source"];
|
let activityText = "General DX";
|
||||||
if (s["sig"]) {
|
if (s["sig"]) {
|
||||||
typeText = s["sig"];
|
activityText = s["sig"];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Format activity refs
|
// Format activity refs
|
||||||
@@ -397,8 +397,8 @@ function createNewTableRowsForSpot(s, highlightNew) {
|
|||||||
if (showDistance) {
|
if (showDistance) {
|
||||||
$tr.append(`<td class='nowrap hideonmobile'>${distanceText}</td>`);
|
$tr.append(`<td class='nowrap hideonmobile'>${distanceText}</td>`);
|
||||||
}
|
}
|
||||||
if (showType) {
|
if (showActivity) {
|
||||||
$tr.append(`<td class='nowrap hideonmobile'><span class='icon-wrapper'><i class='fa-solid ${s["icon"]}'></i></span> ${typeText}</td>`);
|
$tr.append(`<td class='nowrap hideonmobile'><span class='icon-wrapper'><i class='fa-solid ${s["icon"]}'></i></span> ${activityText}</td>`);
|
||||||
}
|
}
|
||||||
if (showRef) {
|
if (showRef) {
|
||||||
$tr.append(`<td class='hideonmobile' style='max-width: 11em;'>${activityRefs}</td>`);
|
$tr.append(`<td class='hideonmobile' style='max-width: 11em;'>${activityRefs}</td>`);
|
||||||
@@ -410,7 +410,7 @@ function createNewTableRowsForSpot(s, highlightNew) {
|
|||||||
$tr.append(`<td class='nowrap hideonmobile'>${workedCheckbox}</td>`);
|
$tr.append(`<td class='nowrap hideonmobile'>${workedCheckbox}</td>`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Second row for mobile view only, containing type, ref & comment
|
// Second row for mobile view only, containing activity, ref & comment
|
||||||
const $tr2 = $("<tr class='hidenotonmobile'>");
|
const $tr2 = $("<tr class='hidenotonmobile'>");
|
||||||
|
|
||||||
// Apply styles as per the first row
|
// Apply styles as per the first row
|
||||||
@@ -429,8 +429,8 @@ function createNewTableRowsForSpot(s, highlightNew) {
|
|||||||
|
|
||||||
const $td2 = $("<td colspan='100'>");
|
const $td2 = $("<td colspan='100'>");
|
||||||
const $td2floatleft = $(`<div style="float: left;">`);
|
const $td2floatleft = $(`<div style="float: left;">`);
|
||||||
if (showType) {
|
if (showActivity) {
|
||||||
$td2floatleft.append(`<span class='icon-wrapper'><i class='fa-solid ${s["icon"]}'></i></span> ${typeText} `);
|
$td2floatleft.append(`<span class='icon-wrapper'><i class='fa-solid ${s["icon"]}'></i></span> ${activityText} `);
|
||||||
}
|
}
|
||||||
if (showRef) {
|
if (showRef) {
|
||||||
$td2floatleft.append(`${activityRefs} `);
|
$td2floatleft.append(`${activityRefs} `);
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ function generateActivitiesMultiToggleFilterCard(activity_options) {
|
|||||||
const domSafeName = o["name"].replace(/^[^A-Za-z0-9]+|[^\w]+/gi, "");
|
const domSafeName = o["name"].replace(/^[^A-Za-z0-9]+|[^\w]+/gi, "");
|
||||||
$grid.append(`<div class="col"><div class="form-check"><input type="checkbox" class="form-check-input filter-button-sig storeable-checkbox" id="filter-button-sig-${domSafeName}" value="${o['name']}" autocomplete="off" onClick="filtersUpdated()" checked><label class="form-check-label" id="filter-button-label-sig-${domSafeName}" for="filter-button-sig-${domSafeName}" title="${o['description']}"><i class="fa-solid ${o['icon']}"></i> ${o['name']} ${(o["region_flag"] != null) ? o['region_flag'] : ''}</label></div></div>`);
|
$grid.append(`<div class="col"><div class="form-check"><input type="checkbox" class="form-check-input filter-button-sig storeable-checkbox" id="filter-button-sig-${domSafeName}" value="${o['name']}" autocomplete="off" onClick="filtersUpdated()" checked><label class="form-check-label" id="filter-button-label-sig-${domSafeName}" for="filter-button-sig-${domSafeName}" title="${o['description']}"><i class="fa-solid ${o['icon']}"></i> ${o['name']} ${(o["region_flag"] != null) ? o['region_flag'] : ''}</label></div></div>`);
|
||||||
});
|
});
|
||||||
$body.append(`<div class="w-100"><div class="form-check"><input type="checkbox" class="form-check-input filter-button-sig storeable-checkbox" id="filter-button-sig-NO_SIG" value="NO_SIG" autocomplete="off" onClick="filtersUpdated()" checked><label class="form-check-label" id="filter-button-label-sig-NO_SIG" for="filter-button-sig-NO_SIG"><i class="fa-solid fa-tower-cell"></i> General DX</label></div></div>`);
|
$body.append(`<div class="w-100 mb-1"><div class="form-check"><input type="checkbox" class="form-check-input filter-button-sig storeable-checkbox" id="filter-button-sig-NO_SIG" value="NO_SIG" autocomplete="off" onClick="filtersUpdated()" checked><label class="form-check-label" id="filter-button-label-sig-NO_SIG" for="filter-button-sig-NO_SIG"><i class="fa-solid fa-tower-cell"></i> General DX</label></div></div>`);
|
||||||
$body.append($grid);
|
$body.append($grid);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -39,16 +39,16 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="form-check">
|
<div class="form-check">
|
||||||
<input class="form-check-input storeable-checkbox" type="checkbox" id="tableShowType"
|
<input class="form-check-input storeable-checkbox" type="checkbox" id="tableShowActivity"
|
||||||
value="tableShowType" oninput="columnsUpdated();" checked>
|
value="tableShowActivity" oninput="columnsUpdated();" checked>
|
||||||
<label class="form-check-label" for="tableShowType">Source</label>
|
<label class="form-check-label" for="tableShowActivity">Activity</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="form-check">
|
<div class="form-check">
|
||||||
<input class="form-check-input storeable-checkbox" type="checkbox" id="tableShowRef"
|
<input class="form-check-input storeable-checkbox" type="checkbox" id="tableShowRef"
|
||||||
value="tableShowRef" oninput="columnsUpdated();" checked>
|
value="tableShowRef" oninput="columnsUpdated();" checked>
|
||||||
<label class="form-check-label" for="tableShowRef">Ref.</label>
|
<label class="form-check-label" for="tableShowRef">Reference</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -53,16 +53,16 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="form-check">
|
<div class="form-check">
|
||||||
<input class="form-check-input storeable-checkbox" type="checkbox" id="tableShowType"
|
<input class="form-check-input storeable-checkbox" type="checkbox" id="tableShowActivity"
|
||||||
value="tableShowType" oninput="columnsUpdated();" checked>
|
value="tableShowActivity" oninput="columnsUpdated();" checked>
|
||||||
<label class="form-check-label" for="tableShowType">Type</label>
|
<label class="form-check-label" for="tableShowActivity">Activity</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="form-check">
|
<div class="form-check">
|
||||||
<input class="form-check-input storeable-checkbox" type="checkbox" id="tableShowRef"
|
<input class="form-check-input storeable-checkbox" type="checkbox" id="tableShowRef"
|
||||||
value="tableShowRef" oninput="columnsUpdated();" checked>
|
value="tableShowRef" oninput="columnsUpdated();" checked>
|
||||||
<label class="form-check-label" for="tableShowRef">Ref.</label>
|
<label class="form-check-label" for="tableShowRef">Reference</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import tornado_eventsource.handler
|
|||||||
from tornado import httputil
|
from tornado import httputil
|
||||||
from tornado.web import Application
|
from tornado.web import Application
|
||||||
|
|
||||||
from core.enums import AlertType
|
|
||||||
from core.utils import safe_json_dumps
|
from core.utils import safe_json_dumps
|
||||||
from data.lookup_credentials import extract_credentials
|
from data.lookup_credentials import extract_credentials
|
||||||
|
|
||||||
@@ -169,13 +168,13 @@ def alert_allowed_by_query(alert, query):
|
|||||||
# the alert is a dxpedition, or contests_skip_max_duration_check and the alert is a contest, it also
|
# the alert is a dxpedition, or contests_skip_max_duration_check and the alert is a contest, it also
|
||||||
# always passes the check.
|
# always passes the check.
|
||||||
if (
|
if (
|
||||||
alert.alert_type == AlertType.DXPEDITION
|
alert.sig == "DXpedition"
|
||||||
and "dxpeditions_skip_max_duration_check" in query
|
and "dxpeditions_skip_max_duration_check" in query
|
||||||
and query.get("dxpeditions_skip_max_duration_check").upper() == "TRUE"
|
and query.get("dxpeditions_skip_max_duration_check").upper() == "TRUE"
|
||||||
):
|
):
|
||||||
continue
|
continue
|
||||||
if (
|
if (
|
||||||
alert.alert_type == AlertType.CONTEST
|
alert.sig == "Contest"
|
||||||
and "contests_skip_max_duration_check" in query
|
and "contests_skip_max_duration_check" in query
|
||||||
and query.get("contests_skip_max_duration_check").upper() == "TRUE"
|
and query.get("contests_skip_max_duration_check").upper() == "TRUE"
|
||||||
):
|
):
|
||||||
|
|||||||
Reference in New Issue
Block a user