we have fixtures ladies and gentleman
This commit is contained in:
@@ -20,10 +20,10 @@ func NewAudit(r *http.Request, u *User) *AuditMeta {
|
||||
|
||||
// AuditInfo contains metadata for audit logging
|
||||
type AuditInfo struct {
|
||||
Action string // e.g., "seasons.create", "users.update"
|
||||
ResourceType string // e.g., "season", "user"
|
||||
ResourceID any // Primary key value (int, string, etc.)
|
||||
Details map[string]any // Changed fields or additional metadata
|
||||
Action string // e.g., "seasons.create", "users.update"
|
||||
ResourceType string // e.g., "season", "user"
|
||||
ResourceID any // Primary key value (int, string, etc.)
|
||||
Details any // Changed fields or additional metadata
|
||||
}
|
||||
|
||||
// extractTableName gets the bun table name from a model type using reflection
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
)
|
||||
|
||||
func IsBadRequest(err error) bool {
|
||||
return strings.HasPrefix(err.Error(), "bad request:")
|
||||
return strings.Contains(err.Error(), "bad request:")
|
||||
}
|
||||
|
||||
func BadRequest(err string) error {
|
||||
@@ -18,14 +18,14 @@ func BadRequestNotFound(resource, field string, value any) error {
|
||||
return BadRequest(errStr)
|
||||
}
|
||||
|
||||
func BadRequestNotAssociated(parent, child string, parentID, childID any) error {
|
||||
errStr := fmt.Sprintf("%s (ID: %v) not associated with %s (ID: %v)",
|
||||
child, childID, parent, parentID)
|
||||
func BadRequestNotAssociated(parent, child, parentField, childField string, parentID, childID any) error {
|
||||
errStr := fmt.Sprintf("%s with %s=%v not associated to %s with %s=%v",
|
||||
child, childField, childID, parent, parentField, parentID)
|
||||
return BadRequest(errStr)
|
||||
}
|
||||
|
||||
func BadRequestAssociated(parent, child string, parentID, childID any) error {
|
||||
errStr := fmt.Sprintf("%s (ID: %v) already associated with %s (ID: %v)",
|
||||
child, childID, parent, parentID)
|
||||
func BadRequestAssociated(parent, child, parentField, childField string, parentID, childID any) error {
|
||||
errStr := fmt.Sprintf("%s with %s=%v already associated to %s with %s=%v",
|
||||
child, childField, childID, parent, parentField, parentID)
|
||||
return BadRequest(errStr)
|
||||
}
|
||||
|
||||
282
internal/db/fixture.go
Normal file
282
internal/db/fixture.go
Normal file
@@ -0,0 +1,282 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/uptrace/bun"
|
||||
)
|
||||
|
||||
type Fixture struct {
|
||||
bun.BaseModel `bun:"table:fixtures,alias:f"`
|
||||
|
||||
ID int `bun:"id,pk,autoincrement"`
|
||||
SeasonID int `bun:",notnull,unique:round"`
|
||||
LeagueID int `bun:",notnull,unique:round"`
|
||||
HomeTeamID int `bun:",notnull,unique:round"`
|
||||
AwayTeamID int `bun:",notnull,unique:round"`
|
||||
Round int `bun:"round,unique:round"`
|
||||
GameWeek *int `bun:"game_week"`
|
||||
CreatedAt int64 `bun:"created_at,notnull"`
|
||||
UpdatedAt *int64 `bun:"updated_at"`
|
||||
|
||||
Season *Season `bun:"rel:belongs-to,join:season_id=id"`
|
||||
League *League `bun:"rel:belongs-to,join:league_id=id"`
|
||||
HomeTeam *Team `bun:"rel:belongs-to,join:home_team_id=id"`
|
||||
AwayTeam *Team `bun:"rel:belongs-to,join:away_team_id=id"`
|
||||
}
|
||||
|
||||
func NewFixture(ctx context.Context, tx bun.Tx, seasonShortName, leagueShortName string,
|
||||
homeTeamID, awayTeamID, round int, audit *AuditMeta,
|
||||
) (*Fixture, error) {
|
||||
season, league, teams, err := GetSeasonLeague(ctx, tx, seasonShortName, leagueShortName)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "GetSeasonLeague")
|
||||
}
|
||||
homeTeam, err := GetTeam(ctx, tx, homeTeamID)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "GetTeam")
|
||||
}
|
||||
awayTeam, err := GetTeam(ctx, tx, awayTeamID)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "GetTeam")
|
||||
}
|
||||
if err = checkTeamsAssociated(season, league, teams, []*Team{homeTeam, awayTeam}); err != nil {
|
||||
return nil, errors.Wrap(err, "checkTeamsAssociated")
|
||||
}
|
||||
fixture := newFixture(season, league, homeTeam, awayTeam, round, time.Now())
|
||||
err = Insert(tx, fixture).WithAudit(audit, nil).Exec(ctx)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Insert")
|
||||
}
|
||||
return fixture, nil
|
||||
}
|
||||
|
||||
func NewRound(ctx context.Context, tx bun.Tx, seasonShortName, leagueShortName string,
|
||||
round int, audit *AuditMeta,
|
||||
) ([]*Fixture, error) {
|
||||
season, league, teams, err := GetSeasonLeague(ctx, tx, seasonShortName, leagueShortName)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "GetSeasonLeague")
|
||||
}
|
||||
fixtures := generateRound(season, league, round, teams)
|
||||
err = InsertMultiple(tx, fixtures).WithAudit(audit, nil).Exec(ctx)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "InsertMultiple")
|
||||
}
|
||||
return fixtures, nil
|
||||
}
|
||||
|
||||
func GetFixtures(ctx context.Context, tx bun.Tx, seasonShortName, leagueShortName string) (*Season, *League, []*Fixture, error) {
|
||||
season, league, _, err := GetSeasonLeague(ctx, tx, seasonShortName, leagueShortName)
|
||||
if err != nil {
|
||||
return nil, nil, nil, errors.Wrap(err, "GetSeasonLeague")
|
||||
}
|
||||
fixtures, err := GetList[Fixture](tx).
|
||||
Where("season_id = ?", season.ID).
|
||||
Where("league_id = ?", league.ID).
|
||||
Order("game_week ASC NULLS FIRST", "round ASC", "id ASC").
|
||||
Relation("HomeTeam").
|
||||
Relation("AwayTeam").
|
||||
GetAll(ctx)
|
||||
if err != nil {
|
||||
return nil, nil, nil, errors.Wrap(err, "GetList")
|
||||
}
|
||||
return season, league, fixtures, nil
|
||||
}
|
||||
|
||||
func GetFixture(ctx context.Context, tx bun.Tx, id int) (*Fixture, error) {
|
||||
return GetByID[Fixture](tx, id).
|
||||
Relation("Season").
|
||||
Relation("League").
|
||||
Relation("HomeTeam").
|
||||
Relation("AwayTeam").
|
||||
Get(ctx)
|
||||
}
|
||||
|
||||
func GetFixturesByGameWeek(ctx context.Context, tx bun.Tx, seasonID, leagueID, gameweek int) ([]*Fixture, error) {
|
||||
fixtures, err := GetList[Fixture](tx).
|
||||
Where("season_id = ?", seasonID).
|
||||
Where("league_id = ?", leagueID).
|
||||
Where("game_week = ?", gameweek).
|
||||
Order("round ASC", "id ASC").
|
||||
Relation("HomeTeam").
|
||||
Relation("AwayTeam").
|
||||
GetAll(ctx)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "GetList")
|
||||
}
|
||||
return fixtures, nil
|
||||
}
|
||||
|
||||
func GetUnallocatedFixtures(ctx context.Context, tx bun.Tx, seasonID, leagueID int) ([]*Fixture, error) {
|
||||
fixtures, err := GetList[Fixture](tx).
|
||||
Where("season_id = ?", seasonID).
|
||||
Where("league_id = ?", leagueID).
|
||||
Where("game_week IS NULL").
|
||||
Order("round ASC", "id ASC").
|
||||
Relation("HomeTeam").
|
||||
Relation("AwayTeam").
|
||||
GetAll(ctx)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "GetList")
|
||||
}
|
||||
return fixtures, nil
|
||||
}
|
||||
|
||||
func CountUnallocatedFixtures(ctx context.Context, tx bun.Tx, seasonID, leagueID int) (int, error) {
|
||||
count, err := GetList[Fixture](tx).
|
||||
Where("season_id = ?", seasonID).
|
||||
Where("league_id = ?", leagueID).
|
||||
Where("game_week IS NULL").
|
||||
Count(ctx)
|
||||
if err != nil {
|
||||
return 0, errors.Wrap(err, "GetList")
|
||||
}
|
||||
return count, nil
|
||||
}
|
||||
|
||||
func GetMaxGameWeek(ctx context.Context, tx bun.Tx, seasonID, leagueID int) (int, error) {
|
||||
var maxGameWeek int
|
||||
err := tx.NewSelect().
|
||||
Model((*Fixture)(nil)).
|
||||
Column("game_week").
|
||||
Where("season_id = ?", seasonID).
|
||||
Where("league_id = ?", leagueID).
|
||||
Order("game_week DESC NULLS LAST").
|
||||
Limit(1).Scan(ctx, &maxGameWeek)
|
||||
if err != nil {
|
||||
return 0, errors.Wrap(err, "tx.NewSelect")
|
||||
}
|
||||
return maxGameWeek, nil
|
||||
}
|
||||
|
||||
func UpdateFixtureGameWeeks(ctx context.Context, tx bun.Tx, fixtures []*Fixture, audit *AuditMeta) error {
|
||||
details := []any{}
|
||||
for _, fixture := range fixtures {
|
||||
err := UpdateByID(tx, fixture.ID, fixture).
|
||||
Column("game_week").
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "UpdateByID")
|
||||
}
|
||||
details = append(details, map[string]any{"fixture_id": fixture.ID, "game_week": fixture.GameWeek})
|
||||
}
|
||||
info := &AuditInfo{
|
||||
"fixtures.manage",
|
||||
"fixture",
|
||||
"multiple",
|
||||
map[string]any{"updated": details},
|
||||
}
|
||||
err := LogSuccess(ctx, tx, audit, info)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "LogSuccess")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeleteAllFixtures(ctx context.Context, tx bun.Tx, seasonShortName, leagueShortName string, audit *AuditMeta) error {
|
||||
season, league, _, err := GetSeasonLeague(ctx, tx, seasonShortName, leagueShortName)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "GetSeasonLeague")
|
||||
}
|
||||
err = DeleteItem[Fixture](tx).
|
||||
Where("season_id = ?", season.ID).
|
||||
Where("league_id = ?", league.ID).
|
||||
WithAudit(audit, nil).
|
||||
Delete(ctx)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "DeleteItem")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeleteFixture(ctx context.Context, tx bun.Tx, id int, audit *AuditMeta) error {
|
||||
err := DeleteByID[Fixture](tx, id).
|
||||
WithAudit(audit, nil).
|
||||
Delete(ctx)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "DeleteByID")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func newFixture(season *Season, league *League, homeTeam, awayTeam *Team, round int, created time.Time) *Fixture {
|
||||
return &Fixture{
|
||||
SeasonID: season.ID,
|
||||
LeagueID: league.ID,
|
||||
HomeTeamID: homeTeam.ID,
|
||||
AwayTeamID: awayTeam.ID,
|
||||
Round: round,
|
||||
CreatedAt: created.Unix(),
|
||||
}
|
||||
}
|
||||
|
||||
func checkTeamsAssociated(season *Season, league *League, teamsIn []*Team, toCheck []*Team) error {
|
||||
badIDs := []string{}
|
||||
master := map[int]bool{}
|
||||
for _, team := range teamsIn {
|
||||
master[team.ID] = true
|
||||
}
|
||||
for _, team := range toCheck {
|
||||
if !master[team.ID] {
|
||||
badIDs = append(badIDs, strconv.Itoa(team.ID))
|
||||
}
|
||||
}
|
||||
ids := strings.Join(badIDs, ",")
|
||||
if len(ids) > 0 {
|
||||
return BadRequestNotAssociated("season_league", "team",
|
||||
"season_id,league_id", "ids",
|
||||
fmt.Sprintf("%v,%v", season.ID, league.ID),
|
||||
ids)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type versus struct {
|
||||
homeTeam *Team
|
||||
awayTeam *Team
|
||||
}
|
||||
|
||||
func generateRound(season *Season, league *League, round int, teams []*Team) []*Fixture {
|
||||
now := time.Now()
|
||||
numTeams := len(teams)
|
||||
numGames := numTeams * (numTeams - 1) / 2
|
||||
fixtures := make([]*Fixture, numGames)
|
||||
for i, matchup := range allTeamsPlay(teams, round) {
|
||||
fixtures[i] = newFixture(season, league, matchup.homeTeam, matchup.awayTeam, round, now)
|
||||
}
|
||||
return fixtures
|
||||
}
|
||||
|
||||
func allTeamsPlay(teams []*Team, round int) []*versus {
|
||||
matchups := []*versus{}
|
||||
if len(teams) < 2 {
|
||||
return matchups
|
||||
}
|
||||
team1 := teams[0]
|
||||
teams = teams[1:]
|
||||
matchups = append(matchups, playOtherTeams(team1, teams, round)...)
|
||||
matchups = append(matchups, allTeamsPlay(teams, round)...)
|
||||
return matchups
|
||||
}
|
||||
|
||||
func playOtherTeams(team *Team, teams []*Team, round int) []*versus {
|
||||
matchups := make([]*versus, len(teams))
|
||||
for i, opponent := range teams {
|
||||
versus := &versus{}
|
||||
if i%2+round%2 == 0 {
|
||||
versus.homeTeam = team
|
||||
versus.awayTeam = opponent
|
||||
} else {
|
||||
versus.homeTeam = opponent
|
||||
versus.awayTeam = team
|
||||
}
|
||||
matchups[i] = versus
|
||||
}
|
||||
return matchups
|
||||
}
|
||||
@@ -92,6 +92,11 @@ func (l *listgetter[T]) Where(query string, args ...any) *listgetter[T] {
|
||||
return l
|
||||
}
|
||||
|
||||
func (l *listgetter[T]) Order(orders ...string) *listgetter[T] {
|
||||
l.q = l.q.Order(orders...)
|
||||
return l
|
||||
}
|
||||
|
||||
func (l *listgetter[T]) Relation(name string, apply ...func(*bun.SelectQuery) *bun.SelectQuery) *listgetter[T] {
|
||||
l.q = l.q.Relation(name, apply...)
|
||||
return l
|
||||
@@ -130,6 +135,14 @@ func (l *listgetter[T]) GetPaged(ctx context.Context, pageOpts, defaults *PageOp
|
||||
return list, nil
|
||||
}
|
||||
|
||||
func (l *listgetter[T]) Count(ctx context.Context) (int, error) {
|
||||
count, err := l.q.Count(ctx)
|
||||
if err != nil {
|
||||
return 0, errors.Wrap(err, "query.Count")
|
||||
}
|
||||
return count, nil
|
||||
}
|
||||
|
||||
func (l *listgetter[T]) GetAll(ctx context.Context) ([]*T, error) {
|
||||
err := l.q.Scan(ctx)
|
||||
if err != nil && errors.Is(err, sql.ErrNoRows) {
|
||||
|
||||
@@ -109,6 +109,7 @@ func (i *inserter[T]) Exec(ctx context.Context) error {
|
||||
}
|
||||
} else {
|
||||
i.auditInfo.ResourceID = extractPrimaryKey(i.model)
|
||||
i.auditInfo.Details = i.model
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,13 +10,13 @@ import (
|
||||
type League struct {
|
||||
bun.BaseModel `bun:"table:leagues,alias:l"`
|
||||
|
||||
ID int `bun:"id,pk,autoincrement"`
|
||||
Name string `bun:"name,unique,notnull"`
|
||||
ShortName string `bun:"short_name,unique,notnull"`
|
||||
Description string `bun:"description"`
|
||||
ID int `bun:"id,pk,autoincrement" json:"id"`
|
||||
Name string `bun:"name,unique,notnull" json:"name"`
|
||||
ShortName string `bun:"short_name,unique,notnull" json:"short_name"`
|
||||
Description string `bun:"description" json:"description"`
|
||||
|
||||
Seasons []Season `bun:"m2m:season_leagues,join:League=Season"`
|
||||
Teams []Team `bun:"m2m:team_participations,join:League=Team"`
|
||||
Seasons []Season `bun:"m2m:season_leagues,join:League=Season" json:"-"`
|
||||
Teams []Team `bun:"m2m:team_participations,join:League=Team" json:"-"`
|
||||
}
|
||||
|
||||
func GetLeagues(ctx context.Context, tx bun.Tx) ([]*League, error) {
|
||||
|
||||
@@ -256,7 +256,7 @@ func migrateStatus(ctx context.Context, migrator *migrate.Migrator) error {
|
||||
// validateMigrations ensures migrations compile before running
|
||||
func validateMigrations(ctx context.Context) error {
|
||||
cmd := exec.CommandContext(ctx, "go", "build",
|
||||
"-o", "/dev/null", "./cmd/oslstats/migrations")
|
||||
"-o", "/dev/null", "./internal/db/migrations")
|
||||
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
|
||||
@@ -31,12 +31,12 @@ func init() {
|
||||
Model(&permissionsData).
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "dbConn.NewInsert")
|
||||
return errors.Wrap(err, "conn.NewInsert")
|
||||
}
|
||||
return nil
|
||||
},
|
||||
// DOWN migration
|
||||
func(ctx context.Context, dbConn *bun.DB) error {
|
||||
func(ctx context.Context, conn *bun.DB) error {
|
||||
// Add your rollback code here
|
||||
return nil
|
||||
},
|
||||
|
||||
52
internal/db/migrations/20260215093841_add_fixtures.go
Normal file
52
internal/db/migrations/20260215093841_add_fixtures.go
Normal file
@@ -0,0 +1,52 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"git.haelnorr.com/h/oslstats/internal/db"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/uptrace/bun"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Migrations.MustRegister(
|
||||
// UP migration
|
||||
func(ctx context.Context, conn *bun.DB) error {
|
||||
// Add your migration code here
|
||||
_, err := conn.NewCreateTable().
|
||||
Model((*db.Fixture)(nil)).
|
||||
IfNotExists().
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
now := time.Now().Unix()
|
||||
permissionsData := []*db.Permission{
|
||||
{Name: "fixtures.create", DisplayName: "Create Fixtures", Description: "Create new fixtures", Resource: "fixtures", Action: "create", IsSystem: true, CreatedAt: now},
|
||||
{Name: "fixtures.manage", DisplayName: "Manage Fixtures", Description: "Manage fixtures", Resource: "fixtures", Action: "manage", IsSystem: true, CreatedAt: now},
|
||||
{Name: "fixtures.delete", DisplayName: "Delete Fixtures", Description: "Delete fixtures", Resource: "fixtures", Action: "delete", IsSystem: true, CreatedAt: now},
|
||||
}
|
||||
|
||||
_, err = conn.NewInsert().
|
||||
Model(&permissionsData).
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "conn.NewInsert")
|
||||
}
|
||||
return nil
|
||||
},
|
||||
// DOWN migration
|
||||
func(ctx context.Context, conn *bun.DB) error {
|
||||
// Add your rollback code here
|
||||
_, err := conn.NewDropTable().
|
||||
Model((*db.Fixture)(nil)).
|
||||
IfExists().
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
},
|
||||
)
|
||||
}
|
||||
@@ -28,17 +28,17 @@ const (
|
||||
type Season struct {
|
||||
bun.BaseModel `bun:"table:seasons,alias:s"`
|
||||
|
||||
ID int `bun:"id,pk,autoincrement"`
|
||||
Name string `bun:"name,unique,notnull"`
|
||||
ShortName string `bun:"short_name,unique,notnull"`
|
||||
StartDate time.Time `bun:"start_date,notnull"`
|
||||
EndDate bun.NullTime `bun:"end_date"`
|
||||
FinalsStartDate bun.NullTime `bun:"finals_start_date"`
|
||||
FinalsEndDate bun.NullTime `bun:"finals_end_date"`
|
||||
SlapVersion string `bun:"slap_version,notnull,default:'rebound'"`
|
||||
ID int `bun:"id,pk,autoincrement" json:"id"`
|
||||
Name string `bun:"name,unique,notnull" json:"name"`
|
||||
ShortName string `bun:"short_name,unique,notnull" json:"short_name"`
|
||||
StartDate time.Time `bun:"start_date,notnull" json:"start_date"`
|
||||
EndDate bun.NullTime `bun:"end_date" json:"end_date"`
|
||||
FinalsStartDate bun.NullTime `bun:"finals_start_date" json:"finals_start_date"`
|
||||
FinalsEndDate bun.NullTime `bun:"finals_end_date" json:"finals_end_date"`
|
||||
SlapVersion string `bun:"slap_version,notnull,default:'rebound'" json:"slap_version"`
|
||||
|
||||
Leagues []League `bun:"m2m:season_leagues,join:Season=League"`
|
||||
Teams []Team `bun:"m2m:team_participations,join:Season=Team"`
|
||||
Leagues []League `bun:"m2m:season_leagues,join:Season=League" json:"-"`
|
||||
Teams []Team `bun:"m2m:team_participations,join:Season=Team" json:"-"`
|
||||
}
|
||||
|
||||
// NewSeason creats a new season
|
||||
@@ -163,11 +163,21 @@ func (s *Season) GetDefaultTab() string {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Season) HasLeague(leagueID int) bool {
|
||||
for _, league := range s.Leagues {
|
||||
if league.ID == leagueID {
|
||||
func (s *Season) HasLeague(league *League) bool {
|
||||
for _, league_ := range s.Leagues {
|
||||
if league_.ID == league.ID {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (s *Season) GetLeague(leagueShortName string) (*League, error) {
|
||||
for _, league := range s.Leagues {
|
||||
if league.ShortName == leagueShortName {
|
||||
return &league, nil
|
||||
}
|
||||
}
|
||||
return nil, BadRequestNotAssociated("season", "league",
|
||||
"id", "short_name", s.ID, leagueShortName)
|
||||
}
|
||||
|
||||
@@ -24,19 +24,14 @@ func GetSeasonLeague(ctx context.Context, tx bun.Tx, seasonShortName, leagueShor
|
||||
return nil, nil, nil, errors.New("league short_name cannot be empty")
|
||||
}
|
||||
|
||||
// Get the season
|
||||
season, err := GetSeason(ctx, tx, seasonShortName)
|
||||
if err != nil {
|
||||
return nil, nil, nil, errors.Wrap(err, "GetSeason")
|
||||
}
|
||||
|
||||
// Get the league
|
||||
league, err := GetLeague(ctx, tx, leagueShortName)
|
||||
league, err := season.GetLeague(leagueShortName)
|
||||
if err != nil {
|
||||
return nil, nil, nil, errors.Wrap(err, "GetLeague")
|
||||
}
|
||||
if !season.HasLeague(league.ID) {
|
||||
return nil, nil, nil, BadRequestNotAssociated("season", "league", seasonShortName, leagueShortName)
|
||||
return nil, nil, nil, errors.Wrap(err, "season.GetLeague")
|
||||
}
|
||||
|
||||
// Get all teams participating in this season+league
|
||||
@@ -63,8 +58,9 @@ func NewSeasonLeague(ctx context.Context, tx bun.Tx, seasonShortName, leagueShor
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "GetLeague")
|
||||
}
|
||||
if season.HasLeague(league.ID) {
|
||||
return BadRequestAssociated("season", "league", seasonShortName, leagueShortName)
|
||||
if season.HasLeague(league) {
|
||||
return BadRequestAssociated("season", "league",
|
||||
"id", "id", season.ID, league.ID)
|
||||
}
|
||||
seasonLeague := &SeasonLeague{
|
||||
SeasonID: season.ID,
|
||||
@@ -84,12 +80,9 @@ func NewSeasonLeague(ctx context.Context, tx bun.Tx, seasonShortName, leagueShor
|
||||
}
|
||||
|
||||
func (s *Season) RemoveLeague(ctx context.Context, tx bun.Tx, leagueShortName string, audit *AuditMeta) error {
|
||||
league, err := GetLeague(ctx, tx, leagueShortName)
|
||||
league, err := s.GetLeague(leagueShortName)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "GetLeague")
|
||||
}
|
||||
if !s.HasLeague(league.ID) {
|
||||
return errors.New("league not in season")
|
||||
return errors.Wrap(err, "s.GetLeague")
|
||||
}
|
||||
info := &AuditInfo{
|
||||
string(permissions.SeasonsRemoveLeague),
|
||||
@@ -107,3 +100,12 @@ func (s *Season) RemoveLeague(ctx context.Context, tx bun.Tx, leagueShortName st
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *Team) InTeams(teams []*Team) bool {
|
||||
for _, team := range teams {
|
||||
if t.ID == team.ID {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -9,14 +9,14 @@ import (
|
||||
|
||||
type Team struct {
|
||||
bun.BaseModel `bun:"table:teams,alias:t"`
|
||||
ID int `bun:"id,pk,autoincrement"`
|
||||
Name string `bun:"name,unique,notnull"`
|
||||
ShortName string `bun:"short_name,notnull,unique:short_names"`
|
||||
AltShortName string `bun:"alt_short_name,notnull,unique:short_names"`
|
||||
Color string `bun:"color"`
|
||||
ID int `bun:"id,pk,autoincrement" json:"id"`
|
||||
Name string `bun:"name,unique,notnull" json:"name"`
|
||||
ShortName string `bun:"short_name,notnull,unique:short_names" json:"short_name"`
|
||||
AltShortName string `bun:"alt_short_name,notnull,unique:short_names" json:"alt_short_name"`
|
||||
Color string `bun:"color" json:"color,omitempty"`
|
||||
|
||||
Seasons []Season `bun:"m2m:team_participations,join:Team=Season"`
|
||||
Leagues []League `bun:"m2m:team_participations,join:Team=League"`
|
||||
Seasons []Season `bun:"m2m:team_participations,join:Team=Season" json:"-"`
|
||||
Leagues []League `bun:"m2m:team_participations,join:Team=League" json:"-"`
|
||||
}
|
||||
|
||||
func NewTeam(ctx context.Context, tx bun.Tx, name, shortName, altShortName, color string, audit *AuditMeta) (*Team, error) {
|
||||
|
||||
@@ -23,19 +23,17 @@ func NewTeamParticipation(ctx context.Context, tx bun.Tx,
|
||||
if err != nil {
|
||||
return nil, nil, nil, errors.Wrap(err, "GetSeason")
|
||||
}
|
||||
league, err := GetLeague(ctx, tx, leagueShortName)
|
||||
league, err := season.GetLeague(leagueShortName)
|
||||
if err != nil {
|
||||
return nil, nil, nil, errors.Wrap(err, "GetLeague")
|
||||
}
|
||||
if !season.HasLeague(league.ID) {
|
||||
return nil, nil, nil, BadRequestNotAssociated("season", "league", seasonShortName, leagueShortName)
|
||||
return nil, nil, nil, errors.Wrap(err, "season.GetLeague")
|
||||
}
|
||||
team, err := GetTeam(ctx, tx, teamID)
|
||||
if err != nil {
|
||||
return nil, nil, nil, errors.Wrap(err, "GetTeam")
|
||||
}
|
||||
if team.InSeason(season.ID) {
|
||||
return nil, nil, nil, BadRequestAssociated("season", "team", seasonShortName, teamID)
|
||||
return nil, nil, nil, BadRequestAssociated("season", "team",
|
||||
"id", "id", season.ID, team.ID)
|
||||
}
|
||||
participation := &TeamParticipation{
|
||||
SeasonID: season.ID,
|
||||
|
||||
@@ -15,12 +15,12 @@ import (
|
||||
type User struct {
|
||||
bun.BaseModel `bun:"table:users,alias:u"`
|
||||
|
||||
ID int `bun:"id,pk,autoincrement"` // Integer ID (index primary key)
|
||||
Username string `bun:"username,unique"` // Username (unique)
|
||||
CreatedAt int64 `bun:"created_at"` // Epoch timestamp when the user was added to the database
|
||||
DiscordID string `bun:"discord_id,unique"`
|
||||
ID int `bun:"id,pk,autoincrement" json:"id"`
|
||||
Username string `bun:"username,unique" json:"username"`
|
||||
CreatedAt int64 `bun:"created_at" json:"created_at"`
|
||||
DiscordID string `bun:"discord_id,unique" json:"discord_id"`
|
||||
|
||||
Roles []*Role `bun:"m2m:user_roles,join:User=Role"`
|
||||
Roles []*Role `bun:"m2m:user_roles,join:User=Role" json:"-"`
|
||||
}
|
||||
|
||||
func (u *User) GetID() int {
|
||||
|
||||
Reference in New Issue
Block a user