mirror of
https://github.com/nprasad2077/NBA_Go.git
synced 2026-09-22 22:15:13 +00:00
252 lines
7.9 KiB
Go
252 lines
7.9 KiB
Go
package controllers
|
|
|
|
import (
|
|
"github.com/gofiber/fiber/v2"
|
|
"github.com/nprasad2077/NBA_Go/models"
|
|
"github.com/nprasad2077/NBA_Go/services"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
// --- MODIFICATION START ---
|
|
// A DTO is created to control the JSON output.
|
|
// It omits fields like ID, ExternalID, CreatedAt, UpdatedAt, and DeletedAt.
|
|
type PlayerTotalStatDTO struct {
|
|
PlayerID string `json:"playerId"`
|
|
PlayerName string `json:"playerName"`
|
|
Position string `json:"position"`
|
|
Age int `json:"age"`
|
|
Games int `json:"games"`
|
|
GamesStarted int `json:"gamesStarted"`
|
|
MinutesPG float64 `json:"minutesPg"`
|
|
FieldGoals int `json:"fieldGoals"`
|
|
FieldAttempts int `json:"fieldAttempts"`
|
|
FieldPercent float64 `json:"fieldPercent"`
|
|
ThreeFG int `json:"threeFg"`
|
|
ThreeAttempts int `json:"threeAttempts"`
|
|
ThreePercent float64 `json:"threePercent"`
|
|
TwoFG int `json:"twoFg"`
|
|
TwoAttempts int `json:"twoAttempts"`
|
|
TwoPercent float64 `json:"twoPercent"`
|
|
EffectFGPercent float64 `json:"effectFgPercent"`
|
|
FT int `json:"ft"`
|
|
FTAttempts int `json:"ftAttempts"`
|
|
FTPercent float64 `json:"ftPercent"`
|
|
OffensiveRB int `json:"offensiveRb"`
|
|
DefensiveRB int `json:"defensiveRb"`
|
|
TotalRB int `json:"totalRb"`
|
|
Assists int `json:"assists"`
|
|
Steals int `json:"steals"`
|
|
Blocks int `json:"blocks"`
|
|
Turnovers int `json:"turnovers"`
|
|
PersonalFouls int `json:"personalFouls"`
|
|
Points int `json:"points"`
|
|
Team string `json:"team"`
|
|
Season int `json:"season"`
|
|
IsPlayoff bool `json:"isPlayoff"`
|
|
}
|
|
|
|
// A dedicated response struct is created for cleaner, type-safe code.
|
|
type PlayerTotalsResponse struct {
|
|
Data []PlayerTotalStatDTO `json:"data"`
|
|
Pagination struct {
|
|
Total int64 `json:"total"`
|
|
Page int `json:"page"`
|
|
PageSize int `json:"pageSize"`
|
|
Pages int64 `json:"pages"`
|
|
} `json:"pagination"`
|
|
}
|
|
// --- MODIFICATION END ---
|
|
|
|
|
|
var totalSortMap = map[string]string{
|
|
"playerId": "player_id",
|
|
"playerName": "player_name",
|
|
"position": "position",
|
|
"age": "age",
|
|
"games": "games",
|
|
"gamesStarted": "games_started",
|
|
"minutesPg": "minutes_pg",
|
|
"fieldGoals": "field_goals",
|
|
"fieldAttempts": "field_attempts",
|
|
"fieldPercent": "field_percent",
|
|
"threeFg": "three_fg",
|
|
"threeAttempts": "three_attempts",
|
|
"threePercent": "three_percent",
|
|
"twoFg": "two_fg",
|
|
"twoAttempts": "two_attempts",
|
|
"twoPercent": "two_percent",
|
|
"effectFgPercent": "effect_fg_percent",
|
|
"ft": "ft",
|
|
"ftAttempts": "ft_attempts",
|
|
"ftPercent": "ft_percent",
|
|
"offensiveRb": "offensive_rb",
|
|
"defensiveRb": "defensive_rb",
|
|
"totalRb": "total_rb",
|
|
"assists": "assists",
|
|
"steals": "steals",
|
|
"blocks": "blocks",
|
|
"turnovers": "turnovers",
|
|
"personalFouls": "personal_fouls",
|
|
"points": "points",
|
|
"team": "team",
|
|
"season": "season",
|
|
}
|
|
|
|
// ScrapePlayerTotalStats godoc
|
|
// @ignore
|
|
// @Summary Scrape player total stats from BR website
|
|
// @Tags PlayerTotals
|
|
// @Param season query int true "Season (e.g. 2025)"
|
|
// @Param isPlayoff query bool false "Whether playoffs?"
|
|
// @Success 200 {object} map[string]string
|
|
// @Failure 400,500 {object} map[string]string
|
|
// //@Router /api/playertotals/scrape [get]
|
|
func ScrapePlayerTotalStats(db *gorm.DB) fiber.Handler {
|
|
return func(c *fiber.Ctx) error {
|
|
season := c.QueryInt("season", 0)
|
|
if season == 0 {
|
|
return c.Status(400).JSON(fiber.Map{"error": "season is required"})
|
|
}
|
|
isPlayoff := c.QueryBool("isPlayoff", false)
|
|
|
|
if err := services.FetchAndStorePlayerTotalScrapedStats(db, season, isPlayoff); err != nil {
|
|
return c.Status(500).JSON(fiber.Map{"error": err.Error()})
|
|
}
|
|
return c.JSON(fiber.Map{"message": "scrapestore complete"})
|
|
}
|
|
}
|
|
|
|
// GetPlayerTotalStats godoc
|
|
// //@Security ApiKeyAuth
|
|
// @Summary Get player total stats
|
|
// @Description Filter and paginate player totals
|
|
// @Tags PlayerTotals
|
|
// @x-order 1
|
|
// @Group Player Stats
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param season query int false "Season (e.g. 2000)"
|
|
// @Param team query string false "Team abbreviation (e.g. LAL)"
|
|
// @Param playerId query string false "Player ID (e.g. greenac01)"
|
|
// @Param page query int false "Page number" default(1)
|
|
// @Param pageSize query int false "Page size" default(20)
|
|
// @Param sortBy query string false "Field to sort by (e.g. points, assists)"
|
|
// @Param ascending query bool false "Sort ascending (default false)"
|
|
// @Param isPlayoff query bool false "Whether the stats are for playoffs"
|
|
// @Success 200 {object} controllers.PlayerTotalsResponse
|
|
// @Failure 500 {object} map[string]string
|
|
// @Router /api/playertotals [get]
|
|
func GetPlayerTotalStats(db *gorm.DB) fiber.Handler {
|
|
return func(c *fiber.Ctx) error {
|
|
var stats []models.PlayerTotalStat
|
|
|
|
// --- FILTERS ---
|
|
playerId := c.Query("playerId")
|
|
if playerId == "" {
|
|
playerId = c.Query("player_id")
|
|
}
|
|
|
|
season := c.QueryInt("season", 0)
|
|
team := c.Query("team")
|
|
page := c.QueryInt("page", 1)
|
|
pageSize := c.QueryInt("pageSize", 20)
|
|
if pageSize > 50 {
|
|
pageSize = 50
|
|
}
|
|
|
|
// --- SORTING ---
|
|
sortByParam := c.Query("sortBy", "points")
|
|
ascending := c.QueryBool("ascending", false)
|
|
|
|
// Translate sortBy param to a valid DB column, defaulting if not found.
|
|
sortBy, ok := totalSortMap[sortByParam]
|
|
if !ok {
|
|
sortBy = "points" // Safe default
|
|
}
|
|
|
|
offset := (page - 1) * pageSize
|
|
order := sortBy + " DESC"
|
|
if ascending {
|
|
order = sortBy + " ASC"
|
|
}
|
|
|
|
query := db.Model(&models.PlayerTotalStat{})
|
|
|
|
if season != 0 {
|
|
query = query.Where("season = ?", season)
|
|
}
|
|
if team != "" {
|
|
query = query.Where("team = ?", team)
|
|
}
|
|
if playerId != "" {
|
|
query = query.Where("player_id = ?", playerId)
|
|
}
|
|
|
|
isPlayoffStr := c.Query("isPlayoff")
|
|
if isPlayoffStr != "" {
|
|
isPlayoff := c.QueryBool("isPlayoff", false)
|
|
query = query.Where("is_playoff = ?", isPlayoff)
|
|
}
|
|
|
|
var total int64
|
|
query.Count(&total)
|
|
|
|
err := query.Order(order).Limit(pageSize).Offset(offset).Find(&stats).Error
|
|
if err != nil {
|
|
return c.Status(500).JSON(fiber.Map{"error": err.Error()})
|
|
}
|
|
|
|
// --- MODIFICATION START ---
|
|
// Transform the database models into DTOs.
|
|
playerTotalDTOs := make([]PlayerTotalStatDTO, len(stats))
|
|
for i, s := range stats {
|
|
playerTotalDTOs[i] = PlayerTotalStatDTO{
|
|
PlayerID: s.PlayerID,
|
|
PlayerName: s.PlayerName,
|
|
Position: s.Position,
|
|
Age: s.Age,
|
|
Games: s.Games,
|
|
GamesStarted: s.GamesStarted,
|
|
MinutesPG: s.MinutesPG,
|
|
FieldGoals: s.FieldGoals,
|
|
FieldAttempts: s.FieldAttempts,
|
|
FieldPercent: s.FieldPercent,
|
|
ThreeFG: s.ThreeFG,
|
|
ThreeAttempts: s.ThreeAttempts,
|
|
ThreePercent: s.ThreePercent,
|
|
TwoFG: s.TwoFG,
|
|
TwoAttempts: s.TwoAttempts,
|
|
TwoPercent: s.TwoPercent,
|
|
EffectFGPercent: s.EffectFGPercent,
|
|
FT: s.FT,
|
|
FTAttempts: s.FTAttempts,
|
|
FTPercent: s.FTPercent,
|
|
OffensiveRB: s.OffensiveRB,
|
|
DefensiveRB: s.DefensiveRB,
|
|
TotalRB: s.TotalRB,
|
|
Assists: s.Assists,
|
|
Steals: s.Steals,
|
|
Blocks: s.Blocks,
|
|
Turnovers: s.Turnovers,
|
|
PersonalFouls: s.PersonalFouls,
|
|
Points: s.Points,
|
|
Team: s.Team,
|
|
Season: s.Season,
|
|
IsPlayoff: s.IsPlayoff,
|
|
}
|
|
}
|
|
|
|
// Build the final response using the new DTOs and response struct.
|
|
resp := PlayerTotalsResponse{
|
|
Data: playerTotalDTOs,
|
|
}
|
|
resp.Pagination.Total = total
|
|
resp.Pagination.Page = page
|
|
resp.Pagination.PageSize = pageSize
|
|
resp.Pagination.Pages = (total + int64(pageSize) - 1) / int64(pageSize)
|
|
|
|
return c.JSON(resp)
|
|
// --- MODIFICATION END ---
|
|
}
|
|
}
|