85 lines
2.2 KiB
Go
85 lines
2.2 KiB
Go
package handlers
|
|
|
|
import (
|
|
"database/sql"
|
|
"net/http"
|
|
|
|
"github.com/google/uuid"
|
|
"github.com/labstack/echo/v4"
|
|
"github.com/tas/horchposten/models"
|
|
)
|
|
|
|
// PlayerStats handles GET /api/analytics/player/:client_id/
|
|
func PlayerStats(db *sql.DB) echo.HandlerFunc {
|
|
return func(c echo.Context) error {
|
|
clientID := c.Param("client_id")
|
|
if _, err := uuid.Parse(clientID); err != nil {
|
|
return c.JSON(http.StatusBadRequest, echo.Map{"error": "invalid client_id format"})
|
|
}
|
|
|
|
// Look up player.
|
|
var playerID int64
|
|
var totalSessions int
|
|
var firstSeen string
|
|
err := db.QueryRow(
|
|
"SELECT id, total_sessions, first_seen FROM players WHERE client_id = ?",
|
|
clientID,
|
|
).Scan(&playerID, &totalSessions, &firstSeen)
|
|
if err == sql.ErrNoRows {
|
|
return c.JSON(http.StatusNotFound, echo.Map{"error": "player not found"})
|
|
} else if err != nil {
|
|
return c.JSON(http.StatusInternalServerError, echo.Map{"error": "database error"})
|
|
}
|
|
|
|
// Get high score.
|
|
var highScore *int
|
|
var hs int
|
|
err = db.QueryRow(
|
|
"SELECT score FROM high_scores WHERE player_id = ?", playerID,
|
|
).Scan(&hs)
|
|
if err == nil {
|
|
highScore = &hs
|
|
}
|
|
|
|
// Get last 50 sessions.
|
|
rows, err := db.Query(
|
|
`SELECT id, score, level_reached, lives_used, duration_seconds,
|
|
end_reason, started_at, ended_at
|
|
FROM game_sessions
|
|
WHERE player_id = ?
|
|
ORDER BY ended_at DESC
|
|
LIMIT 50`,
|
|
playerID,
|
|
)
|
|
if err != nil {
|
|
return c.JSON(http.StatusInternalServerError, echo.Map{"error": "database error"})
|
|
}
|
|
defer rows.Close()
|
|
|
|
sessions := make([]models.SessionSummary, 0)
|
|
for rows.Next() {
|
|
var s models.SessionSummary
|
|
var startedAt, endedAt string
|
|
if err := rows.Scan(
|
|
&s.SessionID, &s.Score, &s.LevelReached, &s.LivesUsed,
|
|
&s.DurationSeconds, &s.EndReason, &startedAt, &endedAt,
|
|
); err != nil {
|
|
return c.JSON(http.StatusInternalServerError, echo.Map{"error": "scan error"})
|
|
}
|
|
s.StartedAt = parseTime(startedAt)
|
|
s.EndedAt = parseTime(endedAt)
|
|
sessions = append(sessions, s)
|
|
}
|
|
|
|
resp := models.PlayerStatsResponse{
|
|
ClientID: clientID,
|
|
TotalSessions: totalSessions,
|
|
FirstSeen: parseTime(firstSeen),
|
|
HighScore: highScore,
|
|
Sessions: sessions,
|
|
}
|
|
|
|
return c.JSON(http.StatusOK, resp)
|
|
}
|
|
}
|