From e3b047f78274a222fbadbbaf4ae9048917a0b703 Mon Sep 17 00:00:00 2001 From: counterweight Date: Mon, 22 Dec 2025 15:43:46 +0100 Subject: [PATCH] feat: add price history GET and POST endpoints --- backend/routes/audit.py | 73 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 72 insertions(+), 1 deletion(-) diff --git a/backend/routes/audit.py b/backend/routes/audit.py index 7d79a03..b9e788e 100644 --- a/backend/routes/audit.py +++ b/backend/routes/audit.py @@ -10,16 +10,25 @@ from sqlalchemy.ext.asyncio import AsyncSession from auth import require_permission from database import get_db -from models import CounterRecord, Permission, RandomNumberOutcome, SumRecord, User +from models import ( + CounterRecord, + Permission, + PriceHistory, + RandomNumberOutcome, + SumRecord, + User, +) from pagination import ( calculate_offset, calculate_total_pages, create_paginated_response, ) +from price_fetcher import fetch_btc_eur_price from schemas import ( CounterRecordResponse, PaginatedCounterRecords, PaginatedSumRecords, + PriceHistoryResponse, RandomNumberOutcomeResponse, SumRecordResponse, ) @@ -140,3 +149,65 @@ async def get_random_job_outcomes( ) for outcome, email in rows ] + + +# ============================================================================= +# Price History Endpoints +# ============================================================================= + +PRICE_HISTORY_LIMIT = 20 + + +@router.get("/price-history", response_model=list[PriceHistoryResponse]) +async def get_price_history( + db: AsyncSession = Depends(get_db), + _current_user: User = Depends(require_permission(Permission.VIEW_AUDIT)), +) -> list[PriceHistoryResponse]: + """Get the 20 most recent price history records.""" + query = ( + select(PriceHistory) + .order_by(desc(PriceHistory.timestamp)) + .limit(PRICE_HISTORY_LIMIT) + ) + result = await db.execute(query) + records = result.scalars().all() + + return [ + PriceHistoryResponse( + id=record.id, + source=record.source, + pair=record.pair, + price=record.price, + timestamp=record.timestamp, + created_at=record.created_at, + ) + for record in records + ] + + +@router.post("/price-history/fetch", response_model=PriceHistoryResponse) +async def fetch_price_now( + db: AsyncSession = Depends(get_db), + _current_user: User = Depends(require_permission(Permission.VIEW_AUDIT)), +) -> PriceHistoryResponse: + """Manually trigger a price fetch from Bitfinex.""" + price, timestamp = await fetch_btc_eur_price() + + record = PriceHistory( + source="bitfinex", + pair="BTC/EUR", + price=price, + timestamp=timestamp, + ) + db.add(record) + await db.commit() + await db.refresh(record) + + return PriceHistoryResponse( + id=record.id, + source=record.source, + pair=record.pair, + price=record.price, + timestamp=record.timestamp, + created_at=record.created_at, + )