Skip to content

Commit f663284

Browse files
Merge pull request #87 from spiceoogway/fix/quickfixes-57-62-70
fix: dead code removal, health check DB ping, UUID validation (#57, #62, #70)
2 parents 4541dc4 + bdd2fc9 commit f663284

2 files changed

Lines changed: 48 additions & 133 deletions

File tree

api.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,17 @@ def raise_rate_limited(detail: str, info: dict) -> None:
109109
STARTING_BALANCE = 1000.0 # New agent starting balance
110110

111111

112+
def _validate_uuid(value: str, param_name: str = "id") -> None:
113+
"""Validate that a string is a valid UUID. Raises 400 if not."""
114+
try:
115+
uuid.UUID(value)
116+
except (ValueError, AttributeError):
117+
raise HTTPException(
118+
status_code=400,
119+
detail=f"Invalid {param_name}: '{value}' is not a valid UUID",
120+
)
121+
122+
112123
def generate_verification_code() -> str:
113124
"""Generate a cryptographically secure verification code like 'crab-reef-A1B2C3D4'.
114125
@@ -1766,6 +1777,7 @@ async def list_markets(status: Optional[str] = None):
17661777
@app.get("/markets/{market_id}", response_model=MarketDetail)
17671778
async def get_market(market_id: str):
17681779
"""Get market details including current probability."""
1780+
_validate_uuid(market_id, "market_id")
17691781
market = db.get_market(market_id)
17701782
if not market:
17711783
raise HTTPException(status_code=404, detail="Market not found")
@@ -1897,6 +1909,7 @@ async def create_market(req: MarketCreate, user: dict = Depends(require_auth)):
18971909
@app.post("/markets/{market_id}/resolve", response_model=MarketDetail)
18981910
async def resolve_market(market_id: str, req: MarketResolve, user: dict = Depends(require_auth)):
18991911
"""Resolve a market. Only creator can resolve."""
1912+
_validate_uuid(market_id, "market_id")
19001913
market = db.get_market(market_id)
19011914
if not market:
19021915
raise HTTPException(status_code=404, detail="Market not found")
@@ -1957,6 +1970,7 @@ async def place_bet(market_id: str, req: BetRequest, response: Response, user: d
19571970
- `X-RateLimit-Reset`: Unix timestamp when window resets
19581971
- `Retry-After` (on 429 only): Seconds to wait
19591972
"""
1973+
_validate_uuid(market_id, "market_id")
19601974
# Require twitter verification before trading
19611975
if user.get("status") != "claimed":
19621976
raise HTTPException(
@@ -2085,6 +2099,7 @@ async def place_bet_plural_alias(market_id: str, req: BetRequest, user: dict = D
20852099
@app.post("/markets/{market_id}/sell", response_model=SellResponse)
20862100
async def sell_shares(market_id: str, req: SellRequest, user: dict = Depends(require_auth)):
20872101
"""Sell shares back to the market."""
2102+
_validate_uuid(market_id, "market_id")
20882103
# Require twitter verification before trading
20892104
if user.get("status") != "claimed":
20902105
raise HTTPException(
@@ -2172,6 +2187,7 @@ async def sell_shares(market_id: str, req: SellRequest, user: dict = Depends(req
21722187
@app.get("/markets/{market_id}/positions", response_model=MarketPositions)
21732188
async def get_positions(market_id: str):
21742189
"""Get all positions for a market."""
2190+
_validate_uuid(market_id, "market_id")
21752191
market = db.get_market(market_id)
21762192
if not market:
21772193
raise HTTPException(status_code=404, detail="Market not found")
@@ -2200,6 +2216,7 @@ async def get_positions(market_id: str):
22002216
@app.get("/markets/{market_id}/history", response_model=MarketHistory)
22012217
async def get_market_history(market_id: str):
22022218
"""Get probability history for charts."""
2219+
_validate_uuid(market_id, "market_id")
22032220
market = db.get_market(market_id)
22042221
if not market:
22052222
raise HTTPException(status_code=404, detail="Market not found")
@@ -2235,6 +2252,7 @@ async def get_market_history(market_id: str):
22352252
@app.get("/markets/{market_id}/bets", response_model=List[BetHistoryItem])
22362253
async def get_market_bets(market_id: str):
22372254
"""Get all bets for a market."""
2255+
_validate_uuid(market_id, "market_id")
22382256
market = db.get_market(market_id)
22392257
if not market:
22402258
raise HTTPException(status_code=404, detail="Market not found")
@@ -2269,6 +2287,7 @@ async def get_market_bets(market_id: str):
22692287
@app.get("/markets/{market_id}/comments", response_model=MarketComments)
22702288
async def get_comments(market_id: str):
22712289
"""Get all comments for a market."""
2290+
_validate_uuid(market_id, "market_id")
22722291
market = db.get_market(market_id)
22732292
if not market:
22742293
raise HTTPException(status_code=404, detail="Market not found")
@@ -2311,6 +2330,7 @@ async def get_comments(market_id: str):
23112330
@app.post("/markets/{market_id}/comments", response_model=Comment)
23122331
async def create_comment(market_id: str, req: CommentCreate, user: dict = Depends(require_auth)):
23132332
"""Create a comment on a market."""
2333+
_validate_uuid(market_id, "market_id")
23142334
market = db.get_market(market_id)
23152335
if not market:
23162336
raise HTTPException(status_code=404, detail="Market not found")
@@ -2354,6 +2374,7 @@ async def request_resolution(market_id: str, user: dict = Depends(require_auth))
23542374
Only the market creator can request resolution.
23552375
The committee will research and vote, with majority (5+) deciding the outcome.
23562376
"""
2377+
_validate_uuid(market_id, "market_id")
23572378
market = db.get_market(market_id)
23582379
if not market:
23592380
raise HTTPException(status_code=404, detail="Market not found")
@@ -2435,6 +2456,7 @@ async def request_resolution(market_id: str, user: dict = Depends(require_auth))
24352456
@app.get("/markets/{market_id}/resolution-votes", response_model=ResolutionResult)
24362457
async def get_resolution_votes(market_id: str):
24372458
"""Get the resolution committee votes for a market."""
2459+
_validate_uuid(market_id, "market_id")
24382460
market = db.get_market(market_id)
24392461
if not market:
24402462
raise HTTPException(status_code=404, detail="Market not found")
@@ -2603,6 +2625,7 @@ async def get_my_bets(
26032625
@app.get("/users/{user_id}", response_model=UserProfile)
26042626
async def get_user(user_id: str):
26052627
"""Get public user profile."""
2628+
_validate_uuid(user_id, "user_id")
26062629
user = db.get_user(user_id)
26072630
if not user:
26082631
raise HTTPException(status_code=404, detail="User not found")
@@ -2876,6 +2899,7 @@ async def get_claim_info(user_id: str):
28762899
28772900
Returns the verification code and instructions for claiming.
28782901
"""
2902+
_validate_uuid(user_id, "user_id")
28792903
user = db.get_user(user_id)
28802904
if not user:
28812905
raise HTTPException(status_code=404, detail="Agent not found")
@@ -3160,10 +3184,34 @@ async def get_chat_messages(limit: int = 50, since: Optional[str] = None, channe
31603184

31613185
@app.get("/health")
31623186
async def health():
3187+
from fastapi.responses import JSONResponse
3188+
3189+
# Verify database is reachable
3190+
db_status = "ok"
3191+
try:
3192+
conn = db._get_conn()
3193+
try:
3194+
with conn.cursor() as cur:
3195+
cur.execute("SELECT 1")
3196+
finally:
3197+
db._put_conn(conn)
3198+
except Exception:
3199+
db_status = "unreachable"
3200+
3201+
if db_status != "ok":
3202+
return JSONResponse(
3203+
status_code=503,
3204+
content={
3205+
"status": "degraded",
3206+
"db": db_status,
3207+
},
3208+
)
3209+
31633210
market_count = len(db.list_markets())
31643211
user_count = len(db.users)
31653212
return {
31663213
"status": "ok",
3214+
"db": "ok",
31673215
"markets": market_count,
31683216
"users": user_count,
31693217
"currency": {

database.py

Lines changed: 0 additions & 133 deletions
This file was deleted.

0 commit comments

Comments
 (0)