95 lines
No EOL
3.2 KiB
Python
95 lines
No EOL
3.2 KiB
Python
from fastapi import FastAPI, HTTPException
|
|
from fastapi.middleware.cors import CORSMiddleware
|
|
from contextlib import asynccontextmanager
|
|
import asyncpg
|
|
import json
|
|
from datetime import date, datetime
|
|
|
|
DB_URL = "postgresql://teeoff_admin:teeoff_secret_password@db:5432/teeoff"
|
|
|
|
@asynccontextmanager
|
|
async def lifespan(app: FastAPI):
|
|
try:
|
|
app.state.pool = await asyncpg.create_pool(DB_URL, min_size=5, max_size=20)
|
|
print("✅ Database tilkoblet og pool opprettet")
|
|
except Exception as e:
|
|
print(f"❌ Databasefeil: {e}")
|
|
raise e
|
|
yield
|
|
await app.state.pool.close()
|
|
|
|
app = FastAPI(title="TeeOff API v2.4", lifespan=lifespan)
|
|
|
|
app.add_middleware(
|
|
CORSMiddleware,
|
|
allow_origins=["*"],
|
|
allow_methods=["*"],
|
|
allow_headers=["*"],
|
|
)
|
|
|
|
def format_row(row):
|
|
if row is None: return None
|
|
d = dict(row)
|
|
|
|
# 1. Dato-håndtering
|
|
for key in ['status_updated_at', 'created_at']:
|
|
if isinstance(d.get(key), (date, datetime)):
|
|
d[key] = d[key].isoformat()
|
|
|
|
# 2. Garanter riktige datatyper (Vaskeliste)
|
|
list_fields = ['course_statuses', 'courses', 'gallery', 'greenfee', 'faqs', 'shotzoom', 'social_links', 'holes']
|
|
dict_fields = ['amenities', 'vtg', 'nsg_data', 'golfamore_data']
|
|
|
|
for field in list_fields:
|
|
if field in d:
|
|
if d[field] is None:
|
|
d[field] = []
|
|
elif isinstance(d[field], str):
|
|
try: d[field] = json.loads(d[field])
|
|
except: d[field] = []
|
|
|
|
for field in dict_fields:
|
|
if field in d:
|
|
if d[field] is None:
|
|
d[field] = {}
|
|
elif isinstance(d[field], str):
|
|
try: d[field] = json.loads(d[field])
|
|
except: d[field] = {}
|
|
|
|
return d
|
|
|
|
@app.get("/api/facilities")
|
|
async def get_facilities():
|
|
async with app.state.pool.acquire() as conn:
|
|
rows = await conn.fetch("""
|
|
SELECT f.*, (
|
|
SELECT jsonb_agg(cs) FROM (
|
|
SELECT name, status FROM courses
|
|
WHERE facility_id = f.id AND status != 'finnes_ingen_bane_to'
|
|
ORDER BY is_main_course DESC, id ASC
|
|
) cs
|
|
) as course_statuses
|
|
FROM facilities f ORDER BY f.name ASC
|
|
""")
|
|
return [format_row(row) for row in rows]
|
|
|
|
@app.get("/api/facilities/{slug}")
|
|
async def get_facility(slug: str):
|
|
async with app.state.pool.acquire() as conn:
|
|
row = await conn.fetchrow("""
|
|
SELECT f.*, (
|
|
SELECT jsonb_agg(c_data) FROM (
|
|
SELECT c.*, (
|
|
SELECT jsonb_agg(h_data ORDER BY h_data.hole_number ASC)
|
|
FROM (SELECT * FROM holes WHERE course_id = c.id) h_data
|
|
) as holes
|
|
FROM courses c
|
|
WHERE c.facility_id = f.id
|
|
AND (c.is_main_course = true OR (c.status NOT IN ('finnes_ingen_bane_to', 'ukjent')))
|
|
ORDER BY c.is_main_course DESC, c.id ASC
|
|
) c_data
|
|
) as courses
|
|
FROM facilities f WHERE f.slug = $1
|
|
""", slug)
|
|
if not row: raise HTTPException(status_code=404)
|
|
return format_row(row) |