248 lines
6.8 KiB
Go
248 lines
6.8 KiB
Go
package db
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
"github.com/pkg/errors"
|
|
"github.com/uptrace/bun"
|
|
)
|
|
|
|
type TeamRoster struct {
|
|
bun.BaseModel `bun:"table:team_rosters,alias:tr"`
|
|
TeamID int `bun:",pk,notnull" json:"team_id"`
|
|
SeasonID int `bun:",pk,notnull,unique:player" json:"season_id"`
|
|
LeagueID int `bun:",pk,notnull,unique:player" json:"league_id"`
|
|
PlayerID int `bun:",pk,notnull,unique:player" json:"player_id"`
|
|
IsManager bool `bun:"is_manager,default:'false'" json:"is_manager"`
|
|
|
|
Team *Team `bun:"rel:belongs-to,join:team_id=id" json:"-"`
|
|
Player *Player `bun:"rel:belongs-to,join:player_id=id" json:"-"`
|
|
Season *Season `bun:"rel:belongs-to,join:season_id=id" json:"-"`
|
|
League *League `bun:"rel:belongs-to,join:league_id=id" json:"-"`
|
|
}
|
|
|
|
type TeamWithRoster struct {
|
|
Team *Team
|
|
Season *Season
|
|
League *League
|
|
Manager *Player
|
|
Players []*Player
|
|
}
|
|
|
|
func GetTeamRoster(ctx context.Context, tx bun.Tx, seasonShortName, leagueShortName string, teamID int) (*TeamWithRoster, error) {
|
|
tr := []*TeamRoster{}
|
|
err := tx.NewSelect().
|
|
Model(&tr).
|
|
Relation("Team", func(q *bun.SelectQuery) *bun.SelectQuery {
|
|
return q.Where("team.id = ?", teamID)
|
|
}).
|
|
Relation("Season", func(q *bun.SelectQuery) *bun.SelectQuery {
|
|
return q.Where("season.short_name = ?", seasonShortName)
|
|
}).
|
|
Relation("League", func(q *bun.SelectQuery) *bun.SelectQuery {
|
|
return q.Where("league.short_name = ?", leagueShortName)
|
|
}).
|
|
Relation("Player").Scan(ctx)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "tx.NewSelect")
|
|
}
|
|
team, err := GetTeam(ctx, tx, teamID)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "GetTeam")
|
|
}
|
|
sl, err := GetSeasonLeague(ctx, tx, seasonShortName, leagueShortName)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "GetSeasonLeague")
|
|
}
|
|
var manager *Player
|
|
players := []*Player{}
|
|
for _, tp := range tr {
|
|
if tp.IsManager {
|
|
manager = tp.Player
|
|
} else {
|
|
players = append(players, tp.Player)
|
|
}
|
|
}
|
|
players = append([]*Player{manager}, players...)
|
|
twr := &TeamWithRoster{
|
|
team,
|
|
sl.Season,
|
|
sl.League,
|
|
manager,
|
|
players,
|
|
}
|
|
return twr, nil
|
|
}
|
|
|
|
// GetManagersByTeam returns a map of teamID -> manager Player for all teams in a season/league
|
|
func GetManagersByTeam(ctx context.Context, tx bun.Tx, seasonID, leagueID int) (map[int]*Player, error) {
|
|
rosters := []*TeamRoster{}
|
|
err := tx.NewSelect().
|
|
Model(&rosters).
|
|
Where("tr.season_id = ?", seasonID).
|
|
Where("tr.league_id = ?", leagueID).
|
|
Where("tr.is_manager = true").
|
|
Relation("Player").
|
|
Scan(ctx)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "tx.NewSelect")
|
|
}
|
|
result := make(map[int]*Player, len(rosters))
|
|
for _, r := range rosters {
|
|
result[r.TeamID] = r.Player
|
|
}
|
|
return result, nil
|
|
}
|
|
|
|
func AddPlayerToTeam(ctx context.Context, tx bun.Tx, seasonID, leagueID, teamID, playerID int, manager bool, audit *AuditMeta) error {
|
|
season, err := GetByID[Season](tx, seasonID).Get(ctx)
|
|
if err != nil {
|
|
return errors.Wrap(err, "GetSeason")
|
|
}
|
|
league, err := GetByID[League](tx, leagueID).Get(ctx)
|
|
if err != nil {
|
|
return errors.Wrap(err, "GetLeague")
|
|
}
|
|
team, err := GetByID[Team](tx, teamID).Get(ctx)
|
|
if err != nil {
|
|
return errors.Wrap(err, "GetTeam")
|
|
}
|
|
player, err := GetByID[Player](tx, playerID).Get(ctx)
|
|
if err != nil {
|
|
return errors.Wrap(err, "GetPlayer")
|
|
}
|
|
tr := &TeamRoster{
|
|
SeasonID: season.ID,
|
|
LeagueID: league.ID,
|
|
TeamID: team.ID,
|
|
PlayerID: player.ID,
|
|
IsManager: manager,
|
|
}
|
|
err = Insert(tx, tr).WithAudit(audit, nil).Exec(ctx)
|
|
if err != nil {
|
|
return errors.Wrap(err, "Insert")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// ManageTeamRoster replaces the entire roster for a team in a season/league.
|
|
// It deletes all existing roster entries and inserts the new ones.
|
|
// Also auto-removes free agent registrations and nominations for players joining a team.
|
|
func ManageTeamRoster(ctx context.Context, tx bun.Tx, seasonID, leagueID, teamID, managerID int, playerIDs []int, audit *AuditMeta) error {
|
|
// Delete all existing roster entries for this team/season/league
|
|
_, err := tx.NewDelete().
|
|
Model((*TeamRoster)(nil)).
|
|
Where("season_id = ?", seasonID).
|
|
Where("league_id = ?", leagueID).
|
|
Where("team_id = ?", teamID).
|
|
Exec(ctx)
|
|
if err != nil {
|
|
return errors.Wrap(err, "delete existing roster")
|
|
}
|
|
|
|
// Collect all player IDs being added (including manager)
|
|
allPlayerIDs := make([]int, 0, len(playerIDs)+1)
|
|
if managerID > 0 {
|
|
allPlayerIDs = append(allPlayerIDs, managerID)
|
|
}
|
|
for _, pid := range playerIDs {
|
|
if pid != managerID {
|
|
allPlayerIDs = append(allPlayerIDs, pid)
|
|
}
|
|
}
|
|
|
|
// Auto-remove free agent registrations and nominations for players joining a team
|
|
for _, playerID := range allPlayerIDs {
|
|
// Check if the player is a registered free agent
|
|
isFA, err := IsFreeAgentRegistered(ctx, tx, seasonID, leagueID, playerID)
|
|
if err != nil {
|
|
return errors.Wrap(err, "IsFreeAgentRegistered")
|
|
}
|
|
if isFA {
|
|
// Remove all nominations for this player
|
|
err = RemoveAllFreeAgentNominationsForPlayer(ctx, tx, playerID)
|
|
if err != nil {
|
|
return errors.Wrap(err, "RemoveAllFreeAgentNominationsForPlayer")
|
|
}
|
|
// Remove free agent registration
|
|
err = RemoveFreeAgentRegistrationForPlayer(ctx, tx, playerID)
|
|
if err != nil {
|
|
return errors.Wrap(err, "RemoveFreeAgentRegistrationForPlayer")
|
|
}
|
|
// Log the cascade action
|
|
if audit != nil {
|
|
cascadeInfo := &AuditInfo{
|
|
"free_agents.auto_removed_on_team_join",
|
|
"season_league_free_agent",
|
|
fmt.Sprintf("%d-%d-%d", seasonID, leagueID, playerID),
|
|
map[string]any{
|
|
"season_id": seasonID,
|
|
"league_id": leagueID,
|
|
"player_id": playerID,
|
|
"team_id": teamID,
|
|
},
|
|
}
|
|
err = LogSuccess(ctx, tx, audit, cascadeInfo)
|
|
if err != nil {
|
|
return errors.Wrap(err, "LogSuccess cascade")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Insert manager if provided
|
|
if managerID > 0 {
|
|
tr := &TeamRoster{
|
|
SeasonID: seasonID,
|
|
LeagueID: leagueID,
|
|
TeamID: teamID,
|
|
PlayerID: managerID,
|
|
IsManager: true,
|
|
}
|
|
err = Insert(tx, tr).Exec(ctx)
|
|
if err != nil {
|
|
return errors.Wrap(err, "Insert manager")
|
|
}
|
|
}
|
|
|
|
// Insert players
|
|
for _, playerID := range playerIDs {
|
|
if playerID == managerID {
|
|
continue // Already inserted as manager
|
|
}
|
|
tr := &TeamRoster{
|
|
SeasonID: seasonID,
|
|
LeagueID: leagueID,
|
|
TeamID: teamID,
|
|
PlayerID: playerID,
|
|
IsManager: false,
|
|
}
|
|
err = Insert(tx, tr).Exec(ctx)
|
|
if err != nil {
|
|
return errors.Wrap(err, "Insert player")
|
|
}
|
|
}
|
|
|
|
// Log the roster change
|
|
details := map[string]any{
|
|
"season_id": seasonID,
|
|
"league_id": leagueID,
|
|
"team_id": teamID,
|
|
"manager_id": managerID,
|
|
"player_ids": playerIDs,
|
|
}
|
|
info := &AuditInfo{
|
|
"teams.manage_players",
|
|
"team_roster",
|
|
fmt.Sprintf("%d-%d-%d", seasonID, leagueID, teamID),
|
|
details,
|
|
}
|
|
err = LogSuccess(ctx, tx, audit, info)
|
|
if err != nil {
|
|
return errors.Wrap(err, "LogSuccess")
|
|
}
|
|
|
|
return nil
|
|
}
|