- Removed direct pool checks and replaced them with a centralized database initialization method in `init_db`. - Updated API endpoints in `admin.py`, `collection.py`, `pins.py`, and `watched.py` to ensure the database connection pool is initialized before usage. - Enhanced error handling to raise HTTP exceptions if the database is unavailable. - Improved the `init_db` function in `database.py` to prevent multiple simultaneous initializations using an asyncio lock.
85 lines
2.5 KiB
Python
85 lines
2.5 KiB
Python
"""Manual pins API endpoints"""
|
|
from fastapi import APIRouter, HTTPException
|
|
from pydantic import BaseModel
|
|
from typing import Optional
|
|
from uuid import UUID
|
|
from app.core.database import init_db, pool as db_pool
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
class PinCreate(BaseModel):
|
|
country_code: str
|
|
label: Optional[str] = None
|
|
|
|
|
|
@router.get("")
|
|
async def list_pins():
|
|
"""List all manual pins"""
|
|
await init_db()
|
|
if db_pool is None:
|
|
raise HTTPException(status_code=503, detail="Database not available")
|
|
|
|
async with db_pool.connection() as conn:
|
|
async with conn.cursor() as cur:
|
|
query = """
|
|
SELECT id, country_code, label, pinned_at
|
|
FROM moviemap.manual_pin
|
|
ORDER BY pinned_at DESC
|
|
"""
|
|
await cur.execute(query)
|
|
rows = await cur.fetchall()
|
|
|
|
pins = []
|
|
for row in rows:
|
|
pins.append({
|
|
"id": str(row[0]),
|
|
"country_code": row[1],
|
|
"label": row[2],
|
|
"pinned_at": row[3].isoformat() if row[3] else None,
|
|
})
|
|
|
|
return pins
|
|
|
|
|
|
@router.post("")
|
|
async def create_pin(pin: PinCreate):
|
|
"""Create a new manual pin"""
|
|
await init_db()
|
|
if db_pool is None:
|
|
raise HTTPException(status_code=503, detail="Database not available")
|
|
|
|
async with db_pool.connection() as conn:
|
|
async with conn.cursor() as cur:
|
|
query = """
|
|
INSERT INTO moviemap.manual_pin (country_code, label)
|
|
VALUES (%s, %s)
|
|
RETURNING id
|
|
"""
|
|
await cur.execute(query, (pin.country_code, pin.label))
|
|
result = await cur.fetchone()
|
|
await conn.commit()
|
|
|
|
return {"id": str(result[0]), "status": "created"}
|
|
|
|
|
|
@router.delete("/{pin_id}")
|
|
async def delete_pin(pin_id: UUID):
|
|
"""Delete a manual pin"""
|
|
await init_db()
|
|
if db_pool is None:
|
|
raise HTTPException(status_code=503, detail="Database not available")
|
|
|
|
async with db_pool.connection() as conn:
|
|
async with conn.cursor() as cur:
|
|
query = "DELETE FROM moviemap.manual_pin WHERE id = %s RETURNING id"
|
|
await cur.execute(query, (str(pin_id),))
|
|
result = await cur.fetchone()
|
|
await conn.commit()
|
|
|
|
if not result:
|
|
raise HTTPException(status_code=404, detail="Pin not found")
|
|
|
|
return {"id": str(result[0]), "status": "deleted"}
|
|
|