Skip to content

Commit

Permalink
Allow selective clearing of match data by level (closes #173).
Browse files Browse the repository at this point in the history
  • Loading branch information
patfair committed May 30, 2024
1 parent 40485a9 commit 8b665c7
Show file tree
Hide file tree
Showing 5 changed files with 217 additions and 56 deletions.
65 changes: 58 additions & 7 deletions templates/setup_settings.html
Original file line number Diff line number Diff line change
Expand Up @@ -301,13 +301,23 @@
<a href="/setup/db/save"><button class="btn btn-primary">Save Copy of Database</button></a>
</p>
<p>
<button type="button" class="btn btn-danger" onclick="$('#uploadDatabase').modal('show');">
<button type="button" class="btn btn-warning" onclick="$('#uploadDatabase').modal('show');">
Load Database from Backup
</button>
</p>
<p>
<button type="button" class="btn btn-danger" onclick="$('#confirmClearData').modal('show');">
Clear All Match Data
<button type="button" class="btn btn-danger" onclick="$('#confirmClearDataPlayoff').modal('show');">
Clear Playoff/Alliance Data
</button>
</p>
<p>
<button type="button" class="btn btn-danger" onclick="$('#confirmClearDataQualification').modal('show');">
Clear Qualification Data
</button>
</p>
<p>
<button type="button" class="btn btn-danger" onclick="$('#confirmClearDataPractice').modal('show');">
Clear Practice Data
</button>
</p>
</div>
Expand Down Expand Up @@ -353,20 +363,61 @@ <h4 class="modal-title">Choose Backup File</h4>
</div>
</div>
</div>
<div id="confirmClearData" class="modal" style="top: 20%;">
<div id="confirmClearDataPlayoff" class="modal" style="top: 20%;">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">Confirm</h4>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-hidden="true"></button>
</div>
<div class="modal-body">
<p>Are you sure you want to clear all playoff match and alliance selection data?</p>
<p>The database will automatically be backed up.</p>
</div>
<div class="modal-footer">
<form class="form-horizontal" action="/setup/db/clear/playoff" method="POST">
<button type="button" class="btn btn-primary" data-bs-dismiss="modal">Cancel</button>
<button type="submit" class="btn btn-danger">Clear Playoff/Alliance Data</button>
</form>
</div>
</div>
</div>
</div>
<div id="confirmClearDataQualification" class="modal" style="top: 20%;">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">Confirm</h4>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-hidden="true"></button>
</div>
<div class="modal-body">
<p>Are you sure you want to clear all qualification match and ranking data?</p>
<p>The database will automatically be backed up.</p>
</div>
<div class="modal-footer">
<form class="form-horizontal" action="/setup/db/clear/qualification" method="POST">
<button type="button" class="btn btn-primary" data-bs-dismiss="modal">Cancel</button>
<button type="submit" class="btn btn-danger">Clear Qualification Data</button>
</form>
</div>
</div>
</div>
</div>
<div id="confirmClearDataPractice" class="modal" style="top: 20%;">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">Confirm</h4>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-hidden="true"></button>
</div>
<div class="modal-body">
<p>Are you sure you want to clear all match, ranking, and alliance selection data?</p>
<p>Are you sure you want to clear all practice match data?</p>
<p>The database will automatically be backed up.</p>
</div>
<div class="modal-footer">
<form class="form-horizontal" action="/setup/db/clear" method="POST">
<form class="form-horizontal" action="/setup/db/clear/practice" method="POST">
<button type="button" class="btn btn-primary" data-bs-dismiss="modal">Cancel</button>
<button type="submit" class="btn btn-danger">Clear All Match Data</button>
<button type="submit" class="btn btn-danger">Clear Practice Data</button>
</form>
</div>
</div>
Expand Down
12 changes: 1 addition & 11 deletions web/alliance_selection.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,21 +147,11 @@ func (web *Web) allianceSelectionResetHandler(w http.ResponseWriter, r *http.Req
}

// Delete any playoff matches that were already created (but not played since they would fail the above check).
matches, err := web.arena.Database.GetMatchesByType(model.Playoff, true)
err := web.deleteMatchDataForType(model.Playoff)
if err != nil {
handleWebErr(w, err)
return
}
for _, match := range matches {
if err = web.arena.Database.DeleteMatch(match.Id); err != nil {
handleWebErr(w, err)
return
}
}
if err = web.arena.Database.DeleteScheduledBreaksByMatchType(model.Playoff); err != nil {
handleWebErr(w, err)
return
}

// Delete the saved alliances.
if err = web.arena.Database.TruncateAlliances(); err != nil {
Expand Down
93 changes: 66 additions & 27 deletions web/setup_settings.go
Original file line number Diff line number Diff line change
Expand Up @@ -203,46 +203,53 @@ func (web *Web) restoreDbHandler(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, "/setup/settings", 303)
}

// Deletes all data except for the team list.
// Deletes all match data including and beyond the given tournament stage.
func (web *Web) clearDbHandler(w http.ResponseWriter, r *http.Request) {
if !web.userIsAdmin(w, r) {
return
}

// Back up the database.
err := web.arena.Database.Backup(web.arena.EventSettings.Name, "pre_clear")
if err != nil {
handleWebErr(w, err)
matchType, err := model.MatchTypeFromString(r.PathValue("type"))
if err != nil || matchType == model.Test {
web.renderSettings(w, r, "Invalid tournament stage to clear.")
return
}

err = web.arena.Database.TruncateMatches()
if err != nil {
handleWebErr(w, err)
return
}
err = web.arena.Database.TruncateMatchResults()
if err != nil {
handleWebErr(w, err)
return
}
err = web.arena.Database.TruncateRankings()
if err != nil {
handleWebErr(w, err)
return
}
err = web.arena.Database.TruncateAlliances()

// Back up the database.
err = web.arena.Database.Backup(web.arena.EventSettings.Name, "pre_clear")
if err != nil {
handleWebErr(w, err)
return
}
err = web.arena.Database.TruncateScheduledBreaks()
if err != nil {
handleWebErr(w, err)
return

switch matchType {
case model.Practice:
if err = web.deleteMatchDataForType(model.Practice); err != nil {
handleWebErr(w, err)
return
}
case model.Qualification:
if err = web.deleteMatchDataForType(model.Qualification); err != nil {
handleWebErr(w, err)
return
}
if err = web.arena.Database.TruncateRankings(); err != nil {
handleWebErr(w, err)
return
}
case model.Playoff:
if err = web.deleteMatchDataForType(model.Playoff); err != nil {
handleWebErr(w, err)
return
}
if err = web.arena.Database.TruncateAlliances(); err != nil {
handleWebErr(w, err)
return
}
web.arena.AllianceSelectionAlliances = []model.Alliance{}
cachedRankedTeams = []*RankedTeam{}
}
web.arena.AllianceSelectionAlliances = []model.Alliance{}
cachedRankedTeams = []*RankedTeam{}

http.Redirect(w, r, "/setup/settings", 303)
}
Expand Down Expand Up @@ -368,3 +375,35 @@ func (web *Web) renderSettings(w http.ResponseWriter, r *http.Request, errorMess
return
}
}

// Deletes all match data (matches, results, and scheduled breaks) for the given match type.
func (web *Web) deleteMatchDataForType(matchType model.MatchType) error {
matches, err := web.arena.Database.GetMatchesByType(matchType, true)
if err != nil {
return err
}
for _, match := range matches {
// Loop to delete all match results for the match before deleting the match itself.
matchResult, err := web.arena.Database.GetMatchResultForMatch(match.Id)
if err != nil {
return err
}
for matchResult != nil {
if err = web.arena.Database.DeleteMatchResult(matchResult.Id); err != nil {
return err
}
matchResult, err = web.arena.Database.GetMatchResultForMatch(match.Id)
if err != nil {
return err
}
}

if err = web.arena.Database.DeleteMatch(match.Id); err != nil {
return err
}
}
if err = web.arena.Database.DeleteScheduledBreaksByMatchType(matchType); err != nil {
return err
}
return nil
}
101 changes: 91 additions & 10 deletions web/setup_settings_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,27 +62,108 @@ func TestSetupSettingsInvalidValues(t *testing.T) {
}

func TestSetupSettingsClearDb(t *testing.T) {
createData := func(web *Web) {
assert.Nil(t, web.arena.Database.CreateTeam(&model.Team{Id: 254}))
assert.Nil(t, web.arena.Database.CreateMatch(&model.Match{Type: model.Practice}))
assert.Nil(t, web.arena.Database.CreateMatch(&model.Match{Type: model.Qualification}))
assert.Nil(t, web.arena.Database.CreateMatch(&model.Match{Type: model.Playoff}))
assert.Nil(t, web.arena.Database.CreateMatchResult(&model.MatchResult{MatchId: 1, PlayNumber: 1}))
assert.Nil(t, web.arena.Database.CreateMatchResult(&model.MatchResult{MatchId: 1, PlayNumber: 2}))
assert.Nil(t, web.arena.Database.CreateMatchResult(&model.MatchResult{MatchId: 2, PlayNumber: 1}))
assert.Nil(t, web.arena.Database.CreateMatchResult(&model.MatchResult{MatchId: 3, PlayNumber: 1}))
assert.Nil(t, web.arena.Database.CreateRanking(&game.Ranking{TeamId: 254}))
assert.Nil(t, web.arena.Database.CreateAlliance(&model.Alliance{Id: 1}))
web.arena.AllianceSelectionAlliances = append(web.arena.AllianceSelectionAlliances, model.Alliance{Id: 1})
}

// Test clearing practice data.
web := setupTestWeb(t)

assert.Nil(t, web.arena.Database.CreateTeam(&model.Team{Id: 254}))
assert.Nil(t, web.arena.Database.CreateMatch(&model.Match{Type: model.Qualification}))
assert.Nil(t, web.arena.Database.CreateMatchResult(new(model.MatchResult)))
assert.Nil(t, web.arena.Database.CreateRanking(&game.Ranking{TeamId: 254}))
assert.Nil(t, web.arena.Database.CreateAlliance(&model.Alliance{Id: 1}))
recorder := web.postHttpResponse("/setup/db/clear", "")
createData(web)
recorder := web.postHttpResponse("/setup/db/clear/practice", "")
assert.Equal(t, 303, recorder.Code)

teams, _ := web.arena.Database.GetAllTeams()
assert.NotEmpty(t, teams)
matches, _ := web.arena.Database.GetMatchesByType(model.Qualification, true)
matches, _ := web.arena.Database.GetMatchesByType(model.Practice, true)
assert.Empty(t, matches)
matchResult, _ := web.arena.Database.GetMatchResultForMatch(1)
assert.Nil(t, matchResult)
matches, _ = web.arena.Database.GetMatchesByType(model.Qualification, true)
assert.NotEmpty(t, matches)
matchResult, _ = web.arena.Database.GetMatchResultForMatch(2)
assert.NotNil(t, matchResult)
matches, _ = web.arena.Database.GetMatchesByType(model.Playoff, true)
assert.NotEmpty(t, matches)
matchResult, _ = web.arena.Database.GetMatchResultForMatch(3)
assert.NotNil(t, matchResult)
rankings, _ := web.arena.Database.GetAllRankings()
assert.NotEmpty(t, rankings)
tournament.CalculateRankings(web.arena.Database, false)
assert.NotEmpty(t, rankings)
alliances, _ := web.arena.Database.GetAllAlliances()
assert.NotEmpty(t, alliances)
assert.NotEmpty(t, web.arena.AllianceSelectionAlliances)

// Test clearing qualification data.
web = setupTestWeb(t)
createData(web)
recorder = web.postHttpResponse("/setup/db/clear/qualification", "")
assert.Equal(t, 303, recorder.Code)
teams, _ = web.arena.Database.GetAllTeams()
assert.NotEmpty(t, teams)
matches, _ = web.arena.Database.GetMatchesByType(model.Practice, true)
assert.NotEmpty(t, matches)
matchResult, _ = web.arena.Database.GetMatchResultForMatch(1)
assert.NotNil(t, matchResult)
matches, _ = web.arena.Database.GetMatchesByType(model.Qualification, true)
assert.Empty(t, matches)
matchResult, _ = web.arena.Database.GetMatchResultForMatch(2)
assert.Nil(t, matchResult)
matches, _ = web.arena.Database.GetMatchesByType(model.Playoff, true)
assert.NotEmpty(t, matches)
matchResult, _ = web.arena.Database.GetMatchResultForMatch(3)
assert.NotNil(t, matchResult)
rankings, _ = web.arena.Database.GetAllRankings()
assert.Empty(t, rankings)
tournament.CalculateRankings(web.arena.Database, false)
assert.Empty(t, rankings)
alliances, _ := web.arena.Database.GetAllAlliances()
alliances, _ = web.arena.Database.GetAllAlliances()
assert.NotEmpty(t, alliances)
assert.NotEmpty(t, web.arena.AllianceSelectionAlliances)

// Test clearing playoff data.
web = setupTestWeb(t)
createData(web)
recorder = web.postHttpResponse("/setup/db/clear/playoff", "")
assert.Equal(t, 303, recorder.Code)
teams, _ = web.arena.Database.GetAllTeams()
assert.NotEmpty(t, teams)
matches, _ = web.arena.Database.GetMatchesByType(model.Practice, true)
assert.NotEmpty(t, matches)
matchResult, _ = web.arena.Database.GetMatchResultForMatch(1)
assert.NotNil(t, matchResult)
matches, _ = web.arena.Database.GetMatchesByType(model.Qualification, true)
assert.NotEmpty(t, matches)
matchResult, _ = web.arena.Database.GetMatchResultForMatch(2)
assert.NotNil(t, matchResult)
matches, _ = web.arena.Database.GetMatchesByType(model.Playoff, true)
assert.Empty(t, matches)
matchResult, _ = web.arena.Database.GetMatchResultForMatch(3)
assert.Nil(t, matchResult)
rankings, _ = web.arena.Database.GetAllRankings()
assert.NotEmpty(t, rankings)
tournament.CalculateRankings(web.arena.Database, false)
assert.NotEmpty(t, rankings)
alliances, _ = web.arena.Database.GetAllAlliances()
assert.Empty(t, alliances)
assert.Empty(t, web.arena.AllianceSelectionAlliances)

// Test with invalid match types.
recorder = web.postHttpResponse("/setup/db/clear/all", "")
assert.Equal(t, 200, recorder.Code)
assert.Contains(t, recorder.Body.String(), "Invalid tournament stage to clear")
recorder = web.postHttpResponse("/setup/db/clear/test", "")
assert.Equal(t, 200, recorder.Code)
assert.Contains(t, recorder.Body.String(), "Invalid tournament stage to clear")
}

func TestSetupSettingsBackupRestoreDb(t *testing.T) {
Expand Down
2 changes: 1 addition & 1 deletion web/web.go
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ func (web *Web) newHandler() http.Handler {
mux.HandleFunc("POST /setup/awards", web.awardsPostHandler)
mux.HandleFunc("GET /setup/breaks", web.breaksGetHandler)
mux.HandleFunc("POST /setup/breaks", web.breaksPostHandler)
mux.HandleFunc("POST /setup/db/clear", web.clearDbHandler)
mux.HandleFunc("POST /setup/db/clear/{type}", web.clearDbHandler)
mux.HandleFunc("POST /setup/db/restore", web.restoreDbHandler)
mux.HandleFunc("GET /setup/db/save", web.saveDbHandler)
mux.HandleFunc("GET /setup/displays", web.displaysGetHandler)
Expand Down

0 comments on commit 8b665c7

Please sign in to comment.