Add monthly MVP snapshots and API
This commit is contained in:
69
ai/tasks/done/TASK-068-monthly-mvp-snapshots-and-api.md
Normal file
69
ai/tasks/done/TASK-068-monthly-mvp-snapshots-and-api.md
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
# TASK-068-monthly-mvp-snapshots-and-api
|
||||||
|
|
||||||
|
## Goal
|
||||||
|
Exponer el ranking mensual MVP V1 mediante snapshots JSON y API propia del backend, siguiendo la misma filosofía rápida y estable ya usada por la capa histórica.
|
||||||
|
|
||||||
|
## Context
|
||||||
|
Una vez implementado el cálculo backend del monthly MVP, hace falta integrarlo en la capa de snapshots del proyecto para que:
|
||||||
|
- no dependa de cálculos pesados on-demand
|
||||||
|
- pueda servirse rápido a la UI
|
||||||
|
- sea consistente con el resto de la arquitectura histórica
|
||||||
|
|
||||||
|
## Steps
|
||||||
|
1. Revisar la implementación del cálculo mensual MVP y la arquitectura actual de snapshots JSON.
|
||||||
|
2. Diseñar la forma de snapshot para el ranking mensual MVP, tanto por servidor como para all-servers.
|
||||||
|
3. Generar snapshots JSON apropiados, por ejemplo:
|
||||||
|
- server monthly mvp
|
||||||
|
- all-servers monthly mvp
|
||||||
|
4. Incluir metadatos claros, como mínimo:
|
||||||
|
- generated_at
|
||||||
|
- source_range_start
|
||||||
|
- source_range_end
|
||||||
|
- freshness / is_stale si aplica
|
||||||
|
- month_key o periodo real usado
|
||||||
|
5. Exponer endpoints claros y consistentes para leer esos snapshots.
|
||||||
|
6. Mantener compatibilidad y coherencia con la API histórica existente.
|
||||||
|
7. Integrar el monthly MVP en el runner/generación periódica de snapshots si corresponde.
|
||||||
|
8. No crear todavía la UI final en esta task.
|
||||||
|
9. Al completar la implementación:
|
||||||
|
- dejar el repositorio consistente
|
||||||
|
- hacer commit
|
||||||
|
- hacer push al remoto si el entorno lo permite
|
||||||
|
|
||||||
|
## Files to Read First
|
||||||
|
- AGENTS.md
|
||||||
|
- backend/README.md
|
||||||
|
- backend/app/routes.py
|
||||||
|
- backend/app/payloads.py
|
||||||
|
- backend/app/historical_snapshots.py
|
||||||
|
- backend/app/historical_snapshot_storage.py
|
||||||
|
- backend/app/historical_runner.py
|
||||||
|
- backend/app/config.py
|
||||||
|
- docs/monthly-mvp-ranking-scoring-design.md
|
||||||
|
|
||||||
|
## Expected Files to Modify
|
||||||
|
- backend/app/routes.py
|
||||||
|
- backend/app/payloads.py
|
||||||
|
- backend/app/historical_snapshots.py
|
||||||
|
- backend/app/historical_snapshot_storage.py
|
||||||
|
- backend/app/historical_runner.py
|
||||||
|
- backend/README.md
|
||||||
|
- opcionalmente nuevos módulos auxiliares si mejoran claridad
|
||||||
|
|
||||||
|
## Constraints
|
||||||
|
- No recalcular el ranking pesado en cada request de usuario.
|
||||||
|
- No romper snapshots históricos existentes.
|
||||||
|
- No crear todavía UI nueva en esta task.
|
||||||
|
- No hacer cambios destructivos.
|
||||||
|
- Mantener el trabajo centrado en snapshots y API del monthly MVP.
|
||||||
|
|
||||||
|
## Validation
|
||||||
|
- Existen snapshots JSON del monthly MVP para servidor y/o all-servers según diseño.
|
||||||
|
- Existen endpoints para leer esos snapshots.
|
||||||
|
- El monthly MVP se integra con la operativa de snapshots del proyecto.
|
||||||
|
- La respuesta es rápida y coherente con el resto de la API histórica.
|
||||||
|
- Los cambios quedan committeados y se hace push si el entorno lo permite.
|
||||||
|
|
||||||
|
## Change Budget
|
||||||
|
- Preferir menos de 6 archivos modificados o creados.
|
||||||
|
- Preferir menos de 240 líneas cambiadas.
|
||||||
@@ -182,11 +182,13 @@ normaliza espacios y barras finales para mantener la comparacion con el header
|
|||||||
- `GET /api/historical/weekly-top-kills?limit=10&server=comunidad-hispana-01`
|
- `GET /api/historical/weekly-top-kills?limit=10&server=comunidad-hispana-01`
|
||||||
- `GET /api/historical/weekly-leaderboard?metric=kills&limit=10&server=comunidad-hispana-01`
|
- `GET /api/historical/weekly-leaderboard?metric=kills&limit=10&server=comunidad-hispana-01`
|
||||||
- `GET /api/historical/leaderboard?timeframe=monthly&metric=kills&limit=10&server=comunidad-hispana-01`
|
- `GET /api/historical/leaderboard?timeframe=monthly&metric=kills&limit=10&server=comunidad-hispana-01`
|
||||||
|
- `GET /api/historical/monthly-mvp?limit=10&server=comunidad-hispana-01`
|
||||||
- `GET /api/historical/recent-matches?limit=20&server=comunidad-hispana-01`
|
- `GET /api/historical/recent-matches?limit=20&server=comunidad-hispana-01`
|
||||||
- `GET /api/historical/server-summary?server=comunidad-hispana-01`
|
- `GET /api/historical/server-summary?server=comunidad-hispana-01`
|
||||||
- `GET /api/historical/snapshots/server-summary?server=comunidad-hispana-01`
|
- `GET /api/historical/snapshots/server-summary?server=comunidad-hispana-01`
|
||||||
- `GET /api/historical/snapshots/weekly-leaderboard?metric=kills&limit=10&server=comunidad-hispana-01`
|
- `GET /api/historical/snapshots/weekly-leaderboard?metric=kills&limit=10&server=comunidad-hispana-01`
|
||||||
- `GET /api/historical/snapshots/leaderboard?timeframe=monthly&metric=kills&limit=10&server=comunidad-hispana-01`
|
- `GET /api/historical/snapshots/leaderboard?timeframe=monthly&metric=kills&limit=10&server=comunidad-hispana-01`
|
||||||
|
- `GET /api/historical/snapshots/monthly-mvp?limit=10&server=comunidad-hispana-01`
|
||||||
- `GET /api/historical/snapshots/recent-matches?limit=6&server=comunidad-hispana-01`
|
- `GET /api/historical/snapshots/recent-matches?limit=6&server=comunidad-hispana-01`
|
||||||
- `GET /api/historical/player-profile?player=steam%3A76561198000000000`
|
- `GET /api/historical/player-profile?player=steam%3A76561198000000000`
|
||||||
|
|
||||||
@@ -289,6 +291,7 @@ bruto. Esta capa esta preparada para guardar:
|
|||||||
- `server-summary`
|
- `server-summary`
|
||||||
- `weekly-leaderboard` con metricas `kills`, `deaths`, `support` y `matches_over_100_kills`
|
- `weekly-leaderboard` con metricas `kills`, `deaths`, `support` y `matches_over_100_kills`
|
||||||
- `monthly-leaderboard` con las mismas metricas semanticas
|
- `monthly-leaderboard` con las mismas metricas semanticas
|
||||||
|
- `monthly-mvp`
|
||||||
- `recent-matches`
|
- `recent-matches`
|
||||||
|
|
||||||
Por defecto se escriben bajo:
|
Por defecto se escriben bajo:
|
||||||
@@ -309,6 +312,7 @@ Ejemplos:
|
|||||||
- `backend/data/snapshots/comunidad-hispana-01/weekly-kills.json`
|
- `backend/data/snapshots/comunidad-hispana-01/weekly-kills.json`
|
||||||
- `backend/data/snapshots/comunidad-hispana-03/recent-matches.json`
|
- `backend/data/snapshots/comunidad-hispana-03/recent-matches.json`
|
||||||
- `backend/data/snapshots/all-servers/weekly-support.json`
|
- `backend/data/snapshots/all-servers/weekly-support.json`
|
||||||
|
- `backend/data/snapshots/all-servers/monthly-mvp.json`
|
||||||
|
|
||||||
Cada archivo conserva metadatos operativos minimos:
|
Cada archivo conserva metadatos operativos minimos:
|
||||||
|
|
||||||
@@ -650,6 +654,10 @@ La misma capa de snapshots guarda tambien `monthly-leaderboard` por servidor y
|
|||||||
por agregado `all-servers`, con archivos como `monthly-kills.json` y
|
por agregado `all-servers`, con archivos como `monthly-kills.json` y
|
||||||
`monthly-support.json`.
|
`monthly-support.json`.
|
||||||
|
|
||||||
|
Tambien persiste `monthly-mvp.json` por servidor y para `all-servers`, listo
|
||||||
|
para lectura rapida desde `/api/historical/monthly-mvp` y
|
||||||
|
`/api/historical/snapshots/monthly-mvp` sin recalculo pesado en request.
|
||||||
|
|
||||||
El backend incluye ademas el calculo interno de `monthly MVP V1` en
|
El backend incluye ademas el calculo interno de `monthly MVP V1` en
|
||||||
`app/monthly_mvp.py`, separado de los leaderboards mensuales simples por
|
`app/monthly_mvp.py`, separado de los leaderboards mensuales simples por
|
||||||
metrica. Ese calculo:
|
metrica. Ese calculo:
|
||||||
|
|||||||
@@ -249,7 +249,7 @@ def _is_effectively_empty_snapshot_payload(
|
|||||||
items = payload.get("items")
|
items = payload.get("items")
|
||||||
return not isinstance(items, list) or len(items) == 0
|
return not isinstance(items, list) or len(items) == 0
|
||||||
|
|
||||||
if snapshot_type in {"weekly-leaderboard", "monthly-leaderboard"}:
|
if snapshot_type in {"weekly-leaderboard", "monthly-leaderboard", "monthly-mvp"}:
|
||||||
items = payload.get("items")
|
items = payload.get("items")
|
||||||
return not isinstance(items, list) or len(items) == 0
|
return not isinstance(items, list) or len(items) == 0
|
||||||
|
|
||||||
@@ -287,6 +287,8 @@ def _build_snapshot_filename(*, snapshot_type: str, metric: str | None) -> str:
|
|||||||
if snapshot_type == "monthly-leaderboard":
|
if snapshot_type == "monthly-leaderboard":
|
||||||
metric_suffix = "matches-over-100-kills" if metric == "matches_over_100_kills" else _slugify(metric or "unknown")
|
metric_suffix = "matches-over-100-kills" if metric == "matches_over_100_kills" else _slugify(metric or "unknown")
|
||||||
return f"monthly-{metric_suffix}.json"
|
return f"monthly-{metric_suffix}.json"
|
||||||
|
if snapshot_type == "monthly-mvp":
|
||||||
|
return "monthly-mvp.json"
|
||||||
metric_suffix = _slugify(metric or "")
|
metric_suffix = _slugify(metric or "")
|
||||||
base_name = _slugify(snapshot_type)
|
base_name = _slugify(snapshot_type)
|
||||||
return f"{base_name}-{metric_suffix}.json" if metric_suffix else f"{base_name}.json"
|
return f"{base_name}-{metric_suffix}.json" if metric_suffix else f"{base_name}.json"
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ from .historical_storage import (
|
|||||||
list_historical_server_summaries,
|
list_historical_server_summaries,
|
||||||
list_historical_servers,
|
list_historical_servers,
|
||||||
list_monthly_leaderboard,
|
list_monthly_leaderboard,
|
||||||
|
list_monthly_mvp_ranking,
|
||||||
list_recent_historical_matches,
|
list_recent_historical_matches,
|
||||||
list_weekly_leaderboard,
|
list_weekly_leaderboard,
|
||||||
)
|
)
|
||||||
@@ -17,6 +18,7 @@ from .historical_storage import (
|
|||||||
SNAPSHOT_TYPE_SERVER_SUMMARY = "server-summary"
|
SNAPSHOT_TYPE_SERVER_SUMMARY = "server-summary"
|
||||||
SNAPSHOT_TYPE_WEEKLY_LEADERBOARD = "weekly-leaderboard"
|
SNAPSHOT_TYPE_WEEKLY_LEADERBOARD = "weekly-leaderboard"
|
||||||
SNAPSHOT_TYPE_MONTHLY_LEADERBOARD = "monthly-leaderboard"
|
SNAPSHOT_TYPE_MONTHLY_LEADERBOARD = "monthly-leaderboard"
|
||||||
|
SNAPSHOT_TYPE_MONTHLY_MVP = "monthly-mvp"
|
||||||
SNAPSHOT_TYPE_RECENT_MATCHES = "recent-matches"
|
SNAPSHOT_TYPE_RECENT_MATCHES = "recent-matches"
|
||||||
|
|
||||||
SUPPORTED_SNAPSHOT_TYPES = frozenset(
|
SUPPORTED_SNAPSHOT_TYPES = frozenset(
|
||||||
@@ -24,6 +26,7 @@ SUPPORTED_SNAPSHOT_TYPES = frozenset(
|
|||||||
SNAPSHOT_TYPE_SERVER_SUMMARY,
|
SNAPSHOT_TYPE_SERVER_SUMMARY,
|
||||||
SNAPSHOT_TYPE_WEEKLY_LEADERBOARD,
|
SNAPSHOT_TYPE_WEEKLY_LEADERBOARD,
|
||||||
SNAPSHOT_TYPE_MONTHLY_LEADERBOARD,
|
SNAPSHOT_TYPE_MONTHLY_LEADERBOARD,
|
||||||
|
SNAPSHOT_TYPE_MONTHLY_MVP,
|
||||||
SNAPSHOT_TYPE_RECENT_MATCHES,
|
SNAPSHOT_TYPE_RECENT_MATCHES,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -123,6 +126,15 @@ def build_historical_server_snapshots(
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
snapshots.append(
|
||||||
|
_build_monthly_mvp_snapshot(
|
||||||
|
server_key,
|
||||||
|
generated_at_value,
|
||||||
|
limit=leaderboard_limit,
|
||||||
|
db_path=db_path,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
snapshots.append(
|
snapshots.append(
|
||||||
_build_recent_matches_snapshot(
|
_build_recent_matches_snapshot(
|
||||||
server_key,
|
server_key,
|
||||||
@@ -168,6 +180,14 @@ def build_priority_historical_snapshots(
|
|||||||
db_path=db_path,
|
db_path=db_path,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
snapshots.append(
|
||||||
|
_build_monthly_mvp_snapshot(
|
||||||
|
server_key,
|
||||||
|
generated_at_value,
|
||||||
|
limit=leaderboard_limit,
|
||||||
|
db_path=db_path,
|
||||||
|
)
|
||||||
|
)
|
||||||
snapshots.append(
|
snapshots.append(
|
||||||
_build_recent_matches_snapshot(
|
_build_recent_matches_snapshot(
|
||||||
server_key,
|
server_key,
|
||||||
@@ -400,6 +420,38 @@ def _build_recent_matches_snapshot(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def _build_monthly_mvp_snapshot(
|
||||||
|
server_key: str,
|
||||||
|
generated_at: datetime,
|
||||||
|
*,
|
||||||
|
limit: int,
|
||||||
|
db_path: Path | None = None,
|
||||||
|
) -> dict[str, object]:
|
||||||
|
ranking_result = list_monthly_mvp_ranking(
|
||||||
|
limit=limit,
|
||||||
|
server_id=server_key,
|
||||||
|
db_path=db_path,
|
||||||
|
)
|
||||||
|
month_key = str(ranking_result.get("window_start") or "")[:7] or None
|
||||||
|
return {
|
||||||
|
"server_key": server_key,
|
||||||
|
"snapshot_type": SNAPSHOT_TYPE_MONTHLY_MVP,
|
||||||
|
"metric": None,
|
||||||
|
"window": DEFAULT_MONTHLY_SNAPSHOT_WINDOW,
|
||||||
|
"generated_at": generated_at,
|
||||||
|
"source_range_start": _parse_optional_timestamp(ranking_result.get("window_start")),
|
||||||
|
"source_range_end": _parse_optional_timestamp(ranking_result.get("window_end")),
|
||||||
|
"is_stale": False,
|
||||||
|
"payload": {
|
||||||
|
"server_key": server_key,
|
||||||
|
"limit": limit,
|
||||||
|
"month_key": month_key,
|
||||||
|
"generated_at": _to_iso(generated_at),
|
||||||
|
**ranking_result,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def _resolve_snapshot_target_keys(
|
def _resolve_snapshot_target_keys(
|
||||||
*,
|
*,
|
||||||
server_key: str | None,
|
server_key: str | None,
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ from .historical_snapshots import (
|
|||||||
DEFAULT_SNAPSHOT_WINDOW,
|
DEFAULT_SNAPSHOT_WINDOW,
|
||||||
DEFAULT_WEEKLY_SNAPSHOT_WINDOW,
|
DEFAULT_WEEKLY_SNAPSHOT_WINDOW,
|
||||||
SNAPSHOT_TYPE_MONTHLY_LEADERBOARD,
|
SNAPSHOT_TYPE_MONTHLY_LEADERBOARD,
|
||||||
|
SNAPSHOT_TYPE_MONTHLY_MVP,
|
||||||
SNAPSHOT_TYPE_RECENT_MATCHES,
|
SNAPSHOT_TYPE_RECENT_MATCHES,
|
||||||
SNAPSHOT_TYPE_SERVER_SUMMARY,
|
SNAPSHOT_TYPE_SERVER_SUMMARY,
|
||||||
SNAPSHOT_TYPE_WEEKLY_LEADERBOARD,
|
SNAPSHOT_TYPE_WEEKLY_LEADERBOARD,
|
||||||
@@ -326,6 +327,31 @@ def build_recent_historical_matches_payload(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def build_monthly_mvp_payload(
|
||||||
|
*,
|
||||||
|
limit: int = 10,
|
||||||
|
server_id: str | None = None,
|
||||||
|
) -> dict[str, object]:
|
||||||
|
"""Return the precomputed monthly MVP payload through the stable API surface."""
|
||||||
|
snapshot_payload = build_monthly_mvp_snapshot_payload(
|
||||||
|
limit=limit,
|
||||||
|
server_id=server_id,
|
||||||
|
)
|
||||||
|
data = snapshot_payload["data"]
|
||||||
|
return {
|
||||||
|
"status": "ok",
|
||||||
|
"data": {
|
||||||
|
**data,
|
||||||
|
"title": _build_monthly_mvp_title(
|
||||||
|
is_all_servers=server_id == ALL_SERVERS_SLUG,
|
||||||
|
snapshot=False,
|
||||||
|
),
|
||||||
|
"context": "historical-monthly-mvp",
|
||||||
|
"source": "historical-precomputed-snapshots",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def build_historical_server_summary_snapshot_payload(
|
def build_historical_server_summary_snapshot_payload(
|
||||||
*,
|
*,
|
||||||
server_slug: str | None = None,
|
server_slug: str | None = None,
|
||||||
@@ -486,6 +512,62 @@ def build_recent_historical_matches_snapshot_payload(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def build_monthly_mvp_snapshot_payload(
|
||||||
|
*,
|
||||||
|
limit: int = 10,
|
||||||
|
server_id: str | None = None,
|
||||||
|
) -> dict[str, object]:
|
||||||
|
"""Return one precomputed monthly MVP snapshot."""
|
||||||
|
snapshot = _get_historical_snapshot_record(
|
||||||
|
server_key=server_id,
|
||||||
|
snapshot_type=SNAPSHOT_TYPE_MONTHLY_MVP,
|
||||||
|
window=DEFAULT_MONTHLY_SNAPSHOT_WINDOW,
|
||||||
|
)
|
||||||
|
payload = snapshot.get("payload") if snapshot else {}
|
||||||
|
items = payload.get("items") if isinstance(payload, dict) else None
|
||||||
|
sliced_items = list(items[:limit]) if isinstance(items, list) else []
|
||||||
|
return {
|
||||||
|
"status": "ok",
|
||||||
|
"data": {
|
||||||
|
"title": _build_monthly_mvp_title(
|
||||||
|
is_all_servers=server_id == ALL_SERVERS_SLUG,
|
||||||
|
snapshot=True,
|
||||||
|
),
|
||||||
|
"context": "historical-monthly-mvp-snapshot",
|
||||||
|
"source": "historical-precomputed-snapshots",
|
||||||
|
"server_slug": server_id,
|
||||||
|
"timeframe": "monthly",
|
||||||
|
"metric": "mvp",
|
||||||
|
"found": snapshot is not None,
|
||||||
|
**_build_historical_snapshot_metadata(snapshot),
|
||||||
|
"month_key": payload.get("month_key") if isinstance(payload, dict) else None,
|
||||||
|
"window_days": payload.get("window_days") if isinstance(payload, dict) else None,
|
||||||
|
"window_start": payload.get("window_start") if isinstance(payload, dict) else None,
|
||||||
|
"window_end": payload.get("window_end") if isinstance(payload, dict) else None,
|
||||||
|
"window_kind": payload.get("window_kind") if isinstance(payload, dict) else None,
|
||||||
|
"window_label": payload.get("window_label") if isinstance(payload, dict) else None,
|
||||||
|
"uses_fallback": bool(payload.get("uses_fallback")) if isinstance(payload, dict) else False,
|
||||||
|
"selection_reason": payload.get("selection_reason") if isinstance(payload, dict) else None,
|
||||||
|
"current_month_start": payload.get("current_month_start") if isinstance(payload, dict) else None,
|
||||||
|
"current_month_closed_matches": (
|
||||||
|
payload.get("current_month_closed_matches") if isinstance(payload, dict) else None
|
||||||
|
),
|
||||||
|
"previous_month_closed_matches": (
|
||||||
|
payload.get("previous_month_closed_matches") if isinstance(payload, dict) else None
|
||||||
|
),
|
||||||
|
"sufficient_sample": payload.get("sufficient_sample") if isinstance(payload, dict) else None,
|
||||||
|
"eligibility": payload.get("eligibility") if isinstance(payload, dict) else None,
|
||||||
|
"ranking_version": payload.get("ranking_version") if isinstance(payload, dict) else None,
|
||||||
|
"eligible_players_count": (
|
||||||
|
payload.get("eligible_players_count") if isinstance(payload, dict) else 0
|
||||||
|
),
|
||||||
|
"snapshot_limit": payload.get("limit") if isinstance(payload, dict) else None,
|
||||||
|
"limit": limit,
|
||||||
|
"items": sliced_items,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def build_historical_server_summary_payload(
|
def build_historical_server_summary_payload(
|
||||||
*,
|
*,
|
||||||
server_slug: str | None = None,
|
server_slug: str | None = None,
|
||||||
@@ -590,6 +672,12 @@ def _build_leaderboard_title(
|
|||||||
return title_by_metric.get(metric, fallback_label)
|
return title_by_metric.get(metric, fallback_label)
|
||||||
|
|
||||||
|
|
||||||
|
def _build_monthly_mvp_title(*, is_all_servers: bool, snapshot: bool = False) -> str:
|
||||||
|
prefix = "Snapshot " if snapshot else ""
|
||||||
|
scope_label = "global" if is_all_servers else "por servidor"
|
||||||
|
return f"{prefix}Top MVP mensual {scope_label}"
|
||||||
|
|
||||||
|
|
||||||
def _enrich_server_items(items: list[dict[str, object]]) -> list[dict[str, object]]:
|
def _enrich_server_items(items: list[dict[str, object]]) -> list[dict[str, object]]:
|
||||||
target_index = {
|
target_index = {
|
||||||
target.external_server_id: target
|
target.external_server_id: target
|
||||||
|
|||||||
@@ -11,8 +11,10 @@ from .payloads import (
|
|||||||
build_error_payload,
|
build_error_payload,
|
||||||
build_health_payload,
|
build_health_payload,
|
||||||
build_historical_leaderboard_payload,
|
build_historical_leaderboard_payload,
|
||||||
|
build_monthly_mvp_payload,
|
||||||
build_monthly_leaderboard_payload,
|
build_monthly_leaderboard_payload,
|
||||||
build_monthly_leaderboard_snapshot_payload,
|
build_monthly_leaderboard_snapshot_payload,
|
||||||
|
build_monthly_mvp_snapshot_payload,
|
||||||
build_historical_server_summary_snapshot_payload,
|
build_historical_server_summary_snapshot_payload,
|
||||||
build_historical_player_profile_payload,
|
build_historical_player_profile_payload,
|
||||||
build_historical_server_summary_payload,
|
build_historical_server_summary_payload,
|
||||||
@@ -107,6 +109,16 @@ def resolve_get_payload(path: str) -> tuple[HTTPStatus | None, dict[str, object]
|
|||||||
metric=metric,
|
metric=metric,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if parsed.path == "/api/historical/monthly-mvp":
|
||||||
|
limit = _parse_limit(parsed.query)
|
||||||
|
if limit is None:
|
||||||
|
return HTTPStatus.BAD_REQUEST, build_error_payload("Invalid limit parameter")
|
||||||
|
server_id = parse_qs(parsed.query).get("server", [None])[0]
|
||||||
|
return HTTPStatus.OK, build_monthly_mvp_payload(
|
||||||
|
limit=limit,
|
||||||
|
server_id=server_id,
|
||||||
|
)
|
||||||
|
|
||||||
if parsed.path == "/api/historical/snapshots/leaderboard":
|
if parsed.path == "/api/historical/snapshots/leaderboard":
|
||||||
limit = _parse_limit(parsed.query)
|
limit = _parse_limit(parsed.query)
|
||||||
if limit is None:
|
if limit is None:
|
||||||
@@ -141,6 +153,16 @@ def resolve_get_payload(path: str) -> tuple[HTTPStatus | None, dict[str, object]
|
|||||||
metric=metric,
|
metric=metric,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if parsed.path == "/api/historical/snapshots/monthly-mvp":
|
||||||
|
limit = _parse_limit(parsed.query)
|
||||||
|
if limit is None:
|
||||||
|
return HTTPStatus.BAD_REQUEST, build_error_payload("Invalid limit parameter")
|
||||||
|
server_id = parse_qs(parsed.query).get("server", [None])[0]
|
||||||
|
return HTTPStatus.OK, build_monthly_mvp_snapshot_payload(
|
||||||
|
limit=limit,
|
||||||
|
server_id=server_id,
|
||||||
|
)
|
||||||
|
|
||||||
if parsed.path == "/api/historical/snapshots/weekly-leaderboard":
|
if parsed.path == "/api/historical/snapshots/weekly-leaderboard":
|
||||||
limit = _parse_limit(parsed.query)
|
limit = _parse_limit(parsed.query)
|
||||||
if limit is None:
|
if limit is None:
|
||||||
|
|||||||
Reference in New Issue
Block a user