Ship Steam login, D1 player sync, and cached「我」dashboard.
Players get a fast TTL-backed homepage (local profile / Cloudflare D1) with dense UI polish; login unlocks /home without blocking on every OpenDota refresh. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
"""TTL helpers for player homepage cache-first serving."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
import unittest
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from pathlib import Path
|
||||
|
||||
PC = Path(__file__).resolve().parents[1]
|
||||
sys.path.insert(0, str(PC))
|
||||
|
||||
from player_pages import ( # noqa: E402
|
||||
profile_fetched_at,
|
||||
profile_has_payload,
|
||||
profile_is_stale,
|
||||
)
|
||||
|
||||
|
||||
def _iso_ago(seconds: int) -> str:
|
||||
t = datetime.now(timezone.utc) - timedelta(seconds=seconds)
|
||||
return t.strftime("%Y-%m-%dT%H:%M:%SZ")
|
||||
|
||||
|
||||
class PlayerPagesCacheTests(unittest.TestCase):
|
||||
def test_has_payload_career(self):
|
||||
self.assertTrue(profile_has_payload({"career": {"games": 10}}))
|
||||
self.assertFalse(profile_has_payload({"career": {"games": 0}}))
|
||||
|
||||
def test_has_payload_recent(self):
|
||||
self.assertTrue(profile_has_payload({"recent": [{"match_id": 1}]}))
|
||||
self.assertFalse(profile_has_payload({"recent": []}))
|
||||
|
||||
def test_fetched_at_prefers_availability(self):
|
||||
p = {
|
||||
"availability": {"fetched_at": "2026-01-01T00:00:00Z"},
|
||||
"enriched_at": "2026-01-02T00:00:00Z",
|
||||
}
|
||||
self.assertEqual(profile_fetched_at(p), "2026-01-01T00:00:00Z")
|
||||
|
||||
def test_stale_ttl(self):
|
||||
fresh = {"enriched_at": _iso_ago(60)}
|
||||
old = {"enriched_at": _iso_ago(1200)}
|
||||
self.assertFalse(profile_is_stale(fresh, 600))
|
||||
self.assertTrue(profile_is_stale(old, 600))
|
||||
self.assertTrue(profile_is_stale({}, 600))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,95 @@
|
||||
"""Unit tests for player homepage aggregates."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
PC = Path(__file__).resolve().parents[1]
|
||||
sys.path.insert(0, str(PC))
|
||||
|
||||
from player_stats import ( # noqa: E402
|
||||
aggregate_from_rows,
|
||||
career_from_opendota,
|
||||
kda,
|
||||
merge_availability,
|
||||
should_keep_old_career,
|
||||
top_heroes_from_opendota,
|
||||
winrate,
|
||||
)
|
||||
|
||||
|
||||
class PlayerStatsTests(unittest.TestCase):
|
||||
def test_kda_zero_deaths(self):
|
||||
self.assertEqual(kda(5, 0, 5), 10.0)
|
||||
|
||||
def test_winrate_empty(self):
|
||||
self.assertIsNone(winrate(0, 0))
|
||||
self.assertEqual(winrate(1, 1), 50.0)
|
||||
|
||||
def test_aggregate_recent(self):
|
||||
rows = [
|
||||
{"won": True, "kills": 10, "deaths": 2, "assists": 8, "gpm": 500, "hero_id": 1},
|
||||
{"won": False, "kills": 0, "deaths": 10, "assists": 2, "gpm": 300, "hero_id": 2},
|
||||
]
|
||||
out = aggregate_from_rows(rows, limit=20)
|
||||
self.assertEqual(out["sample"], 2)
|
||||
self.assertEqual(out["wins"], 1)
|
||||
self.assertEqual(out["winrate"], 50.0)
|
||||
self.assertEqual(out["avg_gpm"], 400)
|
||||
|
||||
def test_career_empty_private(self):
|
||||
self.assertIsNone(career_from_opendota({"win": 0, "lose": 0}, []))
|
||||
|
||||
def test_career_populated(self):
|
||||
career = career_from_opendota(
|
||||
{"win": 10, "lose": 10},
|
||||
[
|
||||
{"field": "kills", "n": 20, "sum": 100},
|
||||
{"field": "deaths", "n": 20, "sum": 50},
|
||||
{"field": "assists", "n": 20, "sum": 150},
|
||||
{"field": "gold_per_min", "n": 20, "sum": 8000},
|
||||
],
|
||||
)
|
||||
self.assertEqual(career["games"], 20)
|
||||
self.assertEqual(career["kda"], 5.0)
|
||||
self.assertEqual(career["avg_gpm"], 400)
|
||||
|
||||
def test_keep_old_career_on_empty(self):
|
||||
old = {"games": 100, "wins": 50, "losses": 50}
|
||||
self.assertEqual(should_keep_old_career(old, None), old)
|
||||
new = {"games": 101, "wins": 51, "losses": 50}
|
||||
self.assertEqual(should_keep_old_career(old, new), new)
|
||||
|
||||
def test_top_heroes(self):
|
||||
heroes = top_heroes_from_opendota(
|
||||
[
|
||||
{"hero_id": 1, "games": 5, "win": 3, "last_played": 100},
|
||||
{"hero_id": 2, "games": 10, "win": 4, "last_played": 90},
|
||||
],
|
||||
hero_lookup={1: {"key": "antimage", "name_loc": "敌法"}, 2: {"key": "axe", "name_loc": "斧王"}},
|
||||
limit=1,
|
||||
)
|
||||
self.assertEqual(len(heroes), 1)
|
||||
self.assertEqual(heroes[0]["hero_key"], "axe")
|
||||
|
||||
def test_availability_syncing(self):
|
||||
avail = merge_availability(
|
||||
opendota_recent_n=0,
|
||||
career=None,
|
||||
steam_history_status=1,
|
||||
fetched_at="t",
|
||||
)
|
||||
self.assertEqual(avail["status"], "syncing")
|
||||
private = merge_availability(
|
||||
opendota_recent_n=0,
|
||||
career=None,
|
||||
steam_history_status=15,
|
||||
fetched_at="t",
|
||||
)
|
||||
self.assertEqual(private["status"], "private")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user