Files
cheesy-arena-lite/reports.go

341 lines
12 KiB
Go
Raw Normal View History

// Copyright 2014 Team 254. All Rights Reserved.
// Author: pat@patfairbank.com (Patrick Fairbank)
//
// Web handlers for generating CSV and PDF reports.
package main
import (
"fmt"
2014-05-26 16:39:20 -07:00
"github.com/gorilla/mux"
2015-03-21 19:16:48 -07:00
"github.com/jung-kurt/gofpdf"
"net/http"
"strconv"
"text/template"
)
2014-05-31 19:28:32 -07:00
// Generates a CSV-formatted report of the qualification rankings.
func RankingsCsvReportHandler(w http.ResponseWriter, r *http.Request) {
2015-08-22 23:33:38 -07:00
if !UserIsReader(w, r) {
return
}
2014-05-31 19:28:32 -07:00
rankings, err := db.GetAllRankings()
if err != nil {
handleWebErr(w, err)
return
}
// 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")
if err != nil {
handleWebErr(w, err)
return
}
err = template.Execute(w, rankings)
if err != nil {
handleWebErr(w, err)
return
}
}
// Generates a PDF-formatted report of the qualification rankings.
func RankingsPdfReportHandler(w http.ResponseWriter, r *http.Request) {
2015-08-22 23:33:38 -07:00
if !UserIsReader(w, r) {
return
}
2014-05-31 19:28:32 -07:00
rankings, err := db.GetAllRankings()
if err != nil {
handleWebErr(w, err)
return
}
// The widths of the table columns in mm, stored here so that they can be referenced for each row.
colWidths := map[string]float64{"Rank": 13, "Team": 23, "QA": 20, "Coop": 20, "Auto": 20,
"Container": 20, "Tote": 20, "Litter": 20, "DQ": 20, "Played": 20}
2014-05-31 19:28:32 -07:00
rowHeight := 6.5
pdf := gofpdf.New("P", "mm", "Letter", "font")
pdf.AddPage()
// Render table header row.
pdf.SetFont("Arial", "B", 10)
pdf.SetFillColor(220, 220, 220)
pdf.CellFormat(195, rowHeight, "Team Standings - "+eventSettings.Name, "", 1, "C", false, 0, "")
pdf.CellFormat(colWidths["Rank"], rowHeight, "Rank", "1", 0, "C", true, 0, "")
pdf.CellFormat(colWidths["Team"], rowHeight, "Team", "1", 0, "C", true, 0, "")
pdf.CellFormat(colWidths["QA"], rowHeight, "QA", "1", 0, "C", true, 0, "")
pdf.CellFormat(colWidths["Coop"], rowHeight, "Coop", "1", 0, "C", true, 0, "")
2014-05-31 19:28:32 -07:00
pdf.CellFormat(colWidths["Auto"], rowHeight, "Auto", "1", 0, "C", true, 0, "")
pdf.CellFormat(colWidths["Container"], rowHeight, "Container", "1", 0, "C", true, 0, "")
pdf.CellFormat(colWidths["Tote"], rowHeight, "Tote", "1", 0, "C", true, 0, "")
pdf.CellFormat(colWidths["Litter"], rowHeight, "Litter", "1", 0, "C", true, 0, "")
2014-05-31 19:28:32 -07:00
pdf.CellFormat(colWidths["DQ"], rowHeight, "DQ", "1", 0, "C", true, 0, "")
pdf.CellFormat(colWidths["Played"], rowHeight, "Played", "1", 1, "C", true, 0, "")
for _, ranking := range rankings {
// Render ranking info row.
pdf.SetFont("Arial", "B", 10)
pdf.CellFormat(colWidths["Rank"], rowHeight, strconv.Itoa(ranking.Rank), "1", 0, "C", false, 0, "")
pdf.SetFont("Arial", "", 10)
pdf.CellFormat(colWidths["Team"], rowHeight, strconv.Itoa(ranking.TeamId), "1", 0, "C", false, 0, "")
pdf.CellFormat(colWidths["QA"], rowHeight, strconv.FormatFloat(ranking.QualificationAverage, 'f', 2, 64), "1", 0, "C", false, 0, "")
pdf.CellFormat(colWidths["Coop"], rowHeight, strconv.Itoa(ranking.CoopertitionPoints), "1", 0, "C", false, 0, "")
2014-05-31 19:28:32 -07:00
pdf.CellFormat(colWidths["Auto"], rowHeight, strconv.Itoa(ranking.AutoPoints), "1", 0, "C", false, 0, "")
pdf.CellFormat(colWidths["Container"], rowHeight, strconv.Itoa(ranking.ContainerPoints), "1", 0, "C", false, 0, "")
pdf.CellFormat(colWidths["Tote"], rowHeight, strconv.Itoa(ranking.TotePoints), "1", 0, "C", false, 0, "")
pdf.CellFormat(colWidths["Litter"], rowHeight, strconv.Itoa(ranking.LitterPoints), "1", 0, "C", false, 0, "")
2014-05-31 19:28:32 -07:00
pdf.CellFormat(colWidths["DQ"], rowHeight, strconv.Itoa(ranking.Disqualifications), "1", 0, "C", false, 0, "")
pdf.CellFormat(colWidths["Played"], rowHeight, strconv.Itoa(ranking.Played), "1", 1, "C", false, 0, "")
}
// Write out the PDF file as the HTTP response.
w.Header().Set("Content-Type", "application/pdf")
err = pdf.Output(w)
if err != nil {
handleWebErr(w, err)
return
}
}
2014-05-26 16:39:20 -07:00
// Generates a CSV-formatted report of the match schedule.
func ScheduleCsvReportHandler(w http.ResponseWriter, r *http.Request) {
2015-08-22 23:33:38 -07:00
if !UserIsReader(w, r) {
return
}
2014-05-26 16:39:20 -07:00
vars := mux.Vars(r)
matches, err := db.GetMatchesByType(vars["type"])
if err != nil {
handleWebErr(w, err)
return
}
// 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")
if err != nil {
handleWebErr(w, err)
return
}
err = template.Execute(w, matches)
if err != nil {
handleWebErr(w, err)
return
}
}
// Generates a PDF-formatted report of the match schedule.
func SchedulePdfReportHandler(w http.ResponseWriter, r *http.Request) {
2015-08-22 23:33:38 -07:00
if !UserIsReader(w, r) {
return
}
2014-05-26 16:39:20 -07:00
vars := mux.Vars(r)
matches, err := db.GetMatchesByType(vars["type"])
if err != nil {
handleWebErr(w, err)
return
}
teams, err := db.GetAllTeams()
if err != nil {
handleWebErr(w, err)
return
}
matchesPerTeam := 0
if len(teams) > 0 {
matchesPerTeam = len(matches) * teamsPerMatch / len(teams)
}
// The widths of the table columns in mm, stored here so that they can be referenced for each row.
colWidths := map[string]float64{"Time": 35, "Type": 25, "Match": 15, "Team": 20}
rowHeight := 6.5
pdf := gofpdf.New("P", "mm", "Letter", "font")
pdf.AddPage()
// Render table header row.
pdf.SetFont("Arial", "B", 10)
pdf.SetFillColor(220, 220, 220)
pdf.CellFormat(195, rowHeight, "Match Schedule - "+eventSettings.Name, "", 1, "C", false, 0, "")
pdf.CellFormat(colWidths["Time"], rowHeight, "Time", "1", 0, "C", true, 0, "")
pdf.CellFormat(colWidths["Type"], rowHeight, "Type", "1", 0, "C", true, 0, "")
pdf.CellFormat(colWidths["Match"], rowHeight, "Match", "1", 0, "C", true, 0, "")
pdf.CellFormat(colWidths["Team"], rowHeight, "Red 1", "1", 0, "C", true, 0, "")
pdf.CellFormat(colWidths["Team"], rowHeight, "Red 2", "1", 0, "C", true, 0, "")
pdf.CellFormat(colWidths["Team"], rowHeight, "Red 3", "1", 0, "C", true, 0, "")
pdf.CellFormat(colWidths["Team"], rowHeight, "Blue 1", "1", 0, "C", true, 0, "")
pdf.CellFormat(colWidths["Team"], rowHeight, "Blue 2", "1", 0, "C", true, 0, "")
pdf.CellFormat(colWidths["Team"], rowHeight, "Blue 3", "1", 1, "C", true, 0, "")
pdf.SetFont("Arial", "", 10)
for _, match := range matches {
height := rowHeight
borderStr := "1"
alignStr := "CM"
surrogate := false
if match.Red1IsSurrogate || match.Red2IsSurrogate || match.Red3IsSurrogate ||
match.Blue1IsSurrogate || match.Blue2IsSurrogate || match.Blue3IsSurrogate {
// If the match contains surrogates, the row needs to be taller to fit some text beneath team numbers.
height = 5.0
borderStr = "LTR"
alignStr = "CB"
surrogate = true
}
2014-06-08 22:58:47 -07:00
// Capitalize match types.
2014-07-27 16:41:09 -07:00
matchType := match.CapitalizedType()
2014-06-08 22:58:47 -07:00
formatTeam := func(teamId int) string {
if teamId == 0 {
return ""
} else {
return strconv.Itoa(teamId)
}
}
2014-05-26 16:39:20 -07:00
// Render match info row.
pdf.CellFormat(colWidths["Time"], height, match.Time.Local().Format("Mon 1/02 03:04 PM"), borderStr, 0, alignStr, false, 0, "")
2014-06-08 22:58:47 -07:00
pdf.CellFormat(colWidths["Type"], height, matchType, borderStr, 0, alignStr, false, 0, "")
2014-05-26 16:39:20 -07:00
pdf.CellFormat(colWidths["Match"], height, match.DisplayName, borderStr, 0, alignStr, false, 0, "")
pdf.CellFormat(colWidths["Team"], height, formatTeam(match.Red1), borderStr, 0, alignStr, false, 0, "")
pdf.CellFormat(colWidths["Team"], height, formatTeam(match.Red2), borderStr, 0, alignStr, false, 0, "")
pdf.CellFormat(colWidths["Team"], height, formatTeam(match.Red3), borderStr, 0, alignStr, false, 0, "")
pdf.CellFormat(colWidths["Team"], height, formatTeam(match.Blue1), borderStr, 0, alignStr, false, 0, "")
pdf.CellFormat(colWidths["Team"], height, formatTeam(match.Blue2), borderStr, 0, alignStr, false, 0, "")
pdf.CellFormat(colWidths["Team"], height, formatTeam(match.Blue3), borderStr, 1, alignStr, false, 0, "")
2014-05-26 16:39:20 -07:00
if surrogate {
// Render the text that indicates which teams are surrogates.
height := 4.0
pdf.SetFont("Arial", "", 8)
pdf.CellFormat(colWidths["Time"], height, "", "LBR", 0, "C", false, 0, "")
pdf.CellFormat(colWidths["Type"], height, "", "LBR", 0, "C", false, 0, "")
pdf.CellFormat(colWidths["Match"], height, "", "LBR", 0, "C", false, 0, "")
pdf.CellFormat(colWidths["Team"], height, surrogateText(match.Red1IsSurrogate), "LBR", 0, "CT", false, 0, "")
pdf.CellFormat(colWidths["Team"], height, surrogateText(match.Red2IsSurrogate), "LBR", 0, "CT", false, 0, "")
pdf.CellFormat(colWidths["Team"], height, surrogateText(match.Red3IsSurrogate), "LBR", 0, "CT", false, 0, "")
pdf.CellFormat(colWidths["Team"], height, surrogateText(match.Blue1IsSurrogate), "LBR", 0, "CT", false, 0, "")
pdf.CellFormat(colWidths["Team"], height, surrogateText(match.Blue2IsSurrogate), "LBR", 0, "CT", false, 0, "")
pdf.CellFormat(colWidths["Team"], height, surrogateText(match.Blue3IsSurrogate), "LBR", 1, "CT", false, 0, "")
pdf.SetFont("Arial", "", 10)
}
}
2014-06-02 23:52:48 -07:00
if vars["type"] != "elimination" {
// Render some summary info at the bottom.
pdf.CellFormat(195, 10, fmt.Sprintf("Matches Per Team: %d", matchesPerTeam), "", 1, "L", false, 0, "")
}
2014-05-26 16:39:20 -07:00
// Write out the PDF file as the HTTP response.
w.Header().Set("Content-Type", "application/pdf")
err = pdf.Output(w)
if err != nil {
handleWebErr(w, err)
return
}
}
// Generates a CSV-formatted report of the team list.
func TeamsCsvReportHandler(w http.ResponseWriter, r *http.Request) {
2015-08-22 23:33:38 -07:00
if !UserIsReader(w, r) {
return
}
teams, err := db.GetAllTeams()
if err != nil {
handleWebErr(w, err)
return
}
2014-05-26 16:39:20 -07:00
// 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")
if err != nil {
handleWebErr(w, err)
return
}
err = template.Execute(w, teams)
if err != nil {
handleWebErr(w, err)
return
}
}
2014-05-26 16:39:20 -07:00
// Generates a PDF-formatted report of the team list.
func TeamsPdfReportHandler(w http.ResponseWriter, r *http.Request) {
2015-08-22 23:33:38 -07:00
if !UserIsReader(w, r) {
return
}
teams, err := db.GetAllTeams()
if err != nil {
handleWebErr(w, err)
return
}
2014-05-26 16:39:20 -07:00
// The widths of the table columns in mm, stored here so that they can be referenced for each row.
colWidths := map[string]float64{"Id": 12, "Name": 80, "Location": 80, "RookieYear": 23}
rowHeight := 6.5
pdf := gofpdf.New("P", "mm", "Letter", "font")
pdf.AddPage()
pdf.SetFont("Arial", "B", 10)
pdf.SetFillColor(220, 220, 220)
2014-05-26 16:39:20 -07:00
// Render table header row.
pdf.CellFormat(195, rowHeight, "Team List - "+eventSettings.Name, "", 1, "C", false, 0, "")
pdf.CellFormat(colWidths["Id"], rowHeight, "Team", "1", 0, "C", true, 0, "")
pdf.CellFormat(colWidths["Name"], rowHeight, "Name", "1", 0, "C", true, 0, "")
pdf.CellFormat(colWidths["Location"], rowHeight, "Location", "1", 0, "C", true, 0, "")
pdf.CellFormat(colWidths["RookieYear"], rowHeight, "Rookie Year", "1", 1, "C", true, 0, "")
pdf.SetFont("Arial", "", 10)
for _, team := range teams {
2014-05-26 16:39:20 -07:00
// Render team info row.
pdf.CellFormat(colWidths["Id"], rowHeight, strconv.Itoa(team.Id), "1", 0, "L", false, 0, "")
pdf.CellFormat(colWidths["Name"], rowHeight, team.Nickname, "1", 0, "L", false, 0, "")
location := fmt.Sprintf("%s, %s, %s", team.City, team.StateProv, team.Country)
pdf.CellFormat(colWidths["Location"], rowHeight, location, "1", 0, "L", false, 0, "")
pdf.CellFormat(colWidths["RookieYear"], rowHeight, strconv.Itoa(team.RookieYear), "1", 1, "L", false, 0, "")
}
2014-05-26 16:39:20 -07:00
// Write out the PDF file as the HTTP response.
w.Header().Set("Content-Type", "application/pdf")
err = pdf.Output(w)
if err != nil {
handleWebErr(w, err)
return
}
}
2014-05-26 16:39:20 -07:00
2014-08-17 16:30:30 -07:00
// Generates a CSV-formatted report of the WPA keys, for import into the radio kiosk.
func WpaKeysCsvReportHandler(w http.ResponseWriter, r *http.Request) {
2015-08-22 23:33:38 -07:00
if !UserIsAdmin(w, r) {
return
}
2014-08-17 16:30:30 -07:00
teams, err := db.GetAllTeams()
if err != nil {
handleWebErr(w, err)
return
}
w.Header().Set("Content-Type", "text/csv")
w.Header().Set("Content-Disposition", "attachment; filename=wpa_keys.csv")
for _, team := range teams {
_, err := w.Write([]byte(fmt.Sprintf("%d,%s\r\n", team.Id, team.WpaKey)))
if err != nil {
handleWebErr(w, err)
return
}
}
}
2014-05-26 16:39:20 -07:00
// Returns the text to display if a team is a surrogate.
func surrogateText(isSurrogate bool) string {
if isSurrogate {
return "(surrogate)"
} else {
return ""
}
}