arbret/backend/routes/audit.py
counterweight 5bad1e7e17
Phase 0.1: Remove backend deprecated code
- Delete routes: counter.py, sum.py
- Delete jobs.py and worker.py
- Delete tests: test_counter.py, test_jobs.py
- Update audit.py: keep only price-history endpoints
- Update models.py: remove VIEW_COUNTER, INCREMENT_COUNTER, USE_SUM permissions
- Update models.py: remove Counter, SumRecord, CounterRecord, RandomNumberOutcome models
- Update schemas.py: remove sum/counter related schemas
- Update main.py: remove deleted router imports
- Update test_permissions.py: remove tests for deprecated features
- Update test_price_history.py: remove worker-related tests
- Update conftest.py: remove mock_enqueue_job fixture
- Update auth.py: fix example in docstring
2025-12-22 18:07:14 +01:00

82 lines
2.6 KiB
Python

"""Audit routes for price history."""
from fastapi import APIRouter, Depends
from sqlalchemy import desc, select
from sqlalchemy.exc import IntegrityError
from sqlalchemy.ext.asyncio import AsyncSession
from auth import require_permission
from database import get_db
from models import Permission, PriceHistory, User
from price_fetcher import PAIR_BTC_EUR, SOURCE_BITFINEX, fetch_btc_eur_price
from schemas import PriceHistoryResponse
router = APIRouter(prefix="/api/audit", tags=["audit"])
def _to_price_history_response(record: PriceHistory) -> PriceHistoryResponse:
return PriceHistoryResponse(
id=record.id,
source=record.source,
pair=record.pair,
price=record.price,
timestamp=record.timestamp,
created_at=record.created_at,
)
# =============================================================================
# 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 [_to_price_history_response(record) 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.FETCH_PRICE)),
) -> PriceHistoryResponse:
"""Manually trigger a price fetch from Bitfinex."""
price, timestamp = await fetch_btc_eur_price()
record = PriceHistory(
source=SOURCE_BITFINEX,
pair=PAIR_BTC_EUR,
price=price,
timestamp=timestamp,
)
db.add(record)
try:
await db.commit()
await db.refresh(record)
except IntegrityError:
# Duplicate timestamp - return the existing record
await db.rollback()
query = select(PriceHistory).where(
PriceHistory.source == SOURCE_BITFINEX,
PriceHistory.pair == PAIR_BTC_EUR,
PriceHistory.timestamp == timestamp,
)
result = await db.execute(query)
record = result.scalar_one()
return _to_price_history_response(record)