mirror of
https://github.com/Team254/cheesy-arena-lite.git
synced 2026-03-09 13:46:44 -04:00
Refactor web handlers into separate package.
This commit is contained in:
@@ -2,7 +2,6 @@
|
||||
CREATE TABLE event_settings (
|
||||
id INTEGER PRIMARY KEY,
|
||||
name VARCHAR(255),
|
||||
code VARCHAR(16),
|
||||
displaybackgroundcolor VARCHAR(16),
|
||||
numelimalliances int,
|
||||
selectionround2order VARCHAR(1),
|
||||
|
||||
@@ -27,8 +27,6 @@ const (
|
||||
blue3Vlan = 60
|
||||
)
|
||||
|
||||
var templatesPath = "."
|
||||
|
||||
type AccessPoint struct {
|
||||
address string
|
||||
port int
|
||||
@@ -101,7 +99,7 @@ func generateAccessPointConfig(red1, red2, red3, blue1, blue2, blue3 *model.Team
|
||||
}
|
||||
|
||||
// Generate the config file to be uploaded to the AP.
|
||||
template, err := template.ParseFiles(filepath.Join(templatesPath, "templates/access_point.cfg"))
|
||||
template, err := template.ParseFiles(filepath.Join(model.BaseDir, "templates/access_point.cfg"))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
)
|
||||
|
||||
func TestConfigureAccessPoint(t *testing.T) {
|
||||
templatesPath = ".."
|
||||
model.BaseDir = ".."
|
||||
|
||||
radioRe := regexp.MustCompile("option device 'radio0'")
|
||||
ssidRe := regexp.MustCompile("option ssid '([-\\w ]+)'")
|
||||
|
||||
@@ -15,14 +15,14 @@ import (
|
||||
)
|
||||
|
||||
func SetupTestArena(t *testing.T, uniqueName string) *Arena {
|
||||
dbPath := fmt.Sprintf("%s_test.db", uniqueName)
|
||||
os.Remove(filepath.Join(model.BaseDir, dbPath))
|
||||
model.BaseDir = ".."
|
||||
dbPath := filepath.Join(model.BaseDir, fmt.Sprintf("%s_test.db", uniqueName))
|
||||
os.Remove(dbPath)
|
||||
arena, err := NewArena(dbPath)
|
||||
assert.Nil(t, err)
|
||||
return arena
|
||||
}
|
||||
|
||||
func setupTestArena(t *testing.T) *Arena {
|
||||
model.BaseDir = ".."
|
||||
return SetupTestArena(t, "field")
|
||||
}
|
||||
|
||||
3
main.go
3
main.go
@@ -5,6 +5,7 @@ package main
|
||||
|
||||
import (
|
||||
"github.com/Team254/cheesy-arena/field"
|
||||
"github.com/Team254/cheesy-arena/web"
|
||||
"log"
|
||||
"math/rand"
|
||||
"time"
|
||||
@@ -23,7 +24,7 @@ func main() {
|
||||
}
|
||||
|
||||
// Start the web server in a separate goroutine.
|
||||
web := NewWeb(arena)
|
||||
web := web.NewWeb(arena)
|
||||
go web.ServeWebInterface(httpPort)
|
||||
|
||||
// Run the arena state machine in the main thread.
|
||||
|
||||
@@ -25,7 +25,7 @@ const migrationsDir = "db/migrations"
|
||||
var BaseDir = "." // Mutable for testing
|
||||
|
||||
type Database struct {
|
||||
filename string
|
||||
Path string
|
||||
db *sql.DB
|
||||
eventSettingsMap *modl.DbMap
|
||||
matchMap *modl.DbMap
|
||||
@@ -41,9 +41,9 @@ type Database struct {
|
||||
// migrations.
|
||||
func OpenDatabase(filename string) (*Database, error) {
|
||||
// Find and run the migrations using goose. This also auto-creates the DB.
|
||||
database := Database{filename: filename}
|
||||
database := Database{Path: filename}
|
||||
migrationsPath := filepath.Join(BaseDir, migrationsDir)
|
||||
dbDriver := goose.DBDriver{"sqlite3", database.GetPath(), "github.com/mattn/go-sqlite3", &goose.Sqlite3Dialect{}}
|
||||
dbDriver := goose.DBDriver{"sqlite3", database.Path, "github.com/mattn/go-sqlite3", &goose.Sqlite3Dialect{}}
|
||||
dbConf := goose.DBConf{MigrationsDir: migrationsPath, Env: "prod", Driver: dbDriver}
|
||||
target, err := goose.GetMostRecentDBVersion(migrationsPath)
|
||||
if err != nil {
|
||||
@@ -54,7 +54,7 @@ func OpenDatabase(filename string) (*Database, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
db, err := sql.Open("sqlite3", database.GetPath())
|
||||
db, err := sql.Open("sqlite3", database.Path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -77,7 +77,7 @@ func (database *Database) Backup(eventName, reason string) error {
|
||||
}
|
||||
filename := fmt.Sprintf("%s/%s_%s_%s.db", backupsPath, strings.Replace(eventName, " ", "_", -1),
|
||||
time.Now().Format("20060102150405"), reason)
|
||||
src, err := os.Open(database.GetPath())
|
||||
src, err := os.Open(database.Path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -93,10 +93,6 @@ func (database *Database) Backup(eventName, reason string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (database *Database) GetPath() string {
|
||||
return filepath.Join(BaseDir, database.filename)
|
||||
}
|
||||
|
||||
// Sets up table-object associations.
|
||||
func (database *Database) mapTables() {
|
||||
dialect := new(modl.SqliteDialect)
|
||||
|
||||
@@ -8,7 +8,6 @@ package model
|
||||
type EventSettings struct {
|
||||
Id int
|
||||
Name string
|
||||
Code string
|
||||
DisplayBackgroundColor string
|
||||
NumElimAlliances int
|
||||
SelectionRound2Order string
|
||||
@@ -39,7 +38,6 @@ func (database *Database) GetEventSettings() (*EventSettings, error) {
|
||||
if err != nil {
|
||||
// Database record doesn't exist yet; create it now.
|
||||
eventSettings.Name = "Untitled Event"
|
||||
eventSettings.Code = "UE"
|
||||
eventSettings.DisplayBackgroundColor = "#00ff00"
|
||||
eventSettings.NumElimAlliances = 8
|
||||
eventSettings.SelectionRound2Order = "L"
|
||||
|
||||
@@ -13,12 +13,11 @@ func TestEventSettingsReadWrite(t *testing.T) {
|
||||
|
||||
eventSettings, err := db.GetEventSettings()
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, EventSettings{Id: 0, Name: "Untitled Event", Code: "UE", DisplayBackgroundColor: "#00ff00",
|
||||
assert.Equal(t, EventSettings{Id: 0, Name: "Untitled Event", DisplayBackgroundColor: "#00ff00",
|
||||
NumElimAlliances: 8, SelectionRound2Order: "L", SelectionRound3Order: "", TBADownloadEnabled: true},
|
||||
*eventSettings)
|
||||
|
||||
eventSettings.Name = "Chezy Champs"
|
||||
eventSettings.Code = "cc"
|
||||
eventSettings.DisplayBackgroundColor = "#ff00ff"
|
||||
eventSettings.NumElimAlliances = 6
|
||||
eventSettings.SelectionRound2Order = "F"
|
||||
|
||||
@@ -16,8 +16,8 @@ import (
|
||||
|
||||
func SetupTestDb(t *testing.T, uniqueName string) *Database {
|
||||
BaseDir = ".."
|
||||
dbPath := fmt.Sprintf("%s_test.db", uniqueName)
|
||||
os.Remove(filepath.Join(BaseDir, dbPath))
|
||||
dbPath := filepath.Join(BaseDir, fmt.Sprintf("%s_test.db", uniqueName))
|
||||
os.Remove(dbPath)
|
||||
database, err := OpenDatabase(dbPath)
|
||||
assert.Nil(t, err)
|
||||
return database
|
||||
|
||||
@@ -24,12 +24,6 @@
|
||||
<input type="text" class="form-control" name="name" value="{{.Name}}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-lg-5 control-label">Code</label>
|
||||
<div class="col-lg-7">
|
||||
<input type="text" class="form-control" name="code" value="{{.Code}}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-lg-5 control-label">Display Background Color</label>
|
||||
<div class="col-lg-7">
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
// Copyright 2017 Team 254. All Rights Reserved.
|
||||
// Author: pat@patfairbank.com (Patrick Fairbank)
|
||||
//
|
||||
// Helper methods for use in tests in this package and others.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/Team254/cheesy-arena/field"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func setupTestWeb(t *testing.T) *Web {
|
||||
arena := field.SetupTestArena(t, "web")
|
||||
return NewWeb(arena)
|
||||
}
|
||||
@@ -12,13 +12,15 @@ import (
|
||||
"math"
|
||||
"math/rand"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
var schedulesDir = "schedules"
|
||||
|
||||
const TeamsPerMatch = 6
|
||||
const (
|
||||
schedulesDir = "schedules"
|
||||
TeamsPerMatch = 6
|
||||
)
|
||||
|
||||
type ScheduleBlock struct {
|
||||
StartTime time.Time
|
||||
@@ -36,7 +38,8 @@ func BuildRandomSchedule(teams []model.Team, scheduleBlocks []ScheduleBlock, mat
|
||||
// Adjust the number of matches to remove any excess from non-perfect block scheduling.
|
||||
numMatches = int(math.Ceil(float64(numTeams) * float64(matchesPerTeam) / TeamsPerMatch))
|
||||
|
||||
file, err := os.Open(fmt.Sprintf("%s/%d_%d.csv", schedulesDir, numTeams, matchesPerTeam))
|
||||
file, err := os.Open(fmt.Sprintf("%s/%d_%d.csv", filepath.Join(model.BaseDir, schedulesDir), numTeams,
|
||||
matchesPerTeam))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("No schedule template exists for %d teams and %d matches", numTeams, matchesPerTeam)
|
||||
}
|
||||
|
||||
@@ -9,12 +9,12 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"math/rand"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
schedulesDir = "../schedules"
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ func TestNonExistentSchedule(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestMalformedSchedule(t *testing.T) {
|
||||
filename := fmt.Sprintf("%s/6_1.csv", schedulesDir)
|
||||
filename := fmt.Sprintf("%s/6_1.csv", filepath.Join(model.BaseDir, schedulesDir))
|
||||
scheduleFile, _ := os.Create(filename)
|
||||
defer os.Remove(filename)
|
||||
scheduleFile.WriteString("1,0,2,0,3,0,4,0,5,0,6,0\n6,0,5,0,4,0,3,0,2,0,1,0\n")
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
//
|
||||
// Web handlers for the alliance station display.
|
||||
|
||||
package main
|
||||
package web
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@@ -13,7 +13,6 @@ import (
|
||||
"log"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
// Renders the team number and status display shown above each alliance station.
|
||||
@@ -22,8 +21,7 @@ func (web *Web) allianceStationDisplayHandler(w http.ResponseWriter, r *http.Req
|
||||
return
|
||||
}
|
||||
|
||||
template := template.New("").Funcs(web.templateHelpers)
|
||||
_, err := template.ParseFiles("templates/alliance_station_display.html")
|
||||
template, err := web.parseFiles("templates/alliance_station_display.html")
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
return
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2014 Team 254. All Rights Reserved.
|
||||
// Author: pat@patfairbank.com (Patrick Fairbank)
|
||||
|
||||
package main
|
||||
package web
|
||||
|
||||
import (
|
||||
"github.com/gorilla/websocket"
|
||||
@@ -3,7 +3,7 @@
|
||||
//
|
||||
// Web handlers for announcer display.
|
||||
|
||||
package main
|
||||
package web
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@@ -12,7 +12,6 @@ import (
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
// Renders the announcer display which shows team info and scores for the current match.
|
||||
@@ -21,8 +20,7 @@ func (web *Web) announcerDisplayHandler(w http.ResponseWriter, r *http.Request)
|
||||
return
|
||||
}
|
||||
|
||||
template := template.New("").Funcs(web.templateHelpers)
|
||||
_, err := template.ParseFiles("templates/announcer_display.html", "templates/base.html")
|
||||
template, err := web.parseFiles("templates/announcer_display.html", "templates/base.html")
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
return
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2014 Team 254. All Rights Reserved.
|
||||
// Author: pat@patfairbank.com (Patrick Fairbank)
|
||||
|
||||
package main
|
||||
package web
|
||||
|
||||
import (
|
||||
"github.com/gorilla/websocket"
|
||||
@@ -3,7 +3,7 @@
|
||||
//
|
||||
// Web API for providing JSON-formatted event data.
|
||||
|
||||
package main
|
||||
package web
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2014 Team 254. All Rights Reserved.
|
||||
// Author: pat@patfairbank.com (Patrick Fairbank)
|
||||
|
||||
package main
|
||||
package web
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
@@ -3,7 +3,7 @@
|
||||
//
|
||||
// Web handlers for audience screen display.
|
||||
|
||||
package main
|
||||
package web
|
||||
|
||||
import (
|
||||
"github.com/Team254/cheesy-arena/game"
|
||||
@@ -11,7 +11,6 @@ import (
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
// Renders the audience display to be chroma keyed over the video feed.
|
||||
@@ -20,8 +19,7 @@ func (web *Web) audienceDisplayHandler(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
template := template.New("").Funcs(web.templateHelpers)
|
||||
_, err := template.ParseFiles("templates/audience_display.html")
|
||||
template, err := web.parseFiles("templates/audience_display.html")
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
return
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2014 Team 254. All Rights Reserved.
|
||||
// Author: pat@patfairbank.com (Patrick Fairbank)
|
||||
|
||||
package main
|
||||
package web
|
||||
|
||||
import (
|
||||
"github.com/gorilla/websocket"
|
||||
@@ -3,14 +3,13 @@
|
||||
//
|
||||
// Web handlers for the FTA diagnostic display.
|
||||
|
||||
package main
|
||||
package web
|
||||
|
||||
import (
|
||||
"github.com/Team254/cheesy-arena/model"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
// Renders the FTA diagnostic display.
|
||||
@@ -19,8 +18,7 @@ func (web *Web) ftaDisplayHandler(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
template := template.New("").Funcs(web.templateHelpers)
|
||||
_, err := template.ParseFiles("templates/fta_display.html", "templates/base.html")
|
||||
template, err := web.parseFiles("templates/fta_display.html", "templates/base.html")
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
return
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2014 Team 254. All Rights Reserved.
|
||||
// Author: pat@patfairbank.com (Patrick Fairbank)
|
||||
|
||||
package main
|
||||
package web
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -3,7 +3,7 @@
|
||||
//
|
||||
// Web routes for controlling match play.
|
||||
|
||||
package main
|
||||
package web
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@@ -17,7 +17,6 @@ import (
|
||||
"net/http"
|
||||
"sort"
|
||||
"strconv"
|
||||
"text/template"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -61,8 +60,7 @@ func (web *Web) matchPlayHandler(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
template := template.New("").Funcs(web.templateHelpers)
|
||||
_, err = template.ParseFiles("templates/match_play.html", "templates/base.html")
|
||||
template, err := web.parseFiles("templates/match_play.html", "templates/base.html")
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
return
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2014 Team 254. All Rights Reserved.
|
||||
// Author: pat@patfairbank.com (Patrick Fairbank)
|
||||
|
||||
package main
|
||||
package web
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@@ -3,7 +3,7 @@
|
||||
//
|
||||
// Web routes for editing match results.
|
||||
|
||||
package main
|
||||
package web
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@@ -11,7 +11,6 @@ import (
|
||||
"github.com/gorilla/mux"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
type MatchReviewListItem struct {
|
||||
@@ -47,7 +46,7 @@ func (web *Web) matchReviewHandler(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
template, err := template.ParseFiles("templates/match_review.html", "templates/base.html")
|
||||
template, err := web.parseFiles("templates/match_review.html", "templates/base.html")
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
return
|
||||
@@ -81,7 +80,7 @@ func (web *Web) matchReviewEditGetHandler(w http.ResponseWriter, r *http.Request
|
||||
return
|
||||
}
|
||||
|
||||
template, err := template.ParseFiles("templates/edit_match_result.html", "templates/base.html")
|
||||
template, err := web.parseFiles("templates/edit_match_result.html", "templates/base.html")
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
return
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2014 Team 254. All Rights Reserved.
|
||||
// Author: pat@patfairbank.com (Patrick Fairbank)
|
||||
|
||||
package main
|
||||
package web
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@@ -3,14 +3,13 @@
|
||||
//
|
||||
// Web handlers for the pit rankings display.
|
||||
|
||||
package main
|
||||
package web
|
||||
|
||||
import (
|
||||
"github.com/Team254/cheesy-arena/model"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
// Renders the pit display which shows scrolling rankings.
|
||||
@@ -19,7 +18,7 @@ func (web *Web) pitDisplayHandler(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
template, err := template.ParseFiles("templates/pit_display.html")
|
||||
template, err := web.parseFiles("templates/pit_display.html")
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
return
|
||||
@@ -27,7 +26,7 @@ func (web *Web) pitDisplayHandler(w http.ResponseWriter, r *http.Request) {
|
||||
data := struct {
|
||||
*model.EventSettings
|
||||
}{web.arena.EventSettings}
|
||||
err = template.Execute(w, data)
|
||||
err = template.ExecuteTemplate(w, "pit_display.html", data)
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
return
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2014 Team 254. All Rights Reserved.
|
||||
// Author: pat@patfairbank.com (Patrick Fairbank)
|
||||
|
||||
package main
|
||||
package web
|
||||
|
||||
import (
|
||||
"github.com/gorilla/websocket"
|
||||
@@ -3,7 +3,7 @@
|
||||
//
|
||||
// Web handlers for the referee interface.
|
||||
|
||||
package main
|
||||
package web
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@@ -15,7 +15,6 @@ import (
|
||||
"log"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
// Renders the referee interface for assigning fouls.
|
||||
@@ -24,8 +23,7 @@ func (web *Web) refereeDisplayHandler(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
template := template.New("").Funcs(web.templateHelpers)
|
||||
_, err := template.ParseFiles("templates/referee_display.html")
|
||||
template, err := web.parseFiles("templates/referee_display.html")
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
return
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2014 Team 254. All Rights Reserved.
|
||||
// Author: pat@patfairbank.com (Patrick Fairbank)
|
||||
|
||||
package main
|
||||
package web
|
||||
|
||||
import (
|
||||
"github.com/Team254/cheesy-arena/field"
|
||||
@@ -3,7 +3,7 @@
|
||||
//
|
||||
// Web handlers for generating CSV and PDF reports.
|
||||
|
||||
package main
|
||||
package web
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@@ -12,7 +12,6 @@ import (
|
||||
"github.com/jung-kurt/gofpdf"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
// Generates a CSV-formatted report of the qualification rankings.
|
||||
@@ -29,12 +28,12 @@ func (web *Web) rankingsCsvReportHandler(w http.ResponseWriter, r *http.Request)
|
||||
|
||||
// Don't set the content type as "text/csv", as that will trigger an automatic download in the browser.
|
||||
w.Header().Set("Content-Type", "text/plain")
|
||||
template, err := template.ParseFiles("templates/rankings.csv")
|
||||
template, err := web.parseFiles("templates/rankings.csv")
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
return
|
||||
}
|
||||
err = template.Execute(w, rankings)
|
||||
err = template.ExecuteTemplate(w, "rankings.csv", rankings)
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
return
|
||||
@@ -118,12 +117,12 @@ func (web *Web) scheduleCsvReportHandler(w http.ResponseWriter, r *http.Request)
|
||||
|
||||
// Don't set the content type as "text/csv", as that will trigger an automatic download in the browser.
|
||||
w.Header().Set("Content-Type", "text/plain")
|
||||
template, err := template.ParseFiles("templates/schedule.csv")
|
||||
template, err := web.parseFiles("templates/schedule.csv")
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
return
|
||||
}
|
||||
err = template.Execute(w, matches)
|
||||
err = template.ExecuteTemplate(w, "schedule.csv", matches)
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
return
|
||||
@@ -253,12 +252,12 @@ func (web *Web) teamsCsvReportHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// Don't set the content type as "text/csv", as that will trigger an automatic download in the browser.
|
||||
w.Header().Set("Content-Type", "text/plain")
|
||||
template, err := template.ParseFiles("templates/teams.csv")
|
||||
template, err := web.parseFiles("templates/teams.csv")
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
return
|
||||
}
|
||||
err = template.Execute(w, teams)
|
||||
err = template.ExecuteTemplate(w, "teams.csv", teams)
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
return
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2014 Team 254. All Rights Reserved.
|
||||
// Author: pat@patfairbank.com (Patrick Fairbank)
|
||||
|
||||
package main
|
||||
package web
|
||||
|
||||
import (
|
||||
"github.com/Team254/cheesy-arena/game"
|
||||
@@ -3,7 +3,7 @@
|
||||
//
|
||||
// Web handlers for scoring interface.
|
||||
|
||||
package main
|
||||
package web
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@@ -14,7 +14,6 @@ import (
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
// Renders the scoring interface which enables input of scores in real-time.
|
||||
@@ -30,7 +29,7 @@ func (web *Web) scoringDisplayHandler(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
template, err := template.ParseFiles("templates/scoring_display.html", "templates/base.html")
|
||||
template, err := web.parseFiles("templates/scoring_display.html", "templates/base.html")
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
return
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2014 Team 254. All Rights Reserved.
|
||||
// Author: pat@patfairbank.com (Patrick Fairbank)
|
||||
|
||||
package main
|
||||
package web
|
||||
|
||||
import (
|
||||
"github.com/Team254/cheesy-arena/field"
|
||||
@@ -3,13 +3,12 @@
|
||||
//
|
||||
// Web routes for conducting the alliance selection process.
|
||||
|
||||
package main
|
||||
package web
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/Team254/cheesy-arena/model"
|
||||
"github.com/Team254/cheesy-arena/tournament"
|
||||
"html/template"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
@@ -227,7 +226,7 @@ func (web *Web) allianceSelectionFinalizeHandler(w http.ResponseWriter, r *http.
|
||||
}
|
||||
|
||||
func (web *Web) renderAllianceSelection(w http.ResponseWriter, r *http.Request, errorMessage string) {
|
||||
template, err := template.ParseFiles("templates/setup_alliance_selection.html", "templates/base.html")
|
||||
template, err := web.parseFiles("templates/setup_alliance_selection.html", "templates/base.html")
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
return
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2014 Team 254. All Rights Reserved.
|
||||
// Author: pat@patfairbank.com (Patrick Fairbank)
|
||||
|
||||
package main
|
||||
package web
|
||||
|
||||
import (
|
||||
"github.com/Team254/cheesy-arena/game"
|
||||
@@ -3,11 +3,10 @@
|
||||
//
|
||||
// Web routes for configuring the field components.
|
||||
|
||||
package main
|
||||
package web
|
||||
|
||||
import (
|
||||
"github.com/Team254/cheesy-arena/model"
|
||||
"html/template"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
@@ -17,7 +16,7 @@ func (web *Web) fieldGetHandler(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
template, err := template.ParseFiles("templates/setup_field.html", "templates/base.html")
|
||||
template, err := web.parseFiles("templates/setup_field.html", "templates/base.html")
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
return
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2014 Team 254. All Rights Reserved.
|
||||
// Author: pat@patfairbank.com (Patrick Fairbank)
|
||||
|
||||
package main
|
||||
package web
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -3,13 +3,12 @@
|
||||
//
|
||||
// Web routes for managing lower thirds.
|
||||
|
||||
package main
|
||||
package web
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/Team254/cheesy-arena/model"
|
||||
"github.com/mitchellh/mapstructure"
|
||||
"html/template"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
@@ -21,7 +20,7 @@ func (web *Web) lowerThirdsGetHandler(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
template, err := template.ParseFiles("templates/setup_lower_thirds.html", "templates/base.html")
|
||||
template, err := web.parseFiles("templates/setup_lower_thirds.html", "templates/base.html")
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
return
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2014 Team 254. All Rights Reserved.
|
||||
// Author: pat@patfairbank.com (Patrick Fairbank)
|
||||
|
||||
package main
|
||||
package web
|
||||
|
||||
import (
|
||||
"github.com/Team254/cheesy-arena/model"
|
||||
@@ -3,13 +3,12 @@
|
||||
//
|
||||
// Web routes for generating practice and qualification schedules.
|
||||
|
||||
package main
|
||||
package web
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/Team254/cheesy-arena/model"
|
||||
"github.com/Team254/cheesy-arena/tournament"
|
||||
"html/template"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
@@ -173,7 +172,7 @@ func (web *Web) renderSchedule(w http.ResponseWriter, r *http.Request, errorMess
|
||||
handleWebErr(w, err)
|
||||
return
|
||||
}
|
||||
template, err := template.ParseFiles("templates/setup_schedule.html", "templates/base.html")
|
||||
template, err := web.parseFiles("templates/setup_schedule.html", "templates/base.html")
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
return
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2014 Team 254. All Rights Reserved.
|
||||
// Author: pat@patfairbank.com (Patrick Fairbank)
|
||||
|
||||
package main
|
||||
package web
|
||||
|
||||
import (
|
||||
"github.com/Team254/cheesy-arena/model"
|
||||
@@ -3,12 +3,11 @@
|
||||
//
|
||||
// Web routes for configuring the event settings.
|
||||
|
||||
package main
|
||||
package web
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/Team254/cheesy-arena/model"
|
||||
"html/template"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
@@ -36,7 +35,6 @@ func (web *Web) settingsPostHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
eventSettings := web.arena.EventSettings
|
||||
eventSettings.Name = r.PostFormValue("name")
|
||||
eventSettings.Code = r.PostFormValue("code")
|
||||
match, _ := regexp.MatchString("^#([0-9A-Fa-f]{3}){1,2}$", r.PostFormValue("displayBackgroundColor"))
|
||||
if !match {
|
||||
web.renderSettings(w, r, "Display background color must be a valid hex color value.")
|
||||
@@ -91,7 +89,7 @@ func (web *Web) saveDbHandler(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
dbFile, err := os.Open(web.arena.Database.GetPath())
|
||||
dbFile, err := os.Open(web.arena.Database.Path)
|
||||
defer dbFile.Close()
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
@@ -147,17 +145,17 @@ func (web *Web) restoreDbHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// Replace the current database with the new one.
|
||||
web.arena.Database.Close()
|
||||
err = os.Remove(eventDbPath)
|
||||
err = os.Remove(web.arena.Database.Path)
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
return
|
||||
}
|
||||
err = os.Rename(tempFilePath, eventDbPath)
|
||||
err = os.Rename(tempFilePath, web.arena.Database.Path)
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
return
|
||||
}
|
||||
web.arena.Database, err = model.OpenDatabase(eventDbPath)
|
||||
web.arena.Database, err = model.OpenDatabase(web.arena.Database.Path)
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
return
|
||||
@@ -208,7 +206,7 @@ func (web *Web) clearDbHandler(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
func (web *Web) renderSettings(w http.ResponseWriter, r *http.Request, errorMessage string) {
|
||||
template, err := template.ParseFiles("templates/setup_settings.html", "templates/base.html")
|
||||
template, err := web.parseFiles("templates/setup_settings.html", "templates/base.html")
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
return
|
||||
@@ -1,11 +1,10 @@
|
||||
// Copyright 2014 Team 254. All Rights Reserved.
|
||||
// Author: pat@patfairbank.com (Patrick Fairbank)
|
||||
|
||||
package main
|
||||
package web
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"github.com/Team254/cheesy-arena/game"
|
||||
"github.com/Team254/cheesy-arena/model"
|
||||
"github.com/Team254/cheesy-arena/tournament"
|
||||
@@ -24,7 +23,6 @@ func TestSetupSettings(t *testing.T) {
|
||||
recorder := web.getHttpResponse("/setup/settings")
|
||||
assert.Equal(t, 200, recorder.Code)
|
||||
assert.Contains(t, recorder.Body.String(), "Untitled Event")
|
||||
assert.Contains(t, recorder.Body.String(), "UE")
|
||||
assert.Contains(t, recorder.Body.String(), "#00ff00")
|
||||
assert.Contains(t, recorder.Body.String(), "8")
|
||||
assert.NotContains(t, recorder.Body.String(), "tbaPublishingEnabled\" checked")
|
||||
@@ -35,7 +33,6 @@ func TestSetupSettings(t *testing.T) {
|
||||
assert.Equal(t, 302, recorder.Code)
|
||||
recorder = web.getHttpResponse("/setup/settings")
|
||||
assert.Contains(t, recorder.Body.String(), "Chezy Champs")
|
||||
assert.Contains(t, recorder.Body.String(), "CC")
|
||||
assert.Contains(t, recorder.Body.String(), "#ff00ff")
|
||||
assert.Contains(t, recorder.Body.String(), "16")
|
||||
assert.Contains(t, recorder.Body.String(), "tbaPublishingEnabled\" checked")
|
||||
@@ -109,8 +106,8 @@ func TestSetupSettingsBackupRestoreDb(t *testing.T) {
|
||||
|
||||
// Check restoring with the backup retrieved before.
|
||||
recorder = web.postFileHttpResponse("/setup/db/restore", "databaseFile", backupBody)
|
||||
fmt.Println(recorder.Body.String())
|
||||
assert.Equal(t, "Chezy Champs", web.arena.EventSettings.Name)
|
||||
|
||||
}
|
||||
|
||||
func (web *Web) postFileHttpResponse(path string, paramName string, file *bytes.Buffer) *httptest.ResponseRecorder {
|
||||
@@ -3,11 +3,10 @@
|
||||
//
|
||||
// Web routes for managing sponsor slides.
|
||||
|
||||
package main
|
||||
package web
|
||||
|
||||
import (
|
||||
"github.com/Team254/cheesy-arena/model"
|
||||
"html/template"
|
||||
"net/http"
|
||||
"strconv"
|
||||
)
|
||||
@@ -18,7 +17,7 @@ func (web *Web) sponsorSlidesGetHandler(w http.ResponseWriter, r *http.Request)
|
||||
return
|
||||
}
|
||||
|
||||
template, err := template.ParseFiles("templates/setup_sponsor_slides.html", "templates/base.html")
|
||||
template, err := web.parseFiles("templates/setup_sponsor_slides.html", "templates/base.html")
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
return
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2014 Team 254. All Rights Reserved.
|
||||
// Author: pat@patfairbank.com (Patrick Fairbank)
|
||||
|
||||
package main
|
||||
package web
|
||||
|
||||
import (
|
||||
"github.com/Team254/cheesy-arena/model"
|
||||
@@ -3,7 +3,7 @@
|
||||
//
|
||||
// Web routes for configuring the team list.
|
||||
|
||||
package main
|
||||
package web
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@@ -11,7 +11,6 @@ import (
|
||||
"github.com/Team254/cheesy-arena/model"
|
||||
"github.com/dchest/uniuri"
|
||||
"github.com/gorilla/mux"
|
||||
"html/template"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -100,7 +99,7 @@ func (web *Web) teamEditGetHandler(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
template, err := template.ParseFiles("templates/edit_team.html", "templates/base.html")
|
||||
template, err := web.parseFiles("templates/edit_team.html", "templates/base.html")
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
return
|
||||
@@ -234,7 +233,7 @@ func (web *Web) renderTeams(w http.ResponseWriter, r *http.Request, showErrorMes
|
||||
return
|
||||
}
|
||||
|
||||
template, err := template.ParseFiles("templates/setup_teams.html", "templates/base.html")
|
||||
template, err := web.parseFiles("templates/setup_teams.html", "templates/base.html")
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
return
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2014 Team 254. All Rights Reserved.
|
||||
// Author: pat@patfairbank.com (Patrick Fairbank)
|
||||
|
||||
package main
|
||||
package web
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@@ -3,7 +3,7 @@
|
||||
//
|
||||
// Configuration and functions for the event server web interface.
|
||||
|
||||
package main
|
||||
package web
|
||||
|
||||
import (
|
||||
"bitbucket.org/rj/httpauth-go"
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"github.com/gorilla/mux"
|
||||
"log"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
@@ -55,9 +56,19 @@ func NewWeb(arena *field.Arena) *Web {
|
||||
return web
|
||||
}
|
||||
|
||||
// Starts the webserver and blocks, waiting on requests. Does not return until the application exits.
|
||||
func (web *Web) ServeWebInterface(port int) {
|
||||
http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("static/"))))
|
||||
http.Handle("/", web.newHandler())
|
||||
log.Printf("Serving HTTP requests on port %d", port)
|
||||
|
||||
// Start Server
|
||||
http.ListenAndServe(fmt.Sprintf(":%d", port), nil)
|
||||
}
|
||||
|
||||
// Serves the root page of Cheesy Arena.
|
||||
func (web *Web) indexHandler(w http.ResponseWriter, r *http.Request) {
|
||||
template, err := template.ParseFiles("templates/index.html", "templates/base.html")
|
||||
template, err := web.parseFiles("templates/index.html", "templates/base.html")
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
return
|
||||
@@ -72,16 +83,6 @@ func (web *Web) indexHandler(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
// Starts the webserver and blocks, waiting on requests. Does not return until the application exits.
|
||||
func (web *Web) ServeWebInterface(port int) {
|
||||
http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("static/"))))
|
||||
http.Handle("/", web.newHandler())
|
||||
log.Printf("Serving HTTP requests on port %d", port)
|
||||
|
||||
// Start Server
|
||||
http.ListenAndServe(fmt.Sprintf(":%d", port), nil)
|
||||
}
|
||||
|
||||
// Returns true if the given user is authorized for admin operations. Used for HTTP Basic Auth.
|
||||
func (web *Web) userIsAdmin(w http.ResponseWriter, r *http.Request) bool {
|
||||
if web.arena.EventSettings.AdminPassword == "" {
|
||||
@@ -192,3 +193,14 @@ func (web *Web) newHandler() http.Handler {
|
||||
func handleWebErr(w http.ResponseWriter, err error) {
|
||||
http.Error(w, "Internal server error: "+err.Error(), 500)
|
||||
}
|
||||
|
||||
// Prepends the base directory to the template filenames.
|
||||
func (web *Web) parseFiles(filenames ...string) (*template.Template, error) {
|
||||
var paths []string
|
||||
for _, filename := range filenames {
|
||||
paths = append(paths, filepath.Join(model.BaseDir, filename))
|
||||
}
|
||||
|
||||
template := template.New("").Funcs(web.templateHelpers)
|
||||
return template.ParseFiles(paths...)
|
||||
}
|
||||
@@ -1,9 +1,10 @@
|
||||
// Copyright 2014 Team 254. All Rights Reserved.
|
||||
// Author: pat@patfairbank.com (Patrick Fairbank)
|
||||
|
||||
package main
|
||||
package web
|
||||
|
||||
import (
|
||||
"github.com/Team254/cheesy-arena/field"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
@@ -68,3 +69,8 @@ func readWebsocketMultiple(t *testing.T, ws *Websocket, count int) map[string]in
|
||||
}
|
||||
return messages
|
||||
}
|
||||
|
||||
func setupTestWeb(t *testing.T) *Web {
|
||||
arena := field.SetupTestArena(t, "web")
|
||||
return NewWeb(arena)
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
//
|
||||
// Functions for the server side of handling websockets.
|
||||
|
||||
package main
|
||||
package web
|
||||
|
||||
import (
|
||||
"github.com/gorilla/websocket"
|
||||
Reference in New Issue
Block a user