Rangefinder-funksjonalitet fantes til nå kun for GolfAPI-importerte personlige baner. Offisielle teeoff-koblede baner (org-turneringer OG frittstående runder spilt på en ekte teeoff-bane) hadde aldri noen koordinatkilde. Ny migrasjon 079: delte domener (course_poi_type/ location/side) for å unngå duplisert CHECK-vedlikehold på tvers av tabeller, ny global tabell teeoff_course_coordinate. Ny delt modul app/target_points.py + resolve_match_course_key() i hole_history.py (tredje søster til de to eksisterende bane-bro- funksjonene) -- alle tre kallesteder (frittstående runder, individuell org-turnering, lag-matchplay) bruker nå samme CourseKey-abstraksjon. rounds.py sitt eksisterende endepunkt refaktorert til samme mønster -- sideeffekt: frittstående runder på en ekte teeoff-bane får nå også rangefinder (var alltid tom liste før). Ny skrive-vei i courses.py (PUT/GET .../coordinates) -- generell, gjenbrukbar mulighet for å legge inn koordinater på enhver offisiell bane, ikke en engangsfiks. HoleTargetDistance generalisert (roundId -> baseUrl) og wiret inn i begge org-turnering-scoringsflytene. 11 nye tester (106/106 backend totalt), full scratch-verifisert ende-til-ende i nettleser i alle tre flyter inkl. lys/mørk og selvskjuling, regresjonssjekk av eksisterende GolfAPI-rangefinder bekreftet uendret oppførsel. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
60 lines
2.2 KiB
Python
60 lines
2.2 KiB
Python
"""
|
|
Rangefinder-koordinater (migrasjon 065/079) -- avstand til green/hindringer,
|
|
GPS-basert. Delt mellom rounds.py (frittstående runder), individual_
|
|
tournaments.py (org-turnering, individuell slagspill) og scoring.py
|
|
(org-turnering, lag-matchplay) -- alle tre løser sin egen kontekst om til
|
|
samme `CourseKey` (se hole_history.py, som denne modulen gjenbruker banen-
|
|
bro-abstraksjonen fra) og kaller `get_target_points()` her.
|
|
|
|
To kildetabeller, ingen RLS på noen av dem (globale, delt på tvers av
|
|
organisasjoner/brukere som tilfeldigvis bruker samme fysiske bane -- samme
|
|
begrunnelse som golfapi_course_coordinate alltid har hatt): `golfapi_
|
|
course_coordinate` (GolfAPI-importerte baner) og `teeoff_course_coordinate`
|
|
(ekte teeoff-baner, migrasjon 079). Fordi ingen av dem er RLS-beskyttet,
|
|
virker `get_target_points()` uendret uansett om `conn` kommer fra
|
|
`plain_connection()` eller `org_connection()`.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from asyncpg import Connection
|
|
from pydantic import BaseModel
|
|
|
|
from .hole_history import CourseKey
|
|
|
|
|
|
class TargetPoint(BaseModel):
|
|
poi_type: str
|
|
location: str | None
|
|
side_fairway: str | None
|
|
latitude: float
|
|
longitude: float
|
|
|
|
|
|
async def get_target_points(conn: Connection, course_key: CourseKey | None, hole_number: int) -> list[TargetPoint]:
|
|
if course_key is None:
|
|
return []
|
|
kind = course_key[0]
|
|
if kind == "teeoff":
|
|
_, facility_slug, teeoff_course_id = course_key
|
|
rows = await conn.fetch(
|
|
"""
|
|
SELECT poi_type, location, side_fairway, latitude, longitude
|
|
FROM teeoff_course_coordinate
|
|
WHERE external_course_ref = $1 AND hole_number = $2
|
|
""",
|
|
f"{facility_slug}:{teeoff_course_id}",
|
|
hole_number,
|
|
)
|
|
else:
|
|
_, golfapi_course_id = course_key
|
|
rows = await conn.fetch(
|
|
"""
|
|
SELECT poi_type, location, side_fairway, latitude, longitude
|
|
FROM golfapi_course_coordinate
|
|
WHERE golfapi_course_id = $1 AND hole_number = $2
|
|
""",
|
|
golfapi_course_id,
|
|
hole_number,
|
|
)
|
|
return [TargetPoint(**dict(r)) for r in rows]
|