paper-dynasty-database/app/main.py
Cal Corum 507037f5b9 feat: add GET /api/v2/cards/featured/card-of-the-week endpoint
Exposes the highest-rated card from the past 7 days (configurable via
?days=) as a Discord-embed-ready payload.  AI teams are excluded by
default (?include_ai=true lifts the filter).  Deterministic tiebreak:
rating desc, pack open_time desc, card id desc.

Roadmap: Phase 2.6c — lowest-friction entry into the automated content
pipeline.  Single-call response includes player name, team, rarity,
rating, card image URL, and cardset name.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 10:31:48 -05:00

137 lines
3.7 KiB
Python

import logging
import os
from contextlib import asynccontextmanager
from datetime import datetime
from fastapi import FastAPI, Request
from fastapi.openapi.docs import get_swagger_ui_html
from fastapi.openapi.utils import get_openapi
_log_date = f"{datetime.now().year}-{datetime.now().month}-{datetime.now().day}"
logging.basicConfig(
filename=f"logs/database/{_log_date}.log",
format="%(asctime)s - database - %(levelname)s - %(message)s",
level=logging.INFO if os.environ.get("LOG_LEVEL") == "INFO" else logging.WARNING,
)
# from fastapi.staticfiles import StaticFiles
# from fastapi.templating import Jinja2Templates
from .db_engine import db # noqa: E402
from .routers_v2.players import get_browser, shutdown_browser # noqa: E402
from .routers_v2 import ( # noqa: E402
current,
awards,
teams,
rarity,
cardsets,
players,
packtypes,
packs,
cards,
events,
results,
rewards,
decisions,
batstats,
pitstats,
notifications,
paperdex,
gamerewards,
gauntletrewards,
gauntletruns,
battingcards,
battingcardratings,
pitchingcards,
pitchingcardratings,
cardpositions,
scouting,
mlbplayers,
stratgame,
stratplays,
scout_opportunities,
scout_claims,
refractor,
season_stats,
featured,
)
@asynccontextmanager
async def lifespan(app):
# Startup: warm up the persistent Chromium browser
await get_browser()
yield
# Shutdown: clean up browser and playwright
await shutdown_browser()
app = FastAPI(
# root_path='/api',
lifespan=lifespan,
responses={404: {"description": "Not found"}},
docs_url="/api/docs",
redoc_url="/api/redoc",
)
# app.mount("/static", StaticFiles(directory="storage/static"), name="static")
# templates = Jinja2Templates(directory=os.path.dirname(os.path.abspath(__file__)))
app.include_router(current.router)
app.include_router(awards.router)
app.include_router(teams.router)
app.include_router(rarity.router)
app.include_router(cardsets.router)
app.include_router(players.router)
app.include_router(packtypes.router)
app.include_router(packs.router)
app.include_router(cards.router)
app.include_router(events.router)
app.include_router(results.router)
app.include_router(rewards.router)
app.include_router(batstats.router)
app.include_router(pitstats.router)
app.include_router(notifications.router)
app.include_router(paperdex.router)
app.include_router(gamerewards.router)
app.include_router(gauntletrewards.router)
app.include_router(gauntletruns.router)
app.include_router(battingcards.router)
app.include_router(battingcardratings.router)
app.include_router(pitchingcards.router)
app.include_router(pitchingcardratings.router)
app.include_router(cardpositions.router)
app.include_router(scouting.router)
app.include_router(mlbplayers.router)
app.include_router(stratgame.router)
app.include_router(stratplays.router)
app.include_router(decisions.router)
app.include_router(scout_opportunities.router)
app.include_router(scout_claims.router)
app.include_router(refractor.router)
app.include_router(season_stats.router)
app.include_router(featured.router)
@app.middleware("http")
async def db_session_middleware(request: Request, call_next):
try:
db.connect(reuse_if_open=True)
response = await call_next(request)
return response
finally:
if not db.is_closed():
db.close()
@app.get("/api/docs", include_in_schema=False)
async def get_docs(req: Request):
return get_swagger_ui_html(
openapi_url=req.scope.get("root_path") + "/openapi.json", title="Swagger"
)
@app.get("/api/openapi.json", include_in_schema=False)
async def openapi():
return get_openapi(title="Paper Dynasty API", version="0.1.1", routes=app.routes)