mirror of
https://github.com/jcreek/CosmicClash.git
synced 2026-09-12 00:13:42 +00:00
feat(multiplayer): expose ranked season countdown
This commit is contained in:
+13
-8
@@ -931,13 +931,14 @@ func assignmentChangedEvent(view AssignmentView, now time.Time) ControlPlaneEven
|
||||
}
|
||||
|
||||
type rankedProfileResponse struct {
|
||||
Rating float64 `json:"rating"`
|
||||
RD float64 `json:"rd"`
|
||||
Volatility float64 `json:"volatility"`
|
||||
RankedGames int `json:"ranked_games"`
|
||||
Tier string `json:"tier"`
|
||||
Provisional bool `json:"provisional"`
|
||||
SeasonID string `json:"season_id,omitempty"`
|
||||
Rating float64 `json:"rating"`
|
||||
RD float64 `json:"rd"`
|
||||
Volatility float64 `json:"volatility"`
|
||||
RankedGames int `json:"ranked_games"`
|
||||
Tier string `json:"tier"`
|
||||
Provisional bool `json:"provisional"`
|
||||
SeasonID string `json:"season_id,omitempty"`
|
||||
SeasonEndsAt string `json:"season_ends_at,omitempty"`
|
||||
}
|
||||
|
||||
func (s *Service) profile(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -1000,7 +1001,11 @@ func (s *Service) rankedProfile(w http.ResponseWriter, r *http.Request) {
|
||||
if seasonID == "" {
|
||||
seasonID = profile.LastSeasonID
|
||||
}
|
||||
writeJSON(w, http.StatusOK, rankedProfileResponse{Rating: profile.Value, RD: profile.RD, Volatility: profile.Volatility, RankedGames: profile.RankedGames, Tier: string(tier), Provisional: domain.RankedIsProvisional(profile), SeasonID: seasonID})
|
||||
seasonEndsAt := ""
|
||||
if profile.CurrentSeasonID != "" && !profile.CurrentSeasonEndsAt.IsZero() {
|
||||
seasonEndsAt = profile.CurrentSeasonEndsAt.UTC().Format(time.RFC3339)
|
||||
}
|
||||
writeJSON(w, http.StatusOK, rankedProfileResponse{Rating: profile.Value, RD: profile.RD, Volatility: profile.Volatility, RankedGames: profile.RankedGames, Tier: string(tier), Provisional: domain.RankedIsProvisional(profile), SeasonID: seasonID, SeasonEndsAt: seasonEndsAt})
|
||||
}
|
||||
|
||||
type probeRequest struct {
|
||||
|
||||
@@ -1079,7 +1079,7 @@ func TestRankedProfileAPIReturnsBackendTierAndHidesCasualData(t *testing.T) {
|
||||
}
|
||||
service := &Service{
|
||||
Sessions: sessions,
|
||||
RankedProfiles: map[string]domain.RankedProfile{"player-a": {Rating: domain.Rating{Value: 1600, RD: 200, Volatility: 0.06}, RankedGames: 10, CurrentSeasonID: "season-current", LastSeasonID: "season-1"}},
|
||||
RankedProfiles: map[string]domain.RankedProfile{"player-a": {Rating: domain.Rating{Value: 1600, RD: 200, Volatility: 0.06}, RankedGames: 10, CurrentSeasonID: "season-current", CurrentSeasonEndsAt: now.Add(48 * time.Hour), LastSeasonID: "season-1"}},
|
||||
TierPolicy: policy,
|
||||
Now: func() time.Time { return now },
|
||||
}
|
||||
@@ -1099,7 +1099,7 @@ func TestRankedProfileAPIReturnsBackendTierAndHidesCasualData(t *testing.T) {
|
||||
if err := json.NewDecoder(response.Body).Decode(&body); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if body.Tier != string(domain.RankTierGold) || body.Provisional || body.RankedGames != 10 || body.SeasonID != "season-current" {
|
||||
if body.Tier != string(domain.RankTierGold) || body.Provisional || body.RankedGames != 10 || body.SeasonID != "season-current" || body.SeasonEndsAt != "1970-01-03T00:16:40Z" {
|
||||
t.Fatalf("ranked profile response = %+v", body)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,10 +60,11 @@ func ScoreForPlayer(outcome MatchOutcome, playerID string, team int) (float64, e
|
||||
|
||||
type RankedProfile struct {
|
||||
Rating
|
||||
RankedGames int
|
||||
CurrentSeasonID string
|
||||
LastSeasonID string
|
||||
SeasonHistory []string
|
||||
RankedGames int
|
||||
CurrentSeasonID string
|
||||
CurrentSeasonEndsAt time.Time
|
||||
LastSeasonID string
|
||||
SeasonHistory []string
|
||||
}
|
||||
|
||||
type RankTier string
|
||||
|
||||
@@ -1290,7 +1290,7 @@ func TestPostgreSQLRankedProfileProjectsActiveSeason(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
profile, found, err := (PostgresRankedProfiles{DB: db}).Get(ctx, "profile-season-player")
|
||||
if err != nil || !found || profile.CurrentSeasonID != "profile-season-current" {
|
||||
if err != nil || !found || profile.CurrentSeasonID != "profile-season-current" || !profile.CurrentSeasonEndsAt.Equal(now.Add(time.Hour)) {
|
||||
t.Fatalf("profile=%+v found=%t err=%v", profile, found, err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,10 @@ import (
|
||||
const RankedProfileSelectSQL = `SELECT rating, deviation, volatility, ranked_games, updated_at,
|
||||
COALESCE((SELECT season_id FROM seasons
|
||||
WHERE playlist = 'ranked' AND starts_at <= CURRENT_TIMESTAMP AND ends_at > CURRENT_TIMESTAMP
|
||||
ORDER BY starts_at DESC, season_id DESC LIMIT 1), '')
|
||||
ORDER BY starts_at DESC, season_id DESC LIMIT 1), ''),
|
||||
COALESCE((SELECT ends_at FROM seasons
|
||||
WHERE playlist = 'ranked' AND starts_at <= CURRENT_TIMESTAMP AND ends_at > CURRENT_TIMESTAMP
|
||||
ORDER BY starts_at DESC, season_id DESC LIMIT 1), TIMESTAMP 'epoch')
|
||||
FROM ratings
|
||||
WHERE player_id = $1`
|
||||
|
||||
@@ -34,7 +37,7 @@ func (p PostgresRankedProfiles) Get(ctx context.Context, playerID string) (domai
|
||||
}
|
||||
var profile domain.RankedProfile
|
||||
err := p.DB.QueryRowContext(ctx, RankedProfileSelectSQL, playerID).
|
||||
Scan(&profile.Value, &profile.RD, &profile.Volatility, &profile.RankedGames, &profile.LastRatedAt, &profile.CurrentSeasonID)
|
||||
Scan(&profile.Value, &profile.RD, &profile.Volatility, &profile.RankedGames, &profile.LastRatedAt, &profile.CurrentSeasonID, &profile.CurrentSeasonEndsAt)
|
||||
if err == sql.ErrNoRows {
|
||||
return domain.RankedProfile{}, false, nil
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ package store
|
||||
import "testing"
|
||||
|
||||
func TestRankedProfileQueryProjectsOnlyTheActiveRankedSeason(t *testing.T) {
|
||||
for _, fragment := range []string{"playlist = 'ranked'", "starts_at <= CURRENT_TIMESTAMP", "ends_at > CURRENT_TIMESTAMP", "ORDER BY starts_at DESC", "LIMIT 1"} {
|
||||
for _, fragment := range []string{"playlist = 'ranked'", "starts_at <= CURRENT_TIMESTAMP", "ends_at > CURRENT_TIMESTAMP", "ORDER BY starts_at DESC", "LIMIT 1", "TIMESTAMP 'epoch'"} {
|
||||
if !contains(RankedProfileSelectSQL, fragment) {
|
||||
t.Fatalf("ranked profile query missing %q", fragment)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user