teecup/app/target_points.py
Erol Haagenrud 93af7c5bef Rangefinder-koordinater for offisielle (TeeOff-koblede) baner
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>
2026-08-17 12:06:47 +02:00

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]