From d5e0ae2bbfedd88db6c298a9f61cb3b43cdc7fd6 Mon Sep 17 00:00:00 2001 From: Patrick Fairbank Date: Sun, 29 Jun 2014 14:20:47 -0700 Subject: [PATCH] Added basic structure of match control interface. --- match_play.go | 35 +++++++++++++++++++-- match_play_test.go | 50 +++++++++++++++++++++++++++++ static/css/cheesy-arena.css | 19 +++++++++++ templates/match_play.html | 63 ++++++++++++++++++++++++++++++++++--- web.go | 22 +------------ 5 files changed, 162 insertions(+), 27 deletions(-) diff --git a/match_play.go b/match_play.go index 0cb1578..e610a3d 100644 --- a/match_play.go +++ b/match_play.go @@ -19,6 +19,7 @@ type MatchPlayListItem struct { Id int DisplayName string Time string + Status string ColorClass string } @@ -27,6 +28,8 @@ type MatchPlayList []MatchPlayListItem // Global var to hold the current active tournament so that its matches are displayed by default. var currentMatchType string +var currentMatch *Match + // Shows the match play control interface. func MatchPlayHandler(w http.ResponseWriter, r *http.Request) { practiceMatches, err := buildMatchPlayList("practice") @@ -55,11 +58,15 @@ func MatchPlayHandler(w http.ResponseWriter, r *http.Request) { if currentMatchType == "" { currentMatchType = "practice" } + if currentMatch == nil { + currentMatch = new(Match) + } data := struct { *EventSettings MatchesByType map[string]MatchPlayList CurrentMatchType string - }{eventSettings, matchesByType, currentMatchType} + Match *Match + }{eventSettings, matchesByType, currentMatchType, currentMatch} err = template.ExecuteTemplate(w, "base", data) if err != nil { handleWebErr(w, err) @@ -67,6 +74,26 @@ func MatchPlayHandler(w http.ResponseWriter, r *http.Request) { } } +func MatchPlayQueueHandler(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + matchId, _ := strconv.Atoi(vars["matchId"]) + match, err := db.GetMatchById(matchId) + if err != nil { + handleWebErr(w, err) + return + } + if match == nil { + handleWebErr(w, fmt.Errorf("Invalid match ID %d.", matchId)) + return + } + + // TODO(pat): Disallow if there is a match currently being played or there are uncommitted results. + currentMatch = match + currentMatchType = match.Type + + http.Redirect(w, r, "/match_play", 302) +} + func MatchPlayFakeResultHandler(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) matchId, _ := strconv.Atoi(vars["matchId"]) @@ -149,7 +176,7 @@ func (list MatchPlayList) Len() int { } func (list MatchPlayList) Less(i, j int) bool { - return list[i].ColorClass == "" && list[j].ColorClass != "" + return list[i].Status != "complete" && list[j].Status == "complete" } func (list MatchPlayList) Swap(i, j int) { @@ -173,6 +200,7 @@ func buildMatchPlayList(matchType string) (MatchPlayList, error) { matchPlayList[i].Id = match.Id matchPlayList[i].DisplayName = prefix + match.DisplayName matchPlayList[i].Time = match.Time.Format("3:04 PM") + matchPlayList[i].Status = match.Status switch match.Winner { case "R": matchPlayList[i].ColorClass = "danger" @@ -183,6 +211,9 @@ func buildMatchPlayList(matchType string) (MatchPlayList, error) { default: matchPlayList[i].ColorClass = "" } + if currentMatch != nil && matchPlayList[i].Id == currentMatch.Id { + matchPlayList[i].ColorClass = "success" + } } // Sort the list to put all completed matches at the bottom. diff --git a/match_play_test.go b/match_play_test.go index 9143d2f..c1db2a3 100644 --- a/match_play_test.go +++ b/match_play_test.go @@ -4,6 +4,7 @@ package main import ( + "fmt" "github.com/stretchr/testify/assert" "testing" ) @@ -37,3 +38,52 @@ func TestMatchPlay(t *testing.T) { assert.Contains(t, recorder.Body.String(), "SF1-1") assert.Contains(t, recorder.Body.String(), "SF1-2") } + +func TestMatchPlayQueue(t *testing.T) { + clearDb() + defer clearDb() + var err error + db, err = OpenDatabase(testDbPath) + assert.Nil(t, err) + defer db.Close() + eventSettings, _ = db.GetEventSettings() + + match := Match{Type: "elimination", DisplayName: "QF4-3", Status: "complete", Winner: "R", Red1: 101, + Red2: 102, Red3: 103, Blue1: 104, Blue2: 105, Blue3: 106} + db.CreateMatch(&match) + recorder := getHttpResponse("/match_play") + assert.Equal(t, 200, recorder.Code) + assert.NotContains(t, recorder.Body.String(), "101") + assert.NotContains(t, recorder.Body.String(), "102") + assert.NotContains(t, recorder.Body.String(), "103") + assert.NotContains(t, recorder.Body.String(), "104") + assert.NotContains(t, recorder.Body.String(), "105") + assert.NotContains(t, recorder.Body.String(), "106") + + // Queue the match and check for the team numbers again. + recorder = getHttpResponse(fmt.Sprintf("/match_play/%d/queue", match.Id)) + assert.Equal(t, 302, recorder.Code) + recorder = getHttpResponse("/match_play") + assert.Equal(t, 200, recorder.Code) + assert.Contains(t, recorder.Body.String(), "101") + assert.Contains(t, recorder.Body.String(), "102") + assert.Contains(t, recorder.Body.String(), "103") + assert.Contains(t, recorder.Body.String(), "104") + assert.Contains(t, recorder.Body.String(), "105") + assert.Contains(t, recorder.Body.String(), "106") +} + +func TestMatchPlayErrors(t *testing.T) { + clearDb() + defer clearDb() + var err error + db, err = OpenDatabase(testDbPath) + assert.Nil(t, err) + defer db.Close() + eventSettings, _ = db.GetEventSettings() + + // Queue an invalid match. + recorder := getHttpResponse("/match_play/1114/queue") + assert.Equal(t, 500, recorder.Code) + assert.Contains(t, recorder.Body.String(), "Invalid match") +} diff --git a/static/css/cheesy-arena.css b/static/css/cheesy-arena.css index 7b52a0a..53f282f 100644 --- a/static/css/cheesy-arena.css +++ b/static/css/cheesy-arena.css @@ -16,3 +16,22 @@ .well-darkblue { background-color: #c4e3f3; } +.col-no-padding { + padding-left: 0; + padding-right: 0; +} +.ds-status, .robot-status, .battery-status, .bypass-button { + background-color: #aaa; + color: #000; + border: 1px solid #999; + border-radius: 4px; + padding: 5px; + width: 40px; + height: 27px; + margin: 2px; + font-family: Arial; + margin: 0 auto; +} +.bypass-button { + background-color: #0e8; +} \ No newline at end of file diff --git a/templates/match_play.html b/templates/match_play.html index fcd16c9..806a378 100644 --- a/templates/match_play.html +++ b/templates/match_play.html @@ -33,6 +33,9 @@ Generate Fake Result + + Queue + {{end}} @@ -42,13 +45,65 @@ {{end}} -
-
-

Placeholder for the match play interface.

-

For now, use the "Generate Fake Result" buttons to simulate matches being played and scored.

+
+
+
+
+
Blue Teams
+
DS
+
R
+
B
+
Byp
+
+
+
1
+ {{template "matchPlayTeam" .Match.Blue1}} +
+
+
2
+ {{template "matchPlayTeam" .Match.Blue2}} +
+
+
3
+ {{template "matchPlayTeam" .Match.Blue3}} +
+
+
+
+
Red Teams
+
DS
+
R
+
B
+
Byp
+
+
+
3
+ {{template "matchPlayTeam" .Match.Red3}} +
+
+
2
+ {{template "matchPlayTeam" .Match.Red2}} +
+
+
1
+ {{template "matchPlayTeam" .Match.Red1}} +
+
{{end}} {{define "script"}} + +{{end}} +{{define "matchPlayTeam"}} +
+ +
+
+
+
+
{{end}} diff --git a/web.go b/web.go index d24213f..c7d584a 100644 --- a/web.go +++ b/web.go @@ -11,9 +11,6 @@ import ( "html/template" "log" "net/http" - "os/exec" - "runtime" - "strconv" ) const httpPort = 8080 @@ -39,24 +36,6 @@ func ServeWebInterface() { http.Handle("/", newHandler()) log.Printf("Serving HTTP requests on port %d", httpPort) - // Open in Default Web Browser - // Necessary to Authenticate - url := "http://localhost:" + strconv.Itoa(httpPort) - var err error - switch runtime.GOOS { - case "linux": - err = exec.Command("xdg-open", url).Start() - case "darwin": - err = exec.Command("open", url).Start() - case "windows": - err = exec.Command(`rundll32.exe`, "url.dll,FileProtocolHandler", url).Start() - default: - err = fmt.Errorf("unsupported platform") - } - if err != nil { - println(err.Error()) - } - // Start Server http.ListenAndServe(fmt.Sprintf(":%d", httpPort), nil) } @@ -83,6 +62,7 @@ func newHandler() http.Handler { router.HandleFunc("/setup/alliance_selection/reset", AllianceSelectionResetHandler).Methods("POST") router.HandleFunc("/setup/alliance_selection/finalize", AllianceSelectionFinalizeHandler).Methods("POST") router.HandleFunc("/match_play", MatchPlayHandler).Methods("GET") + router.HandleFunc("/match_play/{matchId}/queue", MatchPlayQueueHandler).Methods("GET") router.HandleFunc("/match_play/{matchId}/generate_fake_result", MatchPlayFakeResultHandler).Methods("GET") router.HandleFunc("/match_review", MatchReviewHandler).Methods("GET") router.HandleFunc("/match_review/{matchId}/edit", MatchReviewEditGetHandler).Methods("GET")