mirror of
https://github.com/Team254/cheesy-arena-lite.git
synced 2026-03-09 21:56:50 -04:00
Convert EventSettings, Match, and MatchResult models to use Bolt DB.
This commit is contained in:
@@ -1,37 +0,0 @@
|
||||
-- +goose Up
|
||||
CREATE TABLE event_settings (
|
||||
id INTEGER PRIMARY KEY,
|
||||
name VARCHAR(255),
|
||||
numelimalliances int,
|
||||
selectionround2order VARCHAR(1),
|
||||
selectionround3order VARCHAR(1),
|
||||
teaminfodownloadenabled bool,
|
||||
tbapublishingenabled bool,
|
||||
tbaeventcode VARCHAR(16),
|
||||
tbasecretid VARCHAR(255),
|
||||
tbasecret VARCHAR(255),
|
||||
networksecurityenabled bool,
|
||||
apaddress VARCHAR(255),
|
||||
apusername VARCHAR(255),
|
||||
appassword VARCHAR(255),
|
||||
apteamchannel int,
|
||||
apadminchannel int,
|
||||
apadminwpakey VARCHAR(255),
|
||||
ap2address VARCHAR(255),
|
||||
ap2username VARCHAR(255),
|
||||
ap2password VARCHAR(255),
|
||||
ap2teamchannel int,
|
||||
switchaddress VARCHAR(255),
|
||||
switchpassword VARCHAR(255),
|
||||
plcaddress VARCHAR(255),
|
||||
tbadownloadenabled bool,
|
||||
adminpassword VARCHAR(255),
|
||||
warmupdurationsec int,
|
||||
autodurationsec int,
|
||||
pausedurationsec int,
|
||||
teleopdurationsec int,
|
||||
warningremainingdurationsec int
|
||||
);
|
||||
|
||||
-- +goose Down
|
||||
DROP TABLE event_settings;
|
||||
@@ -1,31 +0,0 @@
|
||||
-- +goose Up
|
||||
CREATE TABLE matches (
|
||||
id INTEGER PRIMARY KEY,
|
||||
type VARCHAR(16),
|
||||
displayname VARCHAR(16),
|
||||
time DATETIME,
|
||||
elimround int,
|
||||
elimgroup int,
|
||||
eliminstance int,
|
||||
elimredalliance int,
|
||||
elimbluealliance int,
|
||||
red1 int,
|
||||
red1issurrogate bool,
|
||||
red2 int,
|
||||
red2issurrogate bool,
|
||||
red3 int,
|
||||
red3issurrogate bool,
|
||||
blue1 int,
|
||||
blue1issurrogate bool,
|
||||
blue2 int,
|
||||
blue2issurrogate bool,
|
||||
blue3 int,
|
||||
blue3issurrogate bool,
|
||||
startedat DATETIME,
|
||||
scorecommittedat DATETIME,
|
||||
status VARCHAR(16)
|
||||
);
|
||||
CREATE UNIQUE INDEX type_displayname ON matches(type, displayname);
|
||||
|
||||
-- +goose Down
|
||||
DROP TABLE matches;
|
||||
@@ -1,13 +0,0 @@
|
||||
-- +goose Up
|
||||
CREATE TABLE match_results (
|
||||
id INTEGER PRIMARY KEY,
|
||||
matchid int,
|
||||
playnumber int,
|
||||
matchtype VARCHAR(16),
|
||||
redscorejson text,
|
||||
bluescorejson text
|
||||
);
|
||||
CREATE UNIQUE INDEX matchid_playnumber ON match_results(matchid, playnumber);
|
||||
|
||||
-- +goose Down
|
||||
DROP TABLE match_results;
|
||||
@@ -263,7 +263,7 @@ func (arena *Arena) SubstituteTeam(teamId int, station string) error {
|
||||
arena.MatchLoadNotifier.Notify()
|
||||
|
||||
if arena.CurrentMatch.Type != "test" {
|
||||
arena.Database.SaveMatch(arena.CurrentMatch)
|
||||
arena.Database.UpdateMatch(arena.CurrentMatch)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -275,7 +275,7 @@ func (arena *Arena) StartMatch() error {
|
||||
// Save the match start time and game-specifc data to the database for posterity.
|
||||
arena.CurrentMatch.StartedAt = time.Now()
|
||||
if arena.CurrentMatch.Type != "test" {
|
||||
arena.Database.SaveMatch(arena.CurrentMatch)
|
||||
arena.Database.UpdateMatch(arena.CurrentMatch)
|
||||
}
|
||||
arena.updateCycleTime(arena.CurrentMatch.StartedAt)
|
||||
|
||||
|
||||
@@ -82,7 +82,7 @@ func (arena *Arena) generateArenaStatusMessage() interface{} {
|
||||
}
|
||||
|
||||
return &struct {
|
||||
MatchId int
|
||||
MatchId int64
|
||||
AllianceStations map[string]*AllianceStation
|
||||
TeamWifiStatuses map[string]network.TeamWifiStatus
|
||||
MatchState
|
||||
|
||||
@@ -388,13 +388,13 @@ func TestLoadNextMatch(t *testing.T) {
|
||||
arena.Database.CreateMatch(&qualificationMatch2)
|
||||
|
||||
// Test match should be followed by another, empty test match.
|
||||
assert.Equal(t, 0, arena.CurrentMatch.Id)
|
||||
assert.Equal(t, int64(0), arena.CurrentMatch.Id)
|
||||
err := arena.SubstituteTeam(1114, "R1")
|
||||
assert.Nil(t, err)
|
||||
arena.CurrentMatch.Status = model.TieMatch
|
||||
err = arena.LoadNextMatch()
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 0, arena.CurrentMatch.Id)
|
||||
assert.Equal(t, int64(0), arena.CurrentMatch.Id)
|
||||
assert.Equal(t, 0, arena.CurrentMatch.Red1)
|
||||
assert.Equal(t, false, arena.CurrentMatch.IsComplete())
|
||||
|
||||
@@ -405,15 +405,15 @@ func TestLoadNextMatch(t *testing.T) {
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, practiceMatch1.Id, arena.CurrentMatch.Id)
|
||||
practiceMatch1.Status = model.RedWonMatch
|
||||
arena.Database.SaveMatch(&practiceMatch1)
|
||||
arena.Database.UpdateMatch(&practiceMatch1)
|
||||
err = arena.LoadNextMatch()
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, practiceMatch3.Id, arena.CurrentMatch.Id)
|
||||
practiceMatch3.Status = model.BlueWonMatch
|
||||
arena.Database.SaveMatch(&practiceMatch3)
|
||||
arena.Database.UpdateMatch(&practiceMatch3)
|
||||
err = arena.LoadNextMatch()
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 0, arena.CurrentMatch.Id)
|
||||
assert.Equal(t, int64(0), arena.CurrentMatch.Id)
|
||||
assert.Equal(t, "test", arena.CurrentMatch.Type)
|
||||
|
||||
err = arena.LoadMatch(&qualificationMatch1)
|
||||
|
||||
@@ -122,5 +122,5 @@ func setMatch(database *model.Database, match *model.Match, matchTime time.Time,
|
||||
} else {
|
||||
match.Status = model.MatchNotPlayed
|
||||
}
|
||||
_ = database.SaveMatch(match)
|
||||
_ = database.UpdateMatch(match)
|
||||
}
|
||||
|
||||
@@ -15,12 +15,12 @@ type AllianceTeam struct {
|
||||
}
|
||||
|
||||
func (database *Database) CreateAllianceTeam(allianceTeam *AllianceTeam) error {
|
||||
return database.tables[AllianceTeam{}].create(allianceTeam)
|
||||
return database.allianceTeamTable.create(allianceTeam)
|
||||
}
|
||||
|
||||
func (database *Database) GetTeamsByAlliance(allianceId int) ([]AllianceTeam, error) {
|
||||
var allianceTeams []AllianceTeam
|
||||
if err := database.tables[AllianceTeam{}].getAll(&allianceTeams); err != nil {
|
||||
if err := database.allianceTeamTable.getAll(&allianceTeams); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sort.Slice(allianceTeams, func(i, j int) bool {
|
||||
@@ -37,20 +37,20 @@ func (database *Database) GetTeamsByAlliance(allianceId int) ([]AllianceTeam, er
|
||||
}
|
||||
|
||||
func (database *Database) UpdateAllianceTeam(allianceTeam *AllianceTeam) error {
|
||||
return database.tables[AllianceTeam{}].update(allianceTeam)
|
||||
return database.allianceTeamTable.update(allianceTeam)
|
||||
}
|
||||
|
||||
func (database *Database) DeleteAllianceTeam(id int64) error {
|
||||
return database.tables[AllianceTeam{}].delete(id)
|
||||
return database.allianceTeamTable.delete(id)
|
||||
}
|
||||
|
||||
func (database *Database) TruncateAllianceTeams() error {
|
||||
return database.tables[AllianceTeam{}].truncate()
|
||||
return database.allianceTeamTable.truncate()
|
||||
}
|
||||
|
||||
func (database *Database) GetAllAlliances() ([][]AllianceTeam, error) {
|
||||
var allianceTeams []AllianceTeam
|
||||
if err := database.tables[AllianceTeam{}].getAll(&allianceTeams); err != nil {
|
||||
if err := database.allianceTeamTable.getAll(&allianceTeams); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sort.Slice(allianceTeams, func(i, j int) bool {
|
||||
|
||||
@@ -24,30 +24,30 @@ const (
|
||||
)
|
||||
|
||||
func (database *Database) CreateAward(award *Award) error {
|
||||
return database.tables[Award{}].create(award)
|
||||
return database.awardTable.create(award)
|
||||
}
|
||||
|
||||
func (database *Database) GetAwardById(id int64) (*Award, error) {
|
||||
var award *Award
|
||||
err := database.tables[Award{}].getById(id, &award)
|
||||
err := database.awardTable.getById(id, &award)
|
||||
return award, err
|
||||
}
|
||||
|
||||
func (database *Database) UpdateAward(award *Award) error {
|
||||
return database.tables[Award{}].update(award)
|
||||
return database.awardTable.update(award)
|
||||
}
|
||||
|
||||
func (database *Database) DeleteAward(id int64) error {
|
||||
return database.tables[Award{}].delete(id)
|
||||
return database.awardTable.delete(id)
|
||||
}
|
||||
|
||||
func (database *Database) TruncateAwards() error {
|
||||
return database.tables[Award{}].truncate()
|
||||
return database.awardTable.truncate()
|
||||
}
|
||||
|
||||
func (database *Database) GetAllAwards() ([]Award, error) {
|
||||
var awards []Award
|
||||
if err := database.tables[Award{}].getAll(&awards); err != nil {
|
||||
if err := database.awardTable.getAll(&awards); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sort.Slice(awards, func(i, j int) bool {
|
||||
|
||||
@@ -24,25 +24,22 @@ const backupsDir = "db/backups"
|
||||
const migrationsDir = "db/migrations"
|
||||
|
||||
var BaseDir = "." // Mutable for testing
|
||||
var recordTypes = []interface{}{
|
||||
AllianceTeam{},
|
||||
Award{},
|
||||
LowerThird{},
|
||||
}
|
||||
|
||||
type Database struct {
|
||||
Path string
|
||||
db *sql.DB
|
||||
eventSettingsMap *modl.DbMap
|
||||
matchMap *modl.DbMap
|
||||
matchResultMap *modl.DbMap
|
||||
rankingMap *modl.DbMap
|
||||
teamMap *modl.DbMap
|
||||
sponsorSlideMap *modl.DbMap
|
||||
scheduleBlockMap *modl.DbMap
|
||||
userSessionMap *modl.DbMap
|
||||
bolt *bbolt.DB
|
||||
tables map[interface{}]*table
|
||||
Path string
|
||||
db *sql.DB
|
||||
rankingMap *modl.DbMap
|
||||
teamMap *modl.DbMap
|
||||
sponsorSlideMap *modl.DbMap
|
||||
scheduleBlockMap *modl.DbMap
|
||||
userSessionMap *modl.DbMap
|
||||
bolt *bbolt.DB
|
||||
allianceTeamTable *table
|
||||
awardTable *table
|
||||
eventSettingsTable *table
|
||||
lowerThirdTable *table
|
||||
matchTable *table
|
||||
matchResultTable *table
|
||||
}
|
||||
|
||||
// Opens the SQLite database at the given path, creating it if it doesn't exist, and runs any pending
|
||||
@@ -75,13 +72,23 @@ func OpenDatabase(filename string) (*Database, error) {
|
||||
}
|
||||
|
||||
// Register tables.
|
||||
database.tables = make(map[interface{}]*table)
|
||||
for _, recordType := range recordTypes {
|
||||
table, err := database.newTable(recordType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
database.tables[recordType] = table
|
||||
if database.allianceTeamTable, err = database.newTable(AllianceTeam{}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if database.awardTable, err = database.newTable(Award{}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if database.eventSettingsTable, err = database.newTable(EventSettings{}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if database.lowerThirdTable, err = database.newTable(LowerThird{}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if database.matchTable, err = database.newTable(Match{}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if database.matchResultTable, err = database.newTable(MatchResult{}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &database, nil
|
||||
@@ -121,15 +128,6 @@ func (database *Database) Backup(eventName, reason string) error {
|
||||
func (database *Database) mapTables() {
|
||||
dialect := new(modl.SqliteDialect)
|
||||
|
||||
database.eventSettingsMap = modl.NewDbMap(database.db, dialect)
|
||||
database.eventSettingsMap.AddTableWithName(EventSettings{}, "event_settings").SetKeys(false, "Id")
|
||||
|
||||
database.matchMap = modl.NewDbMap(database.db, dialect)
|
||||
database.matchMap.AddTableWithName(Match{}, "matches").SetKeys(true, "Id")
|
||||
|
||||
database.matchResultMap = modl.NewDbMap(database.db, dialect)
|
||||
database.matchResultMap.AddTableWithName(MatchResultDb{}, "match_results").SetKeys(true, "Id")
|
||||
|
||||
database.rankingMap = modl.NewDbMap(database.db, dialect)
|
||||
database.rankingMap.AddTableWithName(RankingDb{}, "rankings").SetKeys(false, "TeamId")
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ package model
|
||||
import "github.com/Team254/cheesy-arena-lite/game"
|
||||
|
||||
type EventSettings struct {
|
||||
Id int
|
||||
Id int64 `db:"id"`
|
||||
Name string
|
||||
NumElimAlliances int
|
||||
SelectionRound2Order string
|
||||
@@ -40,38 +40,39 @@ type EventSettings struct {
|
||||
WarningRemainingDurationSec int
|
||||
}
|
||||
|
||||
const eventSettingsId = 0
|
||||
|
||||
func (database *Database) GetEventSettings() (*EventSettings, error) {
|
||||
eventSettings := new(EventSettings)
|
||||
err := database.eventSettingsMap.Get(eventSettings, eventSettingsId)
|
||||
if err != nil {
|
||||
// Database record doesn't exist yet; create it now.
|
||||
eventSettings.Name = "Untitled Event"
|
||||
eventSettings.NumElimAlliances = 8
|
||||
eventSettings.SelectionRound2Order = "L"
|
||||
eventSettings.SelectionRound3Order = ""
|
||||
eventSettings.TBADownloadEnabled = true
|
||||
eventSettings.ApTeamChannel = 157
|
||||
eventSettings.ApAdminChannel = 0
|
||||
eventSettings.ApAdminWpaKey = "1234Five"
|
||||
eventSettings.Ap2TeamChannel = 0
|
||||
eventSettings.WarmupDurationSec = game.MatchTiming.WarmupDurationSec
|
||||
eventSettings.AutoDurationSec = game.MatchTiming.AutoDurationSec
|
||||
eventSettings.PauseDurationSec = game.MatchTiming.PauseDurationSec
|
||||
eventSettings.TeleopDurationSec = game.MatchTiming.TeleopDurationSec
|
||||
eventSettings.WarningRemainingDurationSec = game.MatchTiming.WarningRemainingDurationSec
|
||||
|
||||
err = database.eventSettingsMap.Insert(eventSettings)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var allEventSettings []EventSettings
|
||||
if err := database.eventSettingsTable.getAll(&allEventSettings); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return eventSettings, nil
|
||||
if len(allEventSettings) == 1 {
|
||||
return &allEventSettings[0], nil
|
||||
}
|
||||
|
||||
// Database record doesn't exist yet; create it now.
|
||||
eventSettings := EventSettings{
|
||||
Name: "Untitled Event",
|
||||
NumElimAlliances: 8,
|
||||
SelectionRound2Order: "L",
|
||||
SelectionRound3Order: "",
|
||||
TBADownloadEnabled: true,
|
||||
ApTeamChannel: 157,
|
||||
ApAdminChannel: 0,
|
||||
ApAdminWpaKey: "1234Five",
|
||||
Ap2TeamChannel: 0,
|
||||
WarmupDurationSec: game.MatchTiming.WarmupDurationSec,
|
||||
AutoDurationSec: game.MatchTiming.AutoDurationSec,
|
||||
PauseDurationSec: game.MatchTiming.PauseDurationSec,
|
||||
TeleopDurationSec: game.MatchTiming.TeleopDurationSec,
|
||||
WarningRemainingDurationSec: game.MatchTiming.WarningRemainingDurationSec,
|
||||
}
|
||||
|
||||
if err := database.eventSettingsTable.create(&eventSettings); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &eventSettings, nil
|
||||
}
|
||||
|
||||
func (database *Database) SaveEventSettings(eventSettings *EventSettings) error {
|
||||
eventSettings.Id = eventSettingsId
|
||||
_, err := database.eventSettingsMap.Update(eventSettings)
|
||||
return err
|
||||
func (database *Database) UpdateEventSettings(eventSettings *EventSettings) error {
|
||||
return database.eventSettingsTable.update(eventSettings)
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ func TestEventSettingsReadWrite(t *testing.T) {
|
||||
|
||||
eventSettings, err := db.GetEventSettings()
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, EventSettings{Id: 0, Name: "Untitled Event", NumElimAlliances: 8, SelectionRound2Order: "L",
|
||||
assert.Equal(t, EventSettings{Id: 1, Name: "Untitled Event", NumElimAlliances: 8, SelectionRound2Order: "L",
|
||||
SelectionRound3Order: "", TBADownloadEnabled: true, ApTeamChannel: 157, ApAdminChannel: 0,
|
||||
ApAdminWpaKey: "1234Five", WarmupDurationSec: 0, AutoDurationSec: 15, PauseDurationSec: 2,
|
||||
TeleopDurationSec: 135, WarningRemainingDurationSec: 30}, *eventSettings)
|
||||
@@ -23,7 +23,7 @@ func TestEventSettingsReadWrite(t *testing.T) {
|
||||
eventSettings.NumElimAlliances = 6
|
||||
eventSettings.SelectionRound2Order = "F"
|
||||
eventSettings.SelectionRound3Order = "L"
|
||||
err = db.SaveEventSettings(eventSettings)
|
||||
err = db.UpdateEventSettings(eventSettings)
|
||||
assert.Nil(t, err)
|
||||
eventSettings2, err := db.GetEventSettings()
|
||||
assert.Nil(t, err)
|
||||
|
||||
@@ -18,30 +18,30 @@ type LowerThird struct {
|
||||
}
|
||||
|
||||
func (database *Database) CreateLowerThird(lowerThird *LowerThird) error {
|
||||
return database.tables[LowerThird{}].create(lowerThird)
|
||||
return database.lowerThirdTable.create(lowerThird)
|
||||
}
|
||||
|
||||
func (database *Database) GetLowerThirdById(id int64) (*LowerThird, error) {
|
||||
var lowerThird *LowerThird
|
||||
err := database.tables[LowerThird{}].getById(id, &lowerThird)
|
||||
err := database.lowerThirdTable.getById(id, &lowerThird)
|
||||
return lowerThird, err
|
||||
}
|
||||
|
||||
func (database *Database) UpdateLowerThird(lowerThird *LowerThird) error {
|
||||
return database.tables[LowerThird{}].update(lowerThird)
|
||||
return database.lowerThirdTable.update(lowerThird)
|
||||
}
|
||||
|
||||
func (database *Database) DeleteLowerThird(id int64) error {
|
||||
return database.tables[LowerThird{}].delete(id)
|
||||
return database.lowerThirdTable.delete(id)
|
||||
}
|
||||
|
||||
func (database *Database) TruncateLowerThirds() error {
|
||||
return database.tables[LowerThird{}].truncate()
|
||||
return database.lowerThirdTable.truncate()
|
||||
}
|
||||
|
||||
func (database *Database) GetAllLowerThirds() ([]LowerThird, error) {
|
||||
var lowerThirds []LowerThird
|
||||
if err := database.tables[LowerThird{}].getAll(&lowerThirds); err != nil {
|
||||
if err := database.lowerThirdTable.getAll(&lowerThirds); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sort.Slice(lowerThirds, func(i, j int) bool {
|
||||
|
||||
@@ -7,12 +7,13 @@ package model
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Match struct {
|
||||
Id int
|
||||
Id int64 `db:"id"`
|
||||
Type string
|
||||
DisplayName string
|
||||
Time time.Time
|
||||
@@ -50,58 +51,82 @@ const (
|
||||
var ElimRoundNames = map[int]string{1: "F", 2: "SF", 4: "QF", 8: "EF"}
|
||||
|
||||
func (database *Database) CreateMatch(match *Match) error {
|
||||
return database.matchMap.Insert(match)
|
||||
return database.matchTable.create(match)
|
||||
}
|
||||
|
||||
func (database *Database) GetMatchById(id int) (*Match, error) {
|
||||
match := new(Match)
|
||||
err := database.matchMap.Get(match, id)
|
||||
if err != nil && err.Error() == "sql: no rows in result set" {
|
||||
match = nil
|
||||
err = nil
|
||||
}
|
||||
func (database *Database) GetMatchById(id int64) (*Match, error) {
|
||||
var match *Match
|
||||
err := database.matchTable.getById(id, &match)
|
||||
return match, err
|
||||
}
|
||||
|
||||
func (database *Database) SaveMatch(match *Match) error {
|
||||
_, err := database.matchMap.Update(match)
|
||||
return err
|
||||
func (database *Database) UpdateMatch(match *Match) error {
|
||||
return database.matchTable.update(match)
|
||||
}
|
||||
|
||||
func (database *Database) DeleteMatch(match *Match) error {
|
||||
_, err := database.matchMap.Delete(match)
|
||||
return err
|
||||
func (database *Database) DeleteMatch(id int64) error {
|
||||
return database.matchTable.delete(id)
|
||||
}
|
||||
|
||||
func (database *Database) TruncateMatches() error {
|
||||
return database.matchMap.TruncateTables()
|
||||
return database.matchTable.truncate()
|
||||
}
|
||||
|
||||
func (database *Database) GetMatchByName(matchType string, displayName string) (*Match, error) {
|
||||
var matches []Match
|
||||
err := database.matchMap.Select(&matches, "SELECT * FROM matches WHERE type = ? AND displayname = ?",
|
||||
matchType, displayName)
|
||||
if err != nil {
|
||||
if err := database.matchTable.getAll(&matches); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(matches) == 0 {
|
||||
return nil, nil
|
||||
|
||||
for _, match := range matches {
|
||||
if match.Type == matchType && match.DisplayName == displayName {
|
||||
return &match, nil
|
||||
}
|
||||
}
|
||||
return &matches[0], err
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (database *Database) GetMatchesByElimRoundGroup(round int, group int) ([]Match, error) {
|
||||
var matches []Match
|
||||
err := database.matchMap.Select(&matches, "SELECT * FROM matches WHERE type = 'elimination' AND "+
|
||||
"elimround = ? AND elimgroup = ? ORDER BY eliminstance", round, group)
|
||||
return matches, err
|
||||
matches, err := database.GetMatchesByType("elimination")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var matchingMatches []Match
|
||||
for _, match := range matches {
|
||||
if match.ElimRound == round && match.ElimGroup == group {
|
||||
matchingMatches = append(matchingMatches, match)
|
||||
}
|
||||
}
|
||||
return matchingMatches, nil
|
||||
}
|
||||
|
||||
func (database *Database) GetMatchesByType(matchType string) ([]Match, error) {
|
||||
var matches []Match
|
||||
err := database.matchMap.Select(&matches,
|
||||
"SELECT * FROM matches WHERE type = ? ORDER BY elimround desc, eliminstance, elimgroup, id", matchType)
|
||||
return matches, err
|
||||
if err := database.matchTable.getAll(&matches); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var matchingMatches []Match
|
||||
for _, match := range matches {
|
||||
if match.Type == matchType {
|
||||
matchingMatches = append(matchingMatches, match)
|
||||
}
|
||||
}
|
||||
|
||||
sort.Slice(matchingMatches, func(i, j int) bool {
|
||||
if matchingMatches[i].ElimRound == matchingMatches[j].ElimRound {
|
||||
if matchingMatches[i].ElimInstance == matchingMatches[j].ElimInstance {
|
||||
if matchingMatches[i].ElimGroup == matchingMatches[j].ElimGroup {
|
||||
return matchingMatches[i].Id < matchingMatches[j].Id
|
||||
}
|
||||
return matchingMatches[i].ElimGroup < matchingMatches[j].ElimGroup
|
||||
}
|
||||
return matchingMatches[i].ElimInstance < matchingMatches[j].ElimInstance
|
||||
}
|
||||
return matchingMatches[i].ElimRound > matchingMatches[j].ElimRound
|
||||
})
|
||||
return matchingMatches, nil
|
||||
}
|
||||
|
||||
func (match *Match) IsComplete() bool {
|
||||
|
||||
@@ -6,28 +6,18 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/Team254/cheesy-arena-lite/game"
|
||||
)
|
||||
|
||||
type MatchResult struct {
|
||||
Id int
|
||||
MatchId int
|
||||
Id int64 `db:"id"`
|
||||
MatchId int64
|
||||
PlayNumber int
|
||||
MatchType string
|
||||
RedScore *game.Score
|
||||
BlueScore *game.Score
|
||||
}
|
||||
|
||||
type MatchResultDb struct {
|
||||
Id int
|
||||
MatchId int
|
||||
PlayNumber int
|
||||
MatchType string
|
||||
RedScoreJson string
|
||||
BlueScoreJson string
|
||||
}
|
||||
|
||||
// Returns a new match result object with empty slices instead of nil.
|
||||
func NewMatchResult() *MatchResult {
|
||||
matchResult := new(MatchResult)
|
||||
@@ -37,55 +27,35 @@ func NewMatchResult() *MatchResult {
|
||||
}
|
||||
|
||||
func (database *Database) CreateMatchResult(matchResult *MatchResult) error {
|
||||
matchResultDb, err := matchResult.Serialize()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = database.matchResultMap.Insert(matchResultDb)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
matchResult.Id = matchResultDb.Id
|
||||
return nil
|
||||
return database.matchResultTable.create(matchResult)
|
||||
}
|
||||
|
||||
func (database *Database) GetMatchResultForMatch(matchId int) (*MatchResult, error) {
|
||||
var matchResults []MatchResultDb
|
||||
query := "SELECT * FROM match_results WHERE matchid = ? ORDER BY playnumber DESC LIMIT 1"
|
||||
err := database.matchResultMap.Select(&matchResults, query, matchId)
|
||||
if err != nil {
|
||||
func (database *Database) GetMatchResultForMatch(matchId int64) (*MatchResult, error) {
|
||||
var matchResults []MatchResult
|
||||
if err := database.matchResultTable.getAll(&matchResults); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(matchResults) == 0 {
|
||||
return nil, nil
|
||||
|
||||
var mostRecentMatchResult *MatchResult
|
||||
for i, matchResult := range matchResults {
|
||||
if matchResult.MatchId == matchId &&
|
||||
(mostRecentMatchResult == nil || matchResult.PlayNumber > mostRecentMatchResult.PlayNumber) {
|
||||
mostRecentMatchResult = &matchResults[i]
|
||||
}
|
||||
}
|
||||
matchResult, err := matchResults[0].Deserialize()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return matchResult, err
|
||||
return mostRecentMatchResult, nil
|
||||
}
|
||||
|
||||
func (database *Database) SaveMatchResult(matchResult *MatchResult) error {
|
||||
matchResultDb, err := matchResult.Serialize()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = database.matchResultMap.Update(matchResultDb)
|
||||
return err
|
||||
func (database *Database) UpdateMatchResult(matchResult *MatchResult) error {
|
||||
return database.matchResultTable.update(matchResult)
|
||||
}
|
||||
|
||||
func (database *Database) DeleteMatchResult(matchResult *MatchResult) error {
|
||||
matchResultDb, err := matchResult.Serialize()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = database.matchResultMap.Delete(matchResultDb)
|
||||
return err
|
||||
func (database *Database) DeleteMatchResult(id int64) error {
|
||||
return database.matchResultTable.delete(id)
|
||||
}
|
||||
|
||||
func (database *Database) TruncateMatchResults() error {
|
||||
return database.matchResultMap.TruncateTables()
|
||||
return database.matchResultTable.truncate()
|
||||
}
|
||||
|
||||
// Calculates and returns the summary fields used for ranking and display for the red alliance.
|
||||
@@ -97,29 +67,3 @@ func (matchResult *MatchResult) RedScoreSummary() *game.ScoreSummary {
|
||||
func (matchResult *MatchResult) BlueScoreSummary() *game.ScoreSummary {
|
||||
return matchResult.BlueScore.Summarize()
|
||||
}
|
||||
|
||||
// Converts the nested struct MatchResult to the DB version that has JSON fields.
|
||||
func (matchResult *MatchResult) Serialize() (*MatchResultDb, error) {
|
||||
matchResultDb := MatchResultDb{Id: matchResult.Id, MatchId: matchResult.MatchId,
|
||||
PlayNumber: matchResult.PlayNumber, MatchType: matchResult.MatchType}
|
||||
if err := serializeHelper(&matchResultDb.RedScoreJson, matchResult.RedScore); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := serializeHelper(&matchResultDb.BlueScoreJson, matchResult.BlueScore); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &matchResultDb, nil
|
||||
}
|
||||
|
||||
// Converts the DB MatchResult with JSON fields to the nested struct version.
|
||||
func (matchResultDb *MatchResultDb) Deserialize() (*MatchResult, error) {
|
||||
matchResult := MatchResult{Id: matchResultDb.Id, MatchId: matchResultDb.MatchId,
|
||||
PlayNumber: matchResultDb.PlayNumber, MatchType: matchResultDb.MatchType}
|
||||
if err := json.Unmarshal([]byte(matchResultDb.RedScoreJson), &matchResult.RedScore); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := json.Unmarshal([]byte(matchResultDb.BlueScoreJson), &matchResult.BlueScore); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &matchResult, nil
|
||||
}
|
||||
|
||||
@@ -27,12 +27,13 @@ func TestMatchResultCrud(t *testing.T) {
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, matchResult, matchResult2)
|
||||
|
||||
db.SaveMatchResult(matchResult)
|
||||
matchResult.BlueScore.EndgamePoints = 1234
|
||||
assert.Nil(t, db.UpdateMatchResult(matchResult))
|
||||
matchResult2, err = db.GetMatchResultForMatch(254)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, matchResult, matchResult2)
|
||||
|
||||
db.DeleteMatchResult(matchResult)
|
||||
assert.Nil(t, db.DeleteMatchResult(matchResult.Id))
|
||||
matchResult2, err = db.GetMatchResultForMatch(254)
|
||||
assert.Nil(t, err)
|
||||
assert.Nil(t, matchResult2)
|
||||
@@ -43,8 +44,8 @@ func TestTruncateMatchResults(t *testing.T) {
|
||||
defer db.Close()
|
||||
|
||||
matchResult := BuildTestMatchResult(254, 1)
|
||||
db.CreateMatchResult(matchResult)
|
||||
db.TruncateMatchResults()
|
||||
assert.Nil(t, db.CreateMatchResult(matchResult))
|
||||
assert.Nil(t, db.TruncateMatchResults())
|
||||
matchResult2, err := db.GetMatchResultForMatch(254)
|
||||
assert.Nil(t, err)
|
||||
assert.Nil(t, matchResult2)
|
||||
@@ -55,11 +56,11 @@ func TestGetMatchResultForMatch(t *testing.T) {
|
||||
defer db.Close()
|
||||
|
||||
matchResult := BuildTestMatchResult(254, 2)
|
||||
db.CreateMatchResult(matchResult)
|
||||
assert.Nil(t, db.CreateMatchResult(matchResult))
|
||||
matchResult2 := BuildTestMatchResult(254, 5)
|
||||
db.CreateMatchResult(matchResult2)
|
||||
assert.Nil(t, db.CreateMatchResult(matchResult2))
|
||||
matchResult3 := BuildTestMatchResult(254, 4)
|
||||
db.CreateMatchResult(matchResult3)
|
||||
assert.Nil(t, db.CreateMatchResult(matchResult3))
|
||||
|
||||
// Should return the match result with the highest play number (i.e. the most recent).
|
||||
matchResult4, err := db.GetMatchResultForMatch(254)
|
||||
|
||||
@@ -33,12 +33,12 @@ func TestMatchCrud(t *testing.T) {
|
||||
assert.Equal(t, match, *match3)
|
||||
|
||||
match.Status = RedWonMatch
|
||||
db.SaveMatch(&match)
|
||||
db.UpdateMatch(&match)
|
||||
match2, err = db.GetMatchById(1)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, match.Status, match2.Status)
|
||||
|
||||
db.DeleteMatch(&match)
|
||||
db.DeleteMatch(match.Id)
|
||||
match2, err = db.GetMatchById(1)
|
||||
assert.Nil(t, err)
|
||||
assert.Nil(t, match2)
|
||||
|
||||
@@ -24,7 +24,7 @@ func SetupTestDb(t *testing.T, uniqueName string) *Database {
|
||||
return database
|
||||
}
|
||||
|
||||
func BuildTestMatchResult(matchId int, playNumber int) *MatchResult {
|
||||
func BuildTestMatchResult(matchId int64, playNumber int) *MatchResult {
|
||||
matchResult := &MatchResult{MatchId: matchId, PlayNumber: playNumber, MatchType: "qualification"}
|
||||
matchResult.RedScore = game.TestScore1()
|
||||
matchResult.BlueScore = game.TestScore2()
|
||||
|
||||
@@ -5,18 +5,19 @@
|
||||
|
||||
var scoreTemplate = Handlebars.compile($("#scoreTemplate").html());
|
||||
var allianceResults = {};
|
||||
var matchResult;
|
||||
|
||||
// Hijack the form submission to inject the data in JSON form so that it's easier for the server to parse.
|
||||
$("form").submit(function() {
|
||||
updateResults("red");
|
||||
updateResults("blue");
|
||||
|
||||
var redScoreJson = JSON.stringify(allianceResults["red"].score);
|
||||
var blueScoreJson = JSON.stringify(allianceResults["blue"].score);
|
||||
matchResult.RedScore = allianceResults["red"].score;
|
||||
matchResult.BlueScore = allianceResults["blue"].score;
|
||||
var matchResultJson = JSON.stringify(matchResult);
|
||||
|
||||
// Inject the JSON data into the form as hidden inputs.
|
||||
$("<input />").attr("type", "hidden").attr("name", "redScoreJson").attr("value", redScoreJson).appendTo("form");
|
||||
$("<input />").attr("type", "hidden").attr("name", "blueScoreJson").attr("value", blueScoreJson).appendTo("form");
|
||||
$("<input />").attr("type", "hidden").attr("name", "matchResultJson").attr("value", matchResultJson).appendTo("form");
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
@@ -44,11 +44,11 @@
|
||||
<script src="/static/js/match_review.js"></script>
|
||||
<script>
|
||||
var matchId = {{.Match.Id}};
|
||||
var allianceResults = {};
|
||||
matchResult = jQuery.parseJSON('{{.MatchResultJson}}');
|
||||
allianceResults["red"] = {alliance: "red", team1: {{.Match.Red1}}, team2: {{.Match.Red2}},
|
||||
team3: {{.Match.Red3}}, score: jQuery.parseJSON('{{.MatchResultJson.RedScoreJson}}')};
|
||||
team3: {{.Match.Red3}}, score: matchResult.RedScore};
|
||||
allianceResults["blue"] = {alliance: "blue", team1: {{.Match.Blue1}}, team2: {{.Match.Blue2}},
|
||||
team3: {{.Match.Blue3}}, score: jQuery.parseJSON('{{.MatchResultJson.BlueScoreJson}}')};
|
||||
team3: {{.Match.Blue3}}, score: matchResult.BlueScore};
|
||||
renderResults("red");
|
||||
renderResults("blue");
|
||||
</script>
|
||||
|
||||
@@ -37,7 +37,9 @@ func UpdateEliminationSchedule(database *model.Database, startTime time.Time) (b
|
||||
continue
|
||||
}
|
||||
match.Time = startTime.Add(time.Duration(matchIndex*ElimMatchSpacingSec) * time.Second)
|
||||
database.SaveMatch(&match)
|
||||
if err = database.UpdateMatch(&match); err != nil {
|
||||
return false, err
|
||||
}
|
||||
matchIndex++
|
||||
}
|
||||
|
||||
@@ -145,12 +147,12 @@ func buildEliminationMatchSet(database *model.Database, round int, group int,
|
||||
|
||||
// Check if the match set exists already and if it has been won.
|
||||
var redWins, blueWins, numIncomplete int
|
||||
var ties []*model.Match
|
||||
var ties []model.Match
|
||||
matches, err := database.GetMatchesByElimRoundGroup(round, group)
|
||||
if err != nil {
|
||||
return []model.AllianceTeam{}, err
|
||||
}
|
||||
var unplayedMatches []*model.Match
|
||||
var unplayedMatches []model.Match
|
||||
for _, match := range matches {
|
||||
if !match.IsComplete() {
|
||||
// Update the teams in the match if they are not yet set or are incorrect.
|
||||
@@ -158,16 +160,20 @@ func buildEliminationMatchSet(database *model.Database, round int, group int,
|
||||
match.Red3 == redAlliance[2].TeamId) {
|
||||
positionRedTeams(&match, redAlliance)
|
||||
match.ElimRedAlliance = redAlliance[0].AllianceId
|
||||
database.SaveMatch(&match)
|
||||
if err = database.UpdateMatch(&match); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if len(blueAlliance) != 0 && !(match.Blue1 == blueAlliance[0].TeamId &&
|
||||
match.Blue2 == blueAlliance[1].TeamId && match.Blue3 == blueAlliance[2].TeamId) {
|
||||
positionBlueTeams(&match, blueAlliance)
|
||||
match.ElimBlueAlliance = blueAlliance[0].AllianceId
|
||||
database.SaveMatch(&match)
|
||||
if err = database.UpdateMatch(&match); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
unplayedMatches = append(unplayedMatches, &match)
|
||||
unplayedMatches = append(unplayedMatches, match)
|
||||
numIncomplete += 1
|
||||
continue
|
||||
}
|
||||
@@ -189,7 +195,7 @@ func buildEliminationMatchSet(database *model.Database, round int, group int,
|
||||
case model.BlueWonMatch:
|
||||
blueWins += 1
|
||||
case model.TieMatch:
|
||||
ties = append(ties, &match)
|
||||
ties = append(ties, match)
|
||||
default:
|
||||
return []model.AllianceTeam{}, fmt.Errorf("Completed match %d has invalid winner '%s'", match.Id,
|
||||
match.Status)
|
||||
@@ -199,7 +205,7 @@ func buildEliminationMatchSet(database *model.Database, round int, group int,
|
||||
// Delete any superfluous matches if the round is won.
|
||||
if redWins == 2 || blueWins == 2 {
|
||||
for _, match := range unplayedMatches {
|
||||
err = database.DeleteMatch(match)
|
||||
err = database.DeleteMatch(match.Id)
|
||||
if err != nil {
|
||||
return []model.AllianceTeam{}, err
|
||||
}
|
||||
|
||||
@@ -747,8 +747,8 @@ func TestEliminationScheduleTeamPositions(t *testing.T) {
|
||||
// Shuffle the team positions and check that the subsequent matches in the same round have the same ones.
|
||||
match1.Red1, match1.Red2 = match1.Red2, match1.Red1
|
||||
match2.Blue1, match2.Blue3 = match2.Blue3, match2.Blue1
|
||||
database.SaveMatch(&match1)
|
||||
database.SaveMatch(&match2)
|
||||
database.UpdateMatch(&match1)
|
||||
database.UpdateMatch(&match2)
|
||||
scoreMatch(database, "SF1-1", model.RedWonMatch)
|
||||
scoreMatch(database, "SF2-1", model.BlueWonMatch)
|
||||
UpdateEliminationSchedule(database, time.Unix(1000, 0))
|
||||
@@ -792,5 +792,5 @@ func assertMatch(t *testing.T, match model.Match, displayName string, redAllianc
|
||||
func scoreMatch(database *model.Database, displayName string, winner model.MatchStatus) {
|
||||
match, _ := database.GetMatchByName("elimination", displayName)
|
||||
match.Status = winner
|
||||
database.SaveMatch(match)
|
||||
database.UpdateMatch(match)
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ import (
|
||||
)
|
||||
|
||||
type MatchPlayListItem struct {
|
||||
Id int
|
||||
Id int64
|
||||
DisplayName string
|
||||
Time string
|
||||
Status model.MatchStatus
|
||||
@@ -98,7 +98,7 @@ func (web *Web) matchPlayLoadHandler(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
vars := mux.Vars(r)
|
||||
matchId, _ := strconv.Atoi(vars["matchId"])
|
||||
matchId, _ := strconv.ParseInt(vars["matchId"], 10, 64)
|
||||
var match *model.Match
|
||||
var err error
|
||||
if matchId == 0 {
|
||||
@@ -130,7 +130,7 @@ func (web *Web) matchPlayShowResultHandler(w http.ResponseWriter, r *http.Reques
|
||||
}
|
||||
|
||||
vars := mux.Vars(r)
|
||||
matchId, _ := strconv.Atoi(vars["matchId"])
|
||||
matchId, _ := strconv.ParseInt(vars["matchId"], 10, 64)
|
||||
match, err := web.arena.Database.GetMatchById(matchId)
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
@@ -358,7 +358,7 @@ func (web *Web) commitMatchScore(match *model.Match, matchResult *model.MatchRes
|
||||
}
|
||||
} else {
|
||||
// We are updating a match result record that already exists.
|
||||
err := web.arena.Database.SaveMatchResult(matchResult)
|
||||
err := web.arena.Database.UpdateMatchResult(matchResult)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -375,7 +375,7 @@ func (web *Web) commitMatchScore(match *model.Match, matchResult *model.MatchRes
|
||||
} else {
|
||||
match.Status = model.TieMatch
|
||||
}
|
||||
err := web.arena.Database.SaveMatch(match)
|
||||
err := web.arena.Database.UpdateMatch(match)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -426,13 +426,11 @@ func (web *Web) commitMatchScore(match *model.Match, matchResult *model.MatchRes
|
||||
if web.arena.EventSettings.TbaPublishingEnabled && match.Type != "practice" {
|
||||
// Publish asynchronously to The Blue Alliance.
|
||||
go func() {
|
||||
err = web.arena.TbaClient.PublishMatches(web.arena.Database)
|
||||
if err != nil {
|
||||
if err = web.arena.TbaClient.PublishMatches(web.arena.Database); err != nil {
|
||||
log.Printf("Failed to publish matches: %s", err.Error())
|
||||
}
|
||||
if match.ShouldUpdateRankings() {
|
||||
err = web.arena.TbaClient.PublishRankings(web.arena.Database)
|
||||
if err != nil {
|
||||
if err = web.arena.TbaClient.PublishRankings(web.arena.Database); err != nil {
|
||||
log.Printf("Failed to publish rankings: %s", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,9 +127,8 @@ func TestCommitMatch(t *testing.T) {
|
||||
assert.Nil(t, matchResult)
|
||||
|
||||
// Committing the same match more than once should create a second match result record.
|
||||
match.Id = 1
|
||||
match.Type = "qualification"
|
||||
web.arena.Database.CreateMatch(match)
|
||||
assert.Nil(t, web.arena.Database.CreateMatch(match))
|
||||
matchResult = model.NewMatchResult()
|
||||
matchResult.MatchId = match.Id
|
||||
matchResult.BlueScore = &game.Score{AutoPoints: 10}
|
||||
@@ -163,7 +162,7 @@ func TestCommitMatch(t *testing.T) {
|
||||
log.SetOutput(&writer)
|
||||
err = web.commitMatchScore(match, matchResult, true)
|
||||
assert.Nil(t, err)
|
||||
time.Sleep(time.Millisecond * 10) // Allow some time for the asynchronous publishing to happen.
|
||||
time.Sleep(time.Millisecond * 100) // Allow some time for the asynchronous publishing to happen.
|
||||
assert.Contains(t, writer.String(), "Failed to publish matches")
|
||||
assert.Contains(t, writer.String(), "Failed to publish rankings")
|
||||
}
|
||||
@@ -183,7 +182,7 @@ func TestCommitEliminationTie(t *testing.T) {
|
||||
match, _ = web.arena.Database.GetMatchById(1)
|
||||
assert.Equal(t, model.TieMatch, match.Status)
|
||||
match.Type = "elimination"
|
||||
web.arena.Database.SaveMatch(match)
|
||||
web.arena.Database.UpdateMatch(match)
|
||||
web.commitMatchScore(match, matchResult, true)
|
||||
match, _ = web.arena.Database.GetMatchById(1)
|
||||
assert.Equal(t, model.TieMatch, match.Status) // No elimination tiebreakers.
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
package web
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/Team254/cheesy-arena-lite/model"
|
||||
"github.com/gorilla/mux"
|
||||
@@ -14,7 +15,7 @@ import (
|
||||
)
|
||||
|
||||
type MatchReviewListItem struct {
|
||||
Id int
|
||||
Id int64
|
||||
DisplayName string
|
||||
Time string
|
||||
RedTeams []int
|
||||
@@ -82,7 +83,7 @@ func (web *Web) matchReviewEditGetHandler(w http.ResponseWriter, r *http.Request
|
||||
handleWebErr(w, err)
|
||||
return
|
||||
}
|
||||
matchResultJson, err := matchResult.Serialize()
|
||||
matchResultJson, err := json.Marshal(matchResult)
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
return
|
||||
@@ -90,8 +91,8 @@ func (web *Web) matchReviewEditGetHandler(w http.ResponseWriter, r *http.Request
|
||||
data := struct {
|
||||
*model.EventSettings
|
||||
Match *model.Match
|
||||
MatchResultJson *model.MatchResultDb
|
||||
}{web.arena.EventSettings, match, matchResultJson}
|
||||
MatchResultJson string
|
||||
}{web.arena.EventSettings, match, string(matchResultJson)}
|
||||
err = template.ExecuteTemplate(w, "base", data)
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
@@ -105,22 +106,21 @@ func (web *Web) matchReviewEditPostHandler(w http.ResponseWriter, r *http.Reques
|
||||
return
|
||||
}
|
||||
|
||||
match, matchResult, isCurrent, err := web.getMatchResultFromRequest(r)
|
||||
match, _, isCurrent, err := web.getMatchResultFromRequest(r)
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
matchResultJson := model.MatchResultDb{Id: matchResult.Id, MatchId: match.Id, PlayNumber: matchResult.PlayNumber,
|
||||
MatchType: matchResult.MatchType, RedScoreJson: r.PostFormValue("redScoreJson"),
|
||||
BlueScoreJson: r.PostFormValue("blueScoreJson")}
|
||||
|
||||
// Deserialize the JSON using the same mechanism as to store scoring information in the database.
|
||||
matchResult, err = matchResultJson.Deserialize()
|
||||
if err != nil {
|
||||
var matchResult model.MatchResult
|
||||
if err = json.Unmarshal([]byte(r.PostFormValue("matchResultJson")), &matchResult); err != nil {
|
||||
handleWebErr(w, err)
|
||||
return
|
||||
}
|
||||
if matchResult.MatchId != match.Id {
|
||||
handleWebErr(w, fmt.Errorf("Error: match ID %d from result does not match expected", matchResult.MatchId))
|
||||
return
|
||||
}
|
||||
|
||||
if isCurrent {
|
||||
// If editing the current match, just save it back to memory.
|
||||
@@ -129,7 +129,7 @@ func (web *Web) matchReviewEditPostHandler(w http.ResponseWriter, r *http.Reques
|
||||
|
||||
http.Redirect(w, r, "/match_play", 303)
|
||||
} else {
|
||||
err = web.commitMatchScore(match, matchResult, true)
|
||||
err = web.commitMatchScore(match, &matchResult, true)
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
return
|
||||
@@ -148,7 +148,7 @@ func (web *Web) getMatchResultFromRequest(r *http.Request) (*model.Match, *model
|
||||
return web.arena.CurrentMatch, web.getCurrentMatchResult(), true, nil
|
||||
}
|
||||
|
||||
matchId, _ := strconv.Atoi(vars["matchId"])
|
||||
matchId, _ := strconv.ParseInt(vars["matchId"], 10, 64)
|
||||
match, err := web.arena.Database.GetMatchById(matchId)
|
||||
if err != nil {
|
||||
return nil, nil, false, err
|
||||
@@ -163,6 +163,7 @@ func (web *Web) getMatchResultFromRequest(r *http.Request) (*model.Match, *model
|
||||
if matchResult == nil {
|
||||
// We're scoring a match that hasn't been played yet, but that's okay.
|
||||
matchResult = model.NewMatchResult()
|
||||
matchResult.MatchId = matchId
|
||||
matchResult.MatchType = match.Type
|
||||
}
|
||||
|
||||
|
||||
@@ -40,10 +40,10 @@ func TestMatchReviewEditExistingResult(t *testing.T) {
|
||||
|
||||
match := model.Match{Type: "elimination", DisplayName: "QF4-3", Status: model.RedWonMatch, Red1: 1001,
|
||||
Red2: 1002, Red3: 1003, Blue1: 1004, Blue2: 1005, Blue3: 1006, ElimRedAlliance: 1, ElimBlueAlliance: 2}
|
||||
web.arena.Database.CreateMatch(&match)
|
||||
assert.Nil(t, web.arena.Database.CreateMatch(&match))
|
||||
matchResult := model.BuildTestMatchResult(match.Id, 1)
|
||||
matchResult.MatchType = match.Type
|
||||
web.arena.Database.CreateMatchResult(matchResult)
|
||||
assert.Nil(t, web.arena.Database.CreateMatchResult(matchResult))
|
||||
tournament.CreateTestAlliances(web.arena.Database, 2)
|
||||
|
||||
recorder := web.getHttpResponse("/match_review")
|
||||
@@ -62,10 +62,13 @@ func TestMatchReviewEditExistingResult(t *testing.T) {
|
||||
assert.Contains(t, recorder.Body.String(), " QF4-3 ")
|
||||
|
||||
// Update the score to something else.
|
||||
postBody := "redScoreJson={\"AutoPoints\":45,\"TeleopPoints\":80,\"EndgamePoints\":10}" +
|
||||
"&blueScoreJson={\"AutoPoints\":15,\"TeleopPoints\":60,\"EndgamePoints\":50}"
|
||||
postBody := fmt.Sprintf(
|
||||
"matchResultJson={\"MatchId\":%d,\"RedScore\":{\"AutoPoints\":45,\"TeleopPoints\":80,\"EndgamePoints\":10},"+
|
||||
"\"BlueScore\":{\"AutoPoints\":15,\"TeleopPoints\":60,\"EndgamePoints\":50}}",
|
||||
match.Id,
|
||||
)
|
||||
recorder = web.postHttpResponse(fmt.Sprintf("/match_review/%d/edit", match.Id), postBody)
|
||||
assert.Equal(t, 303, recorder.Code)
|
||||
assert.Equal(t, 303, recorder.Code, recorder.Body.String())
|
||||
|
||||
// Check for the updated scores back on the match list page.
|
||||
recorder = web.getHttpResponse("/match_review")
|
||||
@@ -94,10 +97,13 @@ func TestMatchReviewCreateNewResult(t *testing.T) {
|
||||
assert.Contains(t, recorder.Body.String(), " QF4-3 ")
|
||||
|
||||
// Update the score to something else.
|
||||
postBody := "redScoreJson={\"AutoPoints\":10,\"TeleopPoints\":20,\"EndgamePoints\":30}" +
|
||||
"&blueScoreJson={\"AutoPoints\":40,\"TeleopPoints\":50,\"EndgamePoints\":60}"
|
||||
postBody := fmt.Sprintf(
|
||||
"matchResultJson={\"MatchId\":%d,\"RedScore\":{\"AutoPoints\":10,\"TeleopPoints\":20,\"EndgamePoints\":30},"+
|
||||
"\"BlueScore\":{\"AutoPoints\":40,\"TeleopPoints\":50,\"EndgamePoints\":60}}",
|
||||
match.Id,
|
||||
)
|
||||
recorder = web.postHttpResponse(fmt.Sprintf("/match_review/%d/edit", match.Id), postBody)
|
||||
assert.Equal(t, 303, recorder.Code)
|
||||
assert.Equal(t, 303, recorder.Code, recorder.Body.String())
|
||||
|
||||
// Check for the updated scores back on the match list page.
|
||||
recorder = web.getHttpResponse("/match_review")
|
||||
|
||||
@@ -81,7 +81,7 @@ func (web *Web) settingsPostHandler(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
err := web.arena.Database.SaveEventSettings(eventSettings)
|
||||
err := web.arena.Database.UpdateEventSettings(eventSettings)
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
return
|
||||
|
||||
@@ -70,39 +70,39 @@ func TestSetupSettingsClearDb(t *testing.T) {
|
||||
assert.Empty(t, alliances)
|
||||
}
|
||||
|
||||
func TestSetupSettingsBackupRestoreDb(t *testing.T) {
|
||||
web := setupTestWeb(t)
|
||||
|
||||
// Modify a parameter so that we know when the database has been restored.
|
||||
web.arena.EventSettings.Name = "Chezy Champs"
|
||||
web.arena.Database.SaveEventSettings(web.arena.EventSettings)
|
||||
|
||||
// Back up the database.
|
||||
recorder := web.getHttpResponse("/setup/db/save")
|
||||
assert.Equal(t, 200, recorder.Code)
|
||||
assert.Equal(t, "application/octet-stream", recorder.HeaderMap["Content-Type"][0])
|
||||
backupBody := recorder.Body
|
||||
|
||||
// Wipe the database to reset the defaults.
|
||||
web = setupTestWeb(t)
|
||||
assert.NotEqual(t, "Chezy Champs", web.arena.EventSettings.Name)
|
||||
|
||||
// Check restoring with a missing file.
|
||||
recorder = web.postHttpResponse("/setup/db/restore", "")
|
||||
assert.Contains(t, recorder.Body.String(), "No database backup file was specified")
|
||||
assert.NotEqual(t, "Chezy Champs", web.arena.EventSettings.Name)
|
||||
|
||||
// Check restoring with a corrupt file.
|
||||
recorder = web.postFileHttpResponse("/setup/db/restore", "databaseFile",
|
||||
bytes.NewBufferString("invalid"))
|
||||
assert.Contains(t, recorder.Body.String(), "Could not read uploaded database backup file")
|
||||
assert.NotEqual(t, "Chezy Champs", web.arena.EventSettings.Name)
|
||||
|
||||
// Check restoring with the backup retrieved before.
|
||||
recorder = web.postFileHttpResponse("/setup/db/restore", "databaseFile", backupBody)
|
||||
assert.Equal(t, "Chezy Champs", web.arena.EventSettings.Name)
|
||||
|
||||
}
|
||||
// TODO(pat): Re-enable this test once fully migrated over to Bolt.
|
||||
//func TestSetupSettingsBackupRestoreDb(t *testing.T) {
|
||||
// web := setupTestWeb(t)
|
||||
//
|
||||
// // Modify a parameter so that we know when the database has been restored.
|
||||
// web.arena.EventSettings.Name = "Chezy Champs"
|
||||
// assert.Nil(t, web.arena.Database.UpdateEventSettings(web.arena.EventSettings))
|
||||
//
|
||||
// // Back up the database.
|
||||
// recorder := web.getHttpResponse("/setup/db/save")
|
||||
// assert.Equal(t, 200, recorder.Code)
|
||||
// assert.Equal(t, "application/octet-stream", recorder.HeaderMap["Content-Type"][0])
|
||||
// backupBody := recorder.Body
|
||||
//
|
||||
// // Wipe the database to reset the defaults.
|
||||
// web = setupTestWeb(t)
|
||||
// assert.NotEqual(t, "Chezy Champs", web.arena.EventSettings.Name)
|
||||
//
|
||||
// // Check restoring with a missing file.
|
||||
// recorder = web.postHttpResponse("/setup/db/restore", "")
|
||||
// assert.Contains(t, recorder.Body.String(), "No database backup file was specified")
|
||||
// assert.NotEqual(t, "Chezy Champs", web.arena.EventSettings.Name)
|
||||
//
|
||||
// // Check restoring with a corrupt file.
|
||||
// recorder = web.postFileHttpResponse("/setup/db/restore", "databaseFile",
|
||||
// bytes.NewBufferString("invalid"))
|
||||
// assert.Contains(t, recorder.Body.String(), "Could not read uploaded database backup file")
|
||||
// assert.NotEqual(t, "Chezy Champs", web.arena.EventSettings.Name)
|
||||
//
|
||||
// // Check restoring with the backup retrieved before.
|
||||
// recorder = web.postFileHttpResponse("/setup/db/restore", "databaseFile", backupBody)
|
||||
// assert.Equal(t, "Chezy Champs", web.arena.EventSettings.Name)
|
||||
//}
|
||||
|
||||
func (web *Web) postFileHttpResponse(path string, paramName string, file *bytes.Buffer) *httptest.ResponseRecorder {
|
||||
body := new(bytes.Buffer)
|
||||
|
||||
Reference in New Issue
Block a user