Add a has_refs field to activities #147

This commit is contained in:
Ian Renton
2026-09-18 18:28:30 +01:00
parent e5caf7353d
commit 40033d122e
15 changed files with 158 additions and 124 deletions
+135 -93
View File
@@ -1,444 +1,486 @@
from core.enums import ActivityName, ActivityType, ActivityRefType from core.enums import ActivityName, ActivityRefType, ActivityType
from data.activity import Activity from data.activity import Activity
ACTIVITIES: dict[ActivityName, Activity] = { ACTIVITIES: dict[ActivityName, Activity] = {
ActivityName.CONTEST: Activity( ActivityName.CONTEST: Activity(
name=ActivityName.CONTEST, name=ActivityName.CONTEST,
description="Contest",
sig_type=ActivityType.TRADITIONAL,
has_refs=False,
refs_globally_unique=False,
# No sensible way to determine *which* contest, but if we set comment_names=["CONTEST"] then at least # No sensible way to determine *which* contest, but if we set comment_names=["CONTEST"] then at least
# any spots with "contest" in the comment will get allocated to this activity. # any spots with "contest" in the comment will get allocated to this activity.
comment_names=["CONTEST"], comment_names=["CONTEST"],
description="Contest",
sig_type=ActivityType.TRADITIONAL,
icon="fa-trophy", icon="fa-trophy",
refs_globally_unique=False,
), ),
ActivityName.DXPEDITION: Activity( ActivityName.DXPEDITION: Activity(
name=ActivityName.DXPEDITION, name=ActivityName.DXPEDITION,
description="Radio expedition to a remote location",
sig_type=ActivityType.TRADITIONAL,
has_refs=False,
refs_globally_unique=False,
# DXpedition stations are never really spotted with "DXpedition" in the comments, but we can assign # DXpedition stations are never really spotted with "DXpedition" in the comments, but we can assign
# this activity to a spot other ways. # this activity to a spot other ways.
comment_names=[], comment_names=[],
description="Radio expedition to a remote location",
sig_type=ActivityType.TRADITIONAL,
icon="fa-book-atlas", icon="fa-book-atlas",
refs_globally_unique=False,
), ),
ActivityName.SATELLITE: Activity( ActivityName.SATELLITE: Activity(
name=ActivityName.SATELLITE, name=ActivityName.SATELLITE,
comment_names=[],
description="Amateur Radio Satellite", description="Amateur Radio Satellite",
sig_type=ActivityType.TRADITIONAL, sig_type=ActivityType.TRADITIONAL,
icon="fa-satellite", has_refs=False,
refs_globally_unique=False, refs_globally_unique=False,
comment_names=[],
icon="fa-satellite",
), ),
ActivityName.EME: Activity( ActivityName.EME: Activity(
name=ActivityName.EME, name=ActivityName.EME,
comment_names=[],
description="Earth-Moon-Earth (Moonbounce)", description="Earth-Moon-Earth (Moonbounce)",
sig_type=ActivityType.TRADITIONAL, sig_type=ActivityType.TRADITIONAL,
icon="fa-moon", has_refs=False,
refs_globally_unique=False, refs_globally_unique=False,
comment_names=[],
icon="fa-moon",
), ),
ActivityName.AERONAUTICAL_MOBILE: Activity( ActivityName.AERONAUTICAL_MOBILE: Activity(
name=ActivityName.AERONAUTICAL_MOBILE, name=ActivityName.AERONAUTICAL_MOBILE,
# Don't pick /AM out of comments, spot.py will handle picking it out of the callsign
comment_names=[],
description="Aeronautical Mobile", description="Aeronautical Mobile",
sig_type=ActivityType.TRADITIONAL, sig_type=ActivityType.TRADITIONAL,
icon="fa-plane", has_refs=False,
refs_globally_unique=False, refs_globally_unique=False,
# Don't pick /AM out of comments, spot.py will handle picking it out of the callsign
comment_names=[],
icon="fa-plane",
), ),
ActivityName.MARITIME_MOBILE: Activity( ActivityName.MARITIME_MOBILE: Activity(
name=ActivityName.MARITIME_MOBILE, name=ActivityName.MARITIME_MOBILE,
# Don't pick /MM out of comments, spot.py will handle picking it out of the callsign
comment_names=[],
description="Maritime Mobile", description="Maritime Mobile",
sig_type=ActivityType.TRADITIONAL, sig_type=ActivityType.TRADITIONAL,
icon="fa-sailboat", has_refs=False,
refs_globally_unique=False, refs_globally_unique=False,
# Don't pick /MM out of comments, spot.py will handle picking it out of the callsign
comment_names=[],
icon="fa-sailboat",
), ),
ActivityName.QRP: Activity( ActivityName.QRP: Activity(
name=ActivityName.QRP, name=ActivityName.QRP,
comment_names=["QRP"],
description="Low power", description="Low power",
sig_type=ActivityType.TRADITIONAL, sig_type=ActivityType.TRADITIONAL,
icon="fa-volume-low", has_refs=False,
refs_globally_unique=False, refs_globally_unique=False,
comment_names=["QRP"],
icon="fa-volume-low",
), ),
ActivityName.POTA: Activity( ActivityName.POTA: Activity(
name=ActivityName.POTA, name=ActivityName.POTA,
comment_names=["POTA"],
description="Parks on the Air", description="Parks on the Air",
sig_type=ActivityType.ADVENTURE, sig_type=ActivityType.ADVENTURE,
has_refs=True,
refs_globally_unique=False,
ref_type=ActivityRefType.PARK, ref_type=ActivityRefType.PARK,
ref_regex=r"[A-Z]{2}\-\d{4,5}|K\-TEST", ref_regex=r"[A-Z]{2}\-\d{4,5}|K\-TEST",
comment_names=["POTA"],
icon="fa-tree", icon="fa-tree",
refs_globally_unique=False,
), ),
ActivityName.SOTA: Activity( ActivityName.SOTA: Activity(
name=ActivityName.SOTA, name=ActivityName.SOTA,
comment_names=["SOTA"],
description="Summits on the Air", description="Summits on the Air",
sig_type=ActivityType.ADVENTURE, sig_type=ActivityType.ADVENTURE,
has_refs=True,
refs_globally_unique=False,
ref_type=ActivityRefType.SUMMIT, ref_type=ActivityRefType.SUMMIT,
ref_regex=r"[A-Z0-9]{1,3}\/[A-Z]{2}\-\d{3}", ref_regex=r"[A-Z0-9]{1,3}\/[A-Z]{2}\-\d{3}",
comment_names=["SOTA"],
icon="fa-mountain-sun", icon="fa-mountain-sun",
refs_globally_unique=False,
), ),
ActivityName.WWFF: Activity( ActivityName.WWFF: Activity(
name=ActivityName.WWFF, name=ActivityName.WWFF,
comment_names=["WWFF"],
description="World Wide Flora & Fauna", description="World Wide Flora & Fauna",
sig_type=ActivityType.ADVENTURE, sig_type=ActivityType.ADVENTURE,
has_refs=True,
refs_globally_unique=True,
ref_type=ActivityRefType.PARK, ref_type=ActivityRefType.PARK,
ref_regex=r"[A-Z0-9]{1,3}FF\-\d{4}", ref_regex=r"[A-Z0-9]{1,3}FF\-\d{4}",
comment_names=["WWFF"],
icon="fa-seedling", icon="fa-seedling",
refs_globally_unique=True,
), ),
ActivityName.GMA: Activity( ActivityName.GMA: Activity(
name=ActivityName.GMA, name=ActivityName.GMA,
comment_names=["GMA"],
description="Global Mountain Activity", description="Global Mountain Activity",
sig_type=ActivityType.ADVENTURE, sig_type=ActivityType.ADVENTURE,
has_refs=True,
refs_globally_unique=False,
ref_type=ActivityRefType.SUMMIT, ref_type=ActivityRefType.SUMMIT,
ref_regex=r"[A-Z0-9]{1,3}\/[A-Z]{2}\-\d{3}", ref_regex=r"[A-Z0-9]{1,3}\/[A-Z]{2}\-\d{3}",
comment_names=["GMA"],
icon="fa-person-hiking", icon="fa-person-hiking",
refs_globally_unique=False,
), ),
ActivityName.WWBOTA: Activity( ActivityName.WWBOTA: Activity(
name=ActivityName.WWBOTA, name=ActivityName.WWBOTA,
comment_names=["WWBOTA", "BOTA"],
description="Worldwide Bunkers on the Air", description="Worldwide Bunkers on the Air",
sig_type=ActivityType.ADVENTURE, sig_type=ActivityType.ADVENTURE,
has_refs=True,
refs_globally_unique=True,
ref_type=ActivityRefType.BUNKER, ref_type=ActivityRefType.BUNKER,
ref_regex=r"B\/[A-Z0-9]{1,3}\-\d{3,4}", ref_regex=r"B\/[A-Z0-9]{1,3}\-\d{3,4}",
comment_names=["WWBOTA", "BOTA"],
icon="fa-radiation", icon="fa-radiation",
refs_globally_unique=True,
), ),
ActivityName.HEMA: Activity( ActivityName.HEMA: Activity(
name=ActivityName.HEMA, name=ActivityName.HEMA,
comment_names=["HEMA"],
description="HuMPs Excluding Marilyns Award", description="HuMPs Excluding Marilyns Award",
sig_type=ActivityType.ADVENTURE, sig_type=ActivityType.ADVENTURE,
has_refs=True,
refs_globally_unique=False,
ref_type=ActivityRefType.SUMMIT, ref_type=ActivityRefType.SUMMIT,
ref_regex=r"[A-Z0-9]{1,3}\/[A-Z]{3}\-\d{3}", ref_regex=r"[A-Z0-9]{1,3}\/[A-Z]{3}\-\d{3}",
comment_names=["HEMA"],
icon="fa-mound", icon="fa-mound",
refs_globally_unique=False,
), ),
ActivityName.IOTA: Activity( ActivityName.IOTA: Activity(
name=ActivityName.IOTA, name=ActivityName.IOTA,
comment_names=["IOTA"],
description="Islands on the Air", description="Islands on the Air",
sig_type=ActivityType.ADVENTURE, sig_type=ActivityType.ADVENTURE,
has_refs=True,
refs_globally_unique=False,
ref_type=ActivityRefType.ISLAND, ref_type=ActivityRefType.ISLAND,
ref_regex=r"[A-Z]{2}\-\d{3}", ref_regex=r"[A-Z]{2}\-\d{3}",
comment_names=["IOTA"],
icon="fa-book-atlas", icon="fa-book-atlas",
refs_globally_unique=False,
), ),
ActivityName.GMA_ISLANDS: Activity( ActivityName.GMA_ISLANDS: Activity(
name=ActivityName.GMA_ISLANDS, name=ActivityName.GMA_ISLANDS,
comment_names=[],
description="Global Mountain Activity - Islands", description="Global Mountain Activity - Islands",
sig_type=ActivityType.ADVENTURE, sig_type=ActivityType.ADVENTURE,
has_refs=True,
refs_globally_unique=False,
ref_type=ActivityRefType.ISLAND, ref_type=ActivityRefType.ISLAND,
ref_regex=r"(([A-Z]{2}\-\d{3})|([A-Z0-9]{1,3}\/[A-Z]{2}\-\d{3}))", ref_regex=r"(([A-Z]{2}\-\d{3})|([A-Z0-9]{1,3}\/[A-Z]{2}\-\d{3}))",
comment_names=[],
icon="fa-person-hiking", icon="fa-person-hiking",
refs_globally_unique=False,
), ),
ActivityName.ARLHS: Activity( ActivityName.ARLHS: Activity(
name=ActivityName.ARLHS, name=ActivityName.ARLHS,
comment_names=["ARLHS"],
description="Amateur Radio Lighthouse Society", description="Amateur Radio Lighthouse Society",
sig_type=ActivityType.ADVENTURE, sig_type=ActivityType.ADVENTURE,
has_refs=True,
refs_globally_unique=False,
ref_type=ActivityRefType.LIGHTHOUSE, ref_type=ActivityRefType.LIGHTHOUSE,
ref_regex=r"[A-Z]{3}[\- ]\d{3,4}", ref_regex=r"[A-Z]{3}[\- ]\d{3,4}",
comment_names=["ARLHS"],
icon="fa-house-flood-water", icon="fa-house-flood-water",
refs_globally_unique=False,
), ),
ActivityName.ILLW: Activity( ActivityName.ILLW: Activity(
name=ActivityName.ILLW, name=ActivityName.ILLW,
comment_names=["ILLW"],
description="International Lighthouse & Lightship Weekend", description="International Lighthouse & Lightship Weekend",
sig_type=ActivityType.EVENT, sig_type=ActivityType.EVENT,
has_refs=True,
refs_globally_unique=False,
ref_type=ActivityRefType.LIGHTHOUSE, ref_type=ActivityRefType.LIGHTHOUSE,
ref_regex=r"[A-Z]{2}\d{4}", ref_regex=r"[A-Z]{2}\d{4}",
comment_names=["ILLW"],
icon="fa-house-flood-water", icon="fa-house-flood-water",
refs_globally_unique=False,
), ),
ActivityName.MOTA: Activity( ActivityName.MOTA: Activity(
name=ActivityName.MOTA, name=ActivityName.MOTA,
comment_names=["MOTA"],
description="Mills on the Air", description="Mills on the Air",
sig_type=ActivityType.EVENT, sig_type=ActivityType.EVENT,
has_refs=True,
refs_globally_unique=True,
ref_type=ActivityRefType.MILL, ref_type=ActivityRefType.MILL,
ref_regex=r"X\d{4,6}", ref_regex=r"X\d{4,6}",
comment_names=["MOTA"],
icon="fa-fan", icon="fa-fan",
refs_globally_unique=True,
), ),
ActivityName.SIOTA: Activity( ActivityName.SIOTA: Activity(
name=ActivityName.SIOTA, name=ActivityName.SIOTA,
comment_names=["SIOTA"],
description="Silos on the Air", description="Silos on the Air",
sig_type=ActivityType.ADVENTURE, sig_type=ActivityType.ADVENTURE,
has_refs=True,
refs_globally_unique=False,
ref_type=ActivityRefType.SILO, ref_type=ActivityRefType.SILO,
ref_regex=r"[A-Z]{2}\-[A-Z]{3}\d", ref_regex=r"[A-Z]{2}\-[A-Z]{3}\d",
comment_names=["SIOTA"],
icon="fa-wheat-awn", icon="fa-wheat-awn",
refs_globally_unique=False,
), ),
ActivityName.WCA: Activity( ActivityName.WCA: Activity(
name=ActivityName.WCA, name=ActivityName.WCA,
comment_names=["WCA"],
description="World Castles Award", description="World Castles Award",
sig_type=ActivityType.ADVENTURE, sig_type=ActivityType.ADVENTURE,
has_refs=True,
refs_globally_unique=False,
ref_type=ActivityRefType.CASTLE, ref_type=ActivityRefType.CASTLE,
ref_regex=r"[A-Z0-9]{1,3}\-\d{5}", ref_regex=r"[A-Z0-9]{1,3}\-\d{5}",
comment_names=["WCA"],
icon="fa-chess-rook", icon="fa-chess-rook",
refs_globally_unique=False,
), ),
ActivityName.ZLOTA: Activity( ActivityName.ZLOTA: Activity(
name=ActivityName.ZLOTA, name=ActivityName.ZLOTA,
comment_names=["ZLOTA"],
description="New Zealand on the Air", description="New Zealand on the Air",
sig_type=ActivityType.REGIONAL, sig_type=ActivityType.REGIONAL,
has_refs=True,
refs_globally_unique=True,
ref_type=None, ref_type=None,
ref_regex=r"ZL[A-Z]/[A-Z]{2}\-\d{3,4}", ref_regex=r"ZL[A-Z]/[A-Z]{2}\-\d{3,4}",
comment_names=["ZLOTA"],
icon="fa-kiwi-bird", icon="fa-kiwi-bird",
region_flag="🇳🇿", region_flag="🇳🇿",
refs_globally_unique=True,
), ),
ActivityName.WOTA: Activity( ActivityName.WOTA: Activity(
name=ActivityName.WOTA, name=ActivityName.WOTA,
comment_names=["WOTA"],
description="Wainwrights on the Air", description="Wainwrights on the Air",
sig_type=ActivityType.REGIONAL, sig_type=ActivityType.REGIONAL,
has_refs=True,
refs_globally_unique=False,
ref_type=ActivityRefType.SUMMIT, ref_type=ActivityRefType.SUMMIT,
ref_regex=r"[A-Z]{3}-[0-9]{2}", ref_regex=r"[A-Z]{3}-[0-9]{2}",
comment_names=["WOTA"],
icon="fa-w", icon="fa-w",
region_flag="🇬🇧", region_flag="🇬🇧",
refs_globally_unique=False,
), ),
ActivityName.BOTA: Activity( ActivityName.BOTA: Activity(
name=ActivityName.BOTA, name=ActivityName.BOTA,
comment_names=[],
description="Beaches on the Air", description="Beaches on the Air",
sig_type=ActivityType.ADVENTURE, sig_type=ActivityType.ADVENTURE,
ref_type=ActivityRefType.BEACH, has_refs=True,
icon="fa-umbrella-beach",
refs_globally_unique=False, refs_globally_unique=False,
ref_type=ActivityRefType.BEACH,
comment_names=[],
icon="fa-umbrella-beach",
), ),
ActivityName.KRMNPA: Activity( ActivityName.KRMNPA: Activity(
name=ActivityName.KRMNPA, name=ActivityName.KRMNPA,
comment_names=["KRMNPA"],
description="Keith Roget Memorial National Parks Award", description="Keith Roget Memorial National Parks Award",
sig_type=ActivityType.REGIONAL, sig_type=ActivityType.REGIONAL,
has_refs=True,
refs_globally_unique=False,
ref_type=ActivityRefType.PARK, ref_type=ActivityRefType.PARK,
ref_regex=r"VKFF\-\d{4}", ref_regex=r"VKFF\-\d{4}",
comment_names=["KRMNPA"],
icon="fa-earth-oceania", icon="fa-earth-oceania",
region_flag="🇦🇺", region_flag="🇦🇺",
refs_globally_unique=False,
), ),
ActivityName.SANPCPA: Activity( ActivityName.SANPCPA: Activity(
name=ActivityName.SANPCPA, name=ActivityName.SANPCPA,
comment_names=["SANPCPA"],
description="South Australian National Parks and Conservation Parks Award", description="South Australian National Parks and Conservation Parks Award",
sig_type=ActivityType.REGIONAL, sig_type=ActivityType.REGIONAL,
has_refs=True,
refs_globally_unique=False,
ref_type=ActivityRefType.PARK, ref_type=ActivityRefType.PARK,
ref_regex=r"VKFF\-\d{4}", ref_regex=r"VKFF\-\d{4}",
comment_names=["SANPCPA"],
icon="fa-earth-oceania", icon="fa-earth-oceania",
region_flag="🇦🇺", region_flag="🇦🇺",
refs_globally_unique=False,
), ),
ActivityName.LLOTA: Activity( ActivityName.LLOTA: Activity(
name=ActivityName.LLOTA, name=ActivityName.LLOTA,
comment_names=["LLOTA"],
description="Lagos y Lagunas on the Air", description="Lagos y Lagunas on the Air",
sig_type=ActivityType.ADVENTURE, sig_type=ActivityType.ADVENTURE,
has_refs=True,
refs_globally_unique=True,
ref_type=ActivityRefType.LAKE, ref_type=ActivityRefType.LAKE,
ref_regex=r"LL[A-Z]{2}\-\d{4}", ref_regex=r"LL[A-Z]{2}\-\d{4}",
comment_names=["LLOTA"],
icon="fa-water", icon="fa-water",
refs_globally_unique=True,
), ),
ActivityName.TOWERS: Activity( ActivityName.TOWERS: Activity(
name=ActivityName.TOWERS, name=ActivityName.TOWERS,
comment_names=["TOTA"],
description="Towers on the Air", description="Towers on the Air",
sig_type=ActivityType.ADVENTURE, sig_type=ActivityType.ADVENTURE,
has_refs=True,
refs_globally_unique=False,
ref_type=ActivityRefType.TOWER, ref_type=ActivityRefType.TOWER,
ref_regex=r"[A-Z]{2,3}R\-\d{4}", ref_regex=r"[A-Z]{2,3}R\-\d{4}",
comment_names=["TOTA"],
icon="fa-tower-observation", icon="fa-tower-observation",
refs_globally_unique=False,
), ),
ActivityName.TILES: Activity( ActivityName.TILES: Activity(
name=ActivityName.TILES, name=ActivityName.TILES,
comment_names=[],
description="Tiles on the Air", description="Tiles on the Air",
sig_type=ActivityType.ADVENTURE, sig_type=ActivityType.ADVENTURE,
has_refs=True,
refs_globally_unique=False,
ref_type=ActivityRefType.GRID, ref_type=ActivityRefType.GRID,
ref_regex=r"[A-Za-z]{2}[0-9]{2}[A-Za-z]{2}", ref_regex=r"[A-Za-z]{2}[0-9]{2}[A-Za-z]{2}",
comment_names=[],
icon="fa-square", icon="fa-square",
refs_globally_unique=False,
), ),
ActivityName.RADAR_RALLY: Activity( ActivityName.RADAR_RALLY: Activity(
name=ActivityName.RADAR_RALLY, name=ActivityName.RADAR_RALLY,
comment_names=["RaDAR"],
description="RaDAR Rally", description="RaDAR Rally",
sig_type=ActivityType.EVENT, sig_type=ActivityType.EVENT,
icon="fa-headset", has_refs=False,
refs_globally_unique=False, refs_globally_unique=False,
comment_names=["RaDAR"],
icon="fa-headset",
), ),
ActivityName.WAB: Activity( ActivityName.WAB: Activity(
name=ActivityName.WAB, name=ActivityName.WAB,
comment_names=["WAB"],
description="Worked All Britain", description="Worked All Britain",
sig_type=ActivityType.REGIONAL, sig_type=ActivityType.REGIONAL,
has_refs=True,
refs_globally_unique=False,
ref_type=ActivityRefType.GRID, ref_type=ActivityRefType.GRID,
ref_regex=r"[A-Z]{1,2}[0-9]{2}", ref_regex=r"[A-Z]{1,2}[0-9]{2}",
comment_names=["WAB"],
icon="fa-table-cells-large", icon="fa-table-cells-large",
region_flag="🇬🇧", region_flag="🇬🇧",
refs_globally_unique=False,
), ),
ActivityName.WAI: Activity( ActivityName.WAI: Activity(
name=ActivityName.WAI, name=ActivityName.WAI,
comment_names=["WAI"],
description="Worked All Ireland", description="Worked All Ireland",
sig_type=ActivityType.REGIONAL, sig_type=ActivityType.REGIONAL,
has_refs=True,
refs_globally_unique=False,
ref_type=ActivityRefType.GRID, ref_type=ActivityRefType.GRID,
ref_regex=r"[A-Z][0-9]{2}", ref_regex=r"[A-Z][0-9]{2}",
comment_names=["WAI"],
icon="fa-table-cells-large", icon="fa-table-cells-large",
region_flag="🇮🇪", region_flag="🇮🇪",
refs_globally_unique=False,
), ),
ActivityName.DMF: Activity( ActivityName.DMF: Activity(
name=ActivityName.DMF, name=ActivityName.DMF,
comment_names=["DMF"],
description="Diplôme des Moulins de France", description="Diplôme des Moulins de France",
sig_type=ActivityType.REGIONAL, sig_type=ActivityType.REGIONAL,
has_refs=True,
refs_globally_unique=False,
ref_type=ActivityRefType.MILL, ref_type=ActivityRefType.MILL,
comment_names=["DMF"],
icon="fa-fan", icon="fa-fan",
region_flag="🇫🇷", region_flag="🇫🇷",
refs_globally_unique=False,
), ),
ActivityName.DME: Activity( ActivityName.DME: Activity(
name=ActivityName.DME, name=ActivityName.DME,
comment_names=["DME"],
description="Diploma Municipios de España", description="Diploma Municipios de España",
sig_type=ActivityType.REGIONAL, sig_type=ActivityType.REGIONAL,
has_refs=True,
refs_globally_unique=True,
ref_type=ActivityRefType.TOWN, ref_type=ActivityRefType.TOWN,
ref_regex=r"DME[\- ]\d{3,5}", ref_regex=r"DME[\- ]\d{3,5}",
comment_names=["DME"],
icon="fa-building", icon="fa-building",
region_flag="🇪🇸", region_flag="🇪🇸",
refs_globally_unique=True,
), ),
ActivityName.FEA: Activity( ActivityName.FEA: Activity(
name=ActivityName.FEA, name=ActivityName.FEA,
comment_names=["FEA"],
description="Diploma Faros de España", description="Diploma Faros de España",
sig_type=ActivityType.REGIONAL, sig_type=ActivityType.REGIONAL,
has_refs=True,
refs_globally_unique=True,
ref_type=ActivityRefType.LIGHTHOUSE, ref_type=ActivityRefType.LIGHTHOUSE,
# FEA references are technically [DE]\-\d{4}(\.\d)? but spotters always seem to miss out the D- or E- # FEA references are technically [DE]\-\d{4}(\.\d)? but spotters always seem to miss out the D- or E-
# prefix and just use FEA-1234 or FEA 1234, so allow for that. The FEA activity ref data provider adds both # prefix and just use FEA-1234 or FEA 1234, so allow for that. The FEA activity ref data provider adds both
# forms to the database. # forms to the database.
ref_regex=r"([DE]|FEA)[\- ]\d{4}(\.\d)?", ref_regex=r"([DE]|FEA)[\- ]\d{4}(\.\d)?",
comment_names=["FEA"],
icon="fa-house-flood-water", icon="fa-house-flood-water",
region_flag="🇪🇸", region_flag="🇪🇸",
refs_globally_unique=True,
), ),
ActivityName.DMUE: Activity( ActivityName.DMUE: Activity(
name=ActivityName.DMUE, name=ActivityName.DMUE,
comment_names=["DMUE"],
description="Diploma Museos de España", description="Diploma Museos de España",
sig_type=ActivityType.REGIONAL, sig_type=ActivityType.REGIONAL,
has_refs=True,
refs_globally_unique=True,
ref_type=ActivityRefType.BUILDING, ref_type=ActivityRefType.BUILDING,
ref_regex=r"MUE[A-Z]{2}-\d{3}", ref_regex=r"MUE[A-Z]{2}-\d{3}",
comment_names=["DMUE"],
icon="fa-landmark", icon="fa-landmark",
region_flag="🇪🇸", region_flag="🇪🇸",
refs_globally_unique=True,
), ),
ActivityName.DMVE: Activity( ActivityName.DMVE: Activity(
name=ActivityName.DMVE, name=ActivityName.DMVE,
comment_names=["DMVE"],
description="Diploma Monumentos y Vestigios de España", description="Diploma Monumentos y Vestigios de España",
sig_type=ActivityType.REGIONAL, sig_type=ActivityType.REGIONAL,
has_refs=True,
refs_globally_unique=True,
ref_type=ActivityRefType.BUILDING, ref_type=ActivityRefType.BUILDING,
ref_regex=r"MV[A-Z]{1,2}-\d{4}", ref_regex=r"MV[A-Z]{1,2}-\d{4}",
comment_names=["DMVE"],
icon="fa-monument", icon="fa-monument",
region_flag="🇪🇸", region_flag="🇪🇸",
refs_globally_unique=True,
), ),
ActivityName.DCE: Activity( ActivityName.DCE: Activity(
name=ActivityName.DCE, name=ActivityName.DCE,
comment_names=["DCE"],
description="Diploma Castillos de España", description="Diploma Castillos de España",
sig_type=ActivityType.REGIONAL, sig_type=ActivityType.REGIONAL,
has_refs=True,
refs_globally_unique=False,
ref_type=ActivityRefType.CASTLE, ref_type=ActivityRefType.CASTLE,
ref_regex=r"C[A-Z]{1,2}-\d{3}", ref_regex=r"C[A-Z]{1,2}-\d{3}",
comment_names=["DCE"],
icon="fa-chess-rook", icon="fa-chess-rook",
region_flag="🇪🇸", region_flag="🇪🇸",
refs_globally_unique=False,
), ),
ActivityName.DEFE: Activity( ActivityName.DEFE: Activity(
name=ActivityName.DEFE, name=ActivityName.DEFE,
comment_names=["DEFE"],
description="Diploma Estaciones de Ferrocarril de España", description="Diploma Estaciones de Ferrocarril de España",
sig_type=ActivityType.REGIONAL, sig_type=ActivityType.REGIONAL,
has_refs=True,
refs_globally_unique=True,
ref_type=ActivityRefType.BUILDING, ref_type=ActivityRefType.BUILDING,
ref_regex=r"EF[A-Z]{1,2}-\d{3}", ref_regex=r"EF[A-Z]{1,2}-\d{3}",
comment_names=["DEFE"],
icon="fa-train", icon="fa-train",
region_flag="🇪🇸", region_flag="🇪🇸",
refs_globally_unique=True,
), ),
ActivityName.DTMBA: Activity( ActivityName.DTMBA: Activity(
name=ActivityName.DTMBA, name=ActivityName.DTMBA,
comment_names=["DTMBA"],
description="Diploma Teatri Musei e Belle Arti", description="Diploma Teatri Musei e Belle Arti",
sig_type=ActivityType.REGIONAL, sig_type=ActivityType.REGIONAL,
has_refs=True,
refs_globally_unique=True,
ref_type=ActivityRefType.BUILDING, ref_type=ActivityRefType.BUILDING,
ref_regex=r"I-?[0-9]{3,4}\s?[A-Z]{2}", ref_regex=r"I-?[0-9]{3,4}\s?[A-Z]{2}",
comment_names=["DTMBA"],
icon="fa-landmark", icon="fa-landmark",
region_flag="🇮🇹", region_flag="🇮🇹",
refs_globally_unique=True,
), ),
ActivityName.BIWOTA: Activity( ActivityName.BIWOTA: Activity(
name=ActivityName.BIWOTA, name=ActivityName.BIWOTA,
comment_names=["BIWOTA"],
description="British Inland Waterways on the Air", description="British Inland Waterways on the Air",
sig_type=ActivityType.EVENT, sig_type=ActivityType.EVENT,
has_refs=False,
refs_globally_unique=False,
ref_type=ActivityRefType.WATERWAY, ref_type=ActivityRefType.WATERWAY,
comment_names=["BIWOTA"],
icon="fa-ship", icon="fa-ship",
region_flag="🇬🇧", region_flag="🇬🇧",
refs_globally_unique=False,
), ),
ActivityName.COTA: Activity( ActivityName.COTA: Activity(
name=ActivityName.COTA, name=ActivityName.COTA,
comment_names=["COTA"],
description="Castles on the Air", description="Castles on the Air",
sig_type=ActivityType.REGIONAL, sig_type=ActivityType.REGIONAL,
has_refs=True,
refs_globally_unique=False,
ref_type=ActivityRefType.CASTLE, ref_type=ActivityRefType.CASTLE,
ref_regex=r"[A-Z]{3}\-[0-9]{3,5}", ref_regex=r"[A-Z]{3}\-[0-9]{3,5}",
comment_names=["COTA"],
icon="fa-chess-rook", icon="fa-chess-rook",
region_flag="🇩🇪", region_flag="🇩🇪",
refs_globally_unique=False,
), ),
ActivityName.PGA: Activity( ActivityName.PGA: Activity(
name=ActivityName.PGA, name=ActivityName.PGA,
comment_names=["PGA"],
description="Polish Gmina Award", description="Polish Gmina Award",
sig_type=ActivityType.REGIONAL, sig_type=ActivityType.REGIONAL,
has_refs=True,
refs_globally_unique=False,
ref_type=ActivityRefType.REGION, ref_type=ActivityRefType.REGION,
ref_regex=r"[A-Z]{2}[0-9]{2}", ref_regex=r"[A-Z]{2}[0-9]{2}",
comment_names=["PGA"],
icon="fa-g", icon="fa-g",
region_flag="🇵🇱", region_flag="🇵🇱",
refs_globally_unique=False,
), ),
ActivityName.TOILETS: Activity( ActivityName.TOILETS: Activity(
name=ActivityName.TOILETS, name=ActivityName.TOILETS,
comment_names=[],
description="Toilets on the Air", description="Toilets on the Air",
sig_type=ActivityType.EVENT, sig_type=ActivityType.EVENT,
has_refs=True,
refs_globally_unique=True,
ref_type=ActivityRefType.TOILET, ref_type=ActivityRefType.TOILET,
ref_regex=r"T\-[0-9]{2}", ref_regex=r"T\-[0-9]{2}",
comment_names=[],
icon="fa-toilet", icon="fa-toilet",
region_flag="🏴‍☠️", region_flag="🏴‍☠️",
refs_globally_unique=True,
), ),
} }
+6 -3
View File
@@ -21,6 +21,8 @@ class Activity:
# Type, either Worldwide, Regional or Event. Used for sorting in the web UI. # 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. # Note: this field is still named "sig_type" in the API for backwards compatibility.
sig_type: ActivityType sig_type: ActivityType
# Whether this activity has a fixed set of references (e.g. parks) with some sort of ID to "activate"
has_refs: bool
# Identifies that the activity's reference ID structure defined by its regex is unique across all programmes and # 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 # 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 # spot comments without also needing to see the activity name first. For example, "OHFF-1234" or "B/G-1234" are
@@ -28,13 +30,14 @@ class Activity:
# conceivably be POTA or ILLW, etc. So in those cases we need to see the name of the activity itself immediately # conceivably be POTA or ILLW, etc. So in those cases we need to see the name of the activity itself immediately
# before it. # before it.
refs_globally_unique: bool 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 # 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. # things, in which case the spot data will have to provide this instead.
ref_type: ActivityRefType | None = None ref_type: ActivityRefType | None = None
# Regex matcher for references, e.g. for POTA r"[A-Z]{2}\-\d+". # Regex matcher for references, e.g. for POTA r"[A-Z]{2}\-\d+". Only set when has_references is True and we know
# the fixed format references take for this activity.
ref_regex: str | None = None ref_regex: str | None = None
# Activity names as they might appear in cluster spot comments, e.g. ["TOTA"]
comment_names: list[str] = field(default_factory=list)
# Icon to use in the UI when referencing this activity. Chosen from the Font Awesome set. # Icon to use in the UI when referencing this activity. Chosen from the Font Awesome set.
icon: str | None = None icon: str | None = None
# Emoji flag for the country or region where this activity is relevant, if any. If None, this implies the # Emoji flag for the country or region where this activity is relevant, if any. If None, this implies the
+5 -4
View File
@@ -12,6 +12,7 @@ from pyhamtools.locator import latlong_to_locator, locator_to_latlong
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 ( from core.activity_utils import (
ANY_ACTIVITY_REGEX, ANY_ACTIVITY_REGEX,
get_activity_by_name,
get_activity_name_from_comment_name, get_activity_name_from_comment_name,
get_icon_for_activity, get_icon_for_activity,
get_ref_regex_for_activity, get_ref_regex_for_activity,
@@ -296,10 +297,10 @@ class Spot:
# Now look to see if that activity name was followed by something that looks like a reference ID # 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. # for that activity. If so, add that to the sig_refs list for this spot.
ref_regex = get_ref_regex_for_activity(found_activity) found_activity_info = get_activity_by_name(found_activity)
if ref_regex: if found_activity_info and found_activity_info.has_refs and found_activity_info.ref_regex:
ref_matches = re.finditer( ref_matches = re.finditer(
r"(^|\W)" + found_activity + r"([ -])(" + ref_regex + r")($|\W)", r"(^|\W)" + found_activity + r"([ -])(" + found_activity_info.ref_regex + r")($|\W)",
self.comment, self.comment,
re.IGNORECASE, re.IGNORECASE,
) )
@@ -313,7 +314,7 @@ class Spot:
# activity. # activity.
if self.comment: if self.comment:
for activity in ACTIVITIES.values(): for activity in ACTIVITIES.values():
if activity.refs_globally_unique and activity.ref_regex: if activity.has_refs and activity.refs_globally_unique and activity.ref_regex:
ref_matches = re.finditer( ref_matches = re.finditer(
r"(^|\W)(" + activity.ref_regex + r")($|\W)", self.comment, re.IGNORECASE r"(^|\W)(" + activity.ref_regex + r")($|\W)", self.comment, re.IGNORECASE
) )
+1 -2
View File
@@ -2,8 +2,7 @@ import re
from icalendar import Event from icalendar import Event
from core.enums import Continent from core.enums import ActivityName, Continent
from core.enums import ActivityName
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
+1 -2
View File
@@ -4,8 +4,7 @@ from datetime import datetime
import pytz import pytz
from core.constants import HTTP_HEADERS from core.constants import HTTP_HEADERS
from core.enums import Mode from core.enums import ActivityName, ActivityRefType, Mode
from core.enums import ActivityName, ActivityRefType
from core.url_data_cache import URLDataCache from core.url_data_cache import URLDataCache
from data.activity_ref import ActivityRef from data.activity_ref import ActivityRef
from data.spot import Spot from data.spot import Spot
+1 -2
View File
@@ -7,8 +7,7 @@ import requests
from requests.exceptions import ConnectionError, ConnectTimeout, ReadTimeout from requests.exceptions import ConnectionError, ConnectTimeout, ReadTimeout
from core.constants import HTTP_HEADERS from core.constants import HTTP_HEADERS
from core.enums import Mode from core.enums import ActivityName, ActivityRefType, Mode
from core.enums import ActivityName, ActivityRefType
from data.activity_ref import ActivityRef from data.activity_ref import ActivityRef
from data.spot import Spot from data.spot import Spot
from providers.spot.http_spot_provider import HTTPSpotProvider from providers.spot.http_spot_provider import HTTPSpotProvider
+1 -2
View File
@@ -1,7 +1,6 @@
from datetime import datetime from datetime import datetime
from core.enums import Mode from core.enums import ActivityName, ActivityRefType, Mode
from core.enums import ActivityName, ActivityRefType
from data.activity_ref import ActivityRef from data.activity_ref import ActivityRef
from data.spot import Spot from data.spot import Spot
from providers.spot.http_spot_provider import HTTPSpotProvider from providers.spot.http_spot_provider import HTTPSpotProvider
+1 -2
View File
@@ -6,8 +6,7 @@ import pytz
import requests import requests
from core.constants import HTTP_HEADERS from core.constants import HTTP_HEADERS
from core.enums import Mode from core.enums import ActivityName, Mode
from core.enums import ActivityName
from data.activity_ref import ActivityRef from data.activity_ref import ActivityRef
from data.spot import Spot from data.spot import Spot
from providers.spot.http_spot_provider import HTTPSpotProvider from providers.spot.http_spot_provider import HTTPSpotProvider
+1 -2
View File
@@ -4,8 +4,7 @@ import pytz
import requests import requests
from core.constants import HTTP_HEADERS from core.constants import HTTP_HEADERS
from core.enums import Mode from core.enums import ActivityName, ActivityRefType, Mode
from core.enums import ActivityName, ActivityRefType
from data.activity_ref import ActivityRef from data.activity_ref import ActivityRef
from data.spot import Spot from data.spot import Spot
from providers.spot.http_spot_provider import HTTPSpotProvider from providers.spot.http_spot_provider import HTTPSpotProvider
+1 -2
View File
@@ -5,8 +5,7 @@ import requests
from requests.exceptions import ConnectionError, ConnectTimeout, ReadTimeout from requests.exceptions import ConnectionError, ConnectTimeout, ReadTimeout
from core.constants import HTTP_HEADERS from core.constants import HTTP_HEADERS
from core.enums import Mode from core.enums import ActivityName, ActivityRefType, Mode
from core.enums import ActivityName, ActivityRefType
from data.activity_ref import ActivityRef from data.activity_ref import ActivityRef
from data.spot import Spot from data.spot import Spot
from providers.spot.http_spot_provider import HTTPSpotProvider from providers.spot.http_spot_provider import HTTPSpotProvider
+1 -2
View File
@@ -4,8 +4,7 @@ from datetime import datetime
import requests import requests
from core.constants import HTTP_HEADERS from core.constants import HTTP_HEADERS
from core.enums import LocationSourceForSpot, Mode from core.enums import ActivityName, ActivityRefType, LocationSourceForSpot, Mode
from core.enums import ActivityName, ActivityRefType
from data.activity_ref import ActivityRef from data.activity_ref import ActivityRef
from data.spot import Spot from data.spot import Spot
from providers.spot.http_spot_provider import HTTPSpotProvider from providers.spot.http_spot_provider import HTTPSpotProvider
+1 -2
View File
@@ -8,8 +8,7 @@ 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 Mode from core.enums import ActivityName, ActivityRefType, Mode
from core.enums import ActivityName, ActivityRefType
from data.activity_ref import ActivityRef from data.activity_ref import ActivityRef
from data.spot import Spot from data.spot import Spot
from providers.spot.http_spot_provider import HTTPSpotProvider from providers.spot.http_spot_provider import HTTPSpotProvider
+1 -2
View File
@@ -1,8 +1,7 @@
import json import json
from datetime import datetime from datetime import datetime
from core.enums import Mode from core.enums import ActivityName, ActivityRefType, Mode
from core.enums import ActivityName, ActivityRefType
from data.activity_ref import ActivityRef from data.activity_ref import ActivityRef
from data.spot import Spot from data.spot import Spot
from providers.spot.sse_spot_provider import SSESpotProvider from providers.spot.sse_spot_provider import SSESpotProvider
+1 -2
View File
@@ -2,8 +2,7 @@ from datetime import datetime
import pytz import pytz
from core.enums import Mode from core.enums import ActivityName, ActivityRefType, Mode
from core.enums import ActivityName, ActivityRefType
from data.activity_ref import ActivityRef from data.activity_ref import ActivityRef
from data.spot import Spot from data.spot import Spot
from providers.spot.http_spot_provider import HTTPSpotProvider from providers.spot.http_spot_provider import HTTPSpotProvider
+1 -2
View File
@@ -2,8 +2,7 @@ from datetime import datetime
import pytz import pytz
from core.enums import Mode from core.enums import ActivityName, Mode
from core.enums import ActivityName
from data.activity_ref import ActivityRef from data.activity_ref import ActivityRef
from data.spot import Spot from data.spot import Spot
from providers.spot.http_spot_provider import HTTPSpotProvider from providers.spot.http_spot_provider import HTTPSpotProvider