blob: a785e187f56c0721f8c5ec6ba3fdd272be727a04 [file] [log] [blame]
Philipp Schradercdb5cfc2022-02-20 14:57:07 -08001package requests
2
3import (
Philipp Schraderfae8a7e2022-03-13 22:51:54 -07004 "encoding/base64"
Philipp Schraderd3fac192022-03-02 20:35:46 -08005 "errors"
Philipp Schradercdb5cfc2022-02-20 14:57:07 -08006 "fmt"
7 "io"
Philipp Schraderfae8a7e2022-03-13 22:51:54 -07008 "log"
Philipp Schradercdb5cfc2022-02-20 14:57:07 -08009 "net/http"
Emily Markovabf24c9e2023-02-08 20:31:11 -080010 "sort"
Philipp Schraderd3fac192022-03-02 20:35:46 -080011 "strconv"
12 "strings"
Philipp Schradercdb5cfc2022-02-20 14:57:07 -080013
Philipp Schrader8747f1b2022-02-23 23:56:22 -080014 "github.com/frc971/971-Robot-Code/scouting/db"
Philipp Schradercdb5cfc2022-02-20 14:57:07 -080015 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/error_response"
Emily Markova290147d2023-03-03 22:40:06 -080016 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_2023_data_scouting"
17 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_2023_data_scouting_response"
Filip Kujawaf882e022022-12-14 13:14:08 -080018 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_all_driver_rankings"
19 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_all_driver_rankings_response"
Philipp Schradercbf5c6a2022-02-27 23:25:19 -080020 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_all_matches"
21 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_all_matches_response"
Filip Kujawaf882e022022-12-14 13:14:08 -080022 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_all_notes"
23 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_all_notes_response"
Philipp Schraderacf96232022-03-01 22:03:30 -080024 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_data_scouting"
25 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_data_scouting_response"
Alex Perry81f96ba2022-03-13 18:26:19 -070026 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_notes_for_team"
27 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_notes_for_team_response"
Milo Lin1d59f0c2022-06-22 20:30:58 -070028 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_shift_schedule"
29 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_shift_schedule_response"
Sabina Leaver759090b2023-01-14 20:42:56 -080030 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_actions"
31 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_actions_response"
Philipp Schradercdb5cfc2022-02-20 14:57:07 -080032 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_data_scouting"
Philipp Schrader30005e42022-03-06 13:53:58 -080033 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_data_scouting_response"
Filip Kujawa210a03b2022-11-24 14:41:11 -080034 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_driver_ranking"
35 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_driver_ranking_response"
Alex Perry81f96ba2022-03-13 18:26:19 -070036 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_notes"
37 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_notes_response"
Milo Lin1d59f0c2022-06-22 20:30:58 -070038 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_shift_schedule"
39 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_shift_schedule_response"
Philipp Schradercdb5cfc2022-02-20 14:57:07 -080040 "github.com/frc971/971-Robot-Code/scouting/webserver/server"
41 flatbuffers "github.com/google/flatbuffers/go"
42)
43
Philipp Schradercbf5c6a2022-02-27 23:25:19 -080044type SubmitDataScouting = submit_data_scouting.SubmitDataScouting
Philipp Schrader30005e42022-03-06 13:53:58 -080045type SubmitDataScoutingResponseT = submit_data_scouting_response.SubmitDataScoutingResponseT
Philipp Schradercbf5c6a2022-02-27 23:25:19 -080046type RequestAllMatches = request_all_matches.RequestAllMatches
47type RequestAllMatchesResponseT = request_all_matches_response.RequestAllMatchesResponseT
Filip Kujawaf882e022022-12-14 13:14:08 -080048type RequestAllDriverRankings = request_all_driver_rankings.RequestAllDriverRankings
49type RequestAllDriverRankingsResponseT = request_all_driver_rankings_response.RequestAllDriverRankingsResponseT
50type RequestAllNotes = request_all_notes.RequestAllNotes
51type RequestAllNotesResponseT = request_all_notes_response.RequestAllNotesResponseT
Philipp Schraderacf96232022-03-01 22:03:30 -080052type RequestDataScouting = request_data_scouting.RequestDataScouting
53type RequestDataScoutingResponseT = request_data_scouting_response.RequestDataScoutingResponseT
Emily Markova290147d2023-03-03 22:40:06 -080054type Request2023DataScouting = request_2023_data_scouting.Request2023DataScouting
55type Request2023DataScoutingResponseT = request_2023_data_scouting_response.Request2023DataScoutingResponseT
Alex Perry81f96ba2022-03-13 18:26:19 -070056type SubmitNotes = submit_notes.SubmitNotes
57type SubmitNotesResponseT = submit_notes_response.SubmitNotesResponseT
58type RequestNotesForTeam = request_notes_for_team.RequestNotesForTeam
59type RequestNotesForTeamResponseT = request_notes_for_team_response.RequestNotesForTeamResponseT
Milo Lin1d59f0c2022-06-22 20:30:58 -070060type RequestShiftSchedule = request_shift_schedule.RequestShiftSchedule
61type RequestShiftScheduleResponseT = request_shift_schedule_response.RequestShiftScheduleResponseT
62type SubmitShiftSchedule = submit_shift_schedule.SubmitShiftSchedule
63type SubmitShiftScheduleResponseT = submit_shift_schedule_response.SubmitShiftScheduleResponseT
Filip Kujawa210a03b2022-11-24 14:41:11 -080064type SubmitDriverRanking = submit_driver_ranking.SubmitDriverRanking
65type SubmitDriverRankingResponseT = submit_driver_ranking_response.SubmitDriverRankingResponseT
Sabina Leaver759090b2023-01-14 20:42:56 -080066type SubmitActions = submit_actions.SubmitActions
67type SubmitActionsResponseT = submit_actions_response.SubmitActionsResponseT
Philipp Schradercbf5c6a2022-02-27 23:25:19 -080068
Philipp Schrader8747f1b2022-02-23 23:56:22 -080069// The interface we expect the database abstraction to conform to.
70// We use an interface here because it makes unit testing easier.
71type Database interface {
Emily Markovabf24c9e2023-02-08 20:31:11 -080072 AddToMatch(db.TeamMatch) error
Milo Lin1d59f0c2022-06-22 20:30:58 -070073 AddToShift(db.Shift) error
Philipp Schrader8747f1b2022-02-23 23:56:22 -080074 AddToStats(db.Stats) error
Emily Markova290147d2023-03-03 22:40:06 -080075 AddToStats2023(db.Stats2023) error
Emily Markovabf24c9e2023-02-08 20:31:11 -080076 ReturnMatches() ([]db.TeamMatch, error)
Filip Kujawaf882e022022-12-14 13:14:08 -080077 ReturnAllNotes() ([]db.NotesData, error)
78 ReturnAllDriverRankings() ([]db.DriverRankingData, error)
Milo Lin1d59f0c2022-06-22 20:30:58 -070079 ReturnAllShifts() ([]db.Shift, error)
Philipp Schrader8747f1b2022-02-23 23:56:22 -080080 ReturnStats() ([]db.Stats, error)
Emily Markova290147d2023-03-03 22:40:06 -080081 ReturnStats2023() ([]db.Stats2023, error)
Philipp Schrader0f7b6362023-03-11 14:02:48 -080082 ReturnStats2023ForTeam(teamNumber string, matchNumber int32, setNumber int32, compLevel string) ([]db.Stats2023, error)
Milo Lin1d59f0c2022-06-22 20:30:58 -070083 QueryAllShifts(int) ([]db.Shift, error)
Philipp Schrader8747f1b2022-02-23 23:56:22 -080084 QueryStats(int) ([]db.Stats, error)
Philipp Schradereecb8962022-06-01 21:02:42 -070085 QueryNotes(int32) ([]string, error)
Filip Kujawaf947cb42022-11-21 10:00:30 -080086 AddNotes(db.NotesData) error
Filip Kujawa210a03b2022-11-24 14:41:11 -080087 AddDriverRanking(db.DriverRankingData) error
Philipp Schrader8747f1b2022-02-23 23:56:22 -080088}
89
Philipp Schradercdb5cfc2022-02-20 14:57:07 -080090// Handles unknown requests. Just returns a 404.
91func unknown(w http.ResponseWriter, req *http.Request) {
92 w.WriteHeader(http.StatusNotFound)
93}
94
95func respondWithError(w http.ResponseWriter, statusCode int, errorMessage string) {
96 builder := flatbuffers.NewBuilder(1024)
97 builder.Finish((&error_response.ErrorResponseT{
98 ErrorMessage: errorMessage,
99 }).Pack(builder))
100 w.WriteHeader(statusCode)
101 w.Write(builder.FinishedBytes())
102}
103
104func respondNotImplemented(w http.ResponseWriter) {
105 respondWithError(w, http.StatusNotImplemented, "")
106}
107
Philipp Schraderb7e75932022-03-26 16:18:34 -0700108func parseRequest[T interface{}](w http.ResponseWriter, buf []byte, requestName string, parser func([]byte, flatbuffers.UOffsetT) *T) (*T, bool) {
Philipp Schradercdb5cfc2022-02-20 14:57:07 -0800109 success := true
110 defer func() {
111 if r := recover(); r != nil {
Philipp Schraderb7e75932022-03-26 16:18:34 -0700112 respondWithError(w, http.StatusBadRequest, fmt.Sprintf("Failed to parse %s: %v", requestName, r))
Philipp Schradercdb5cfc2022-02-20 14:57:07 -0800113 success = false
114 }
115 }()
Philipp Schraderb7e75932022-03-26 16:18:34 -0700116 result := parser(buf, 0)
Philipp Schradercdb5cfc2022-02-20 14:57:07 -0800117 return result, success
118}
119
Philipp Schraderfae8a7e2022-03-13 22:51:54 -0700120// Parses the authorization information that the browser inserts into the
121// headers. The authorization follows this format:
122//
Philipp Schrader35bb1532023-03-05 13:49:12 -0800123// req.Headers["Authorization"] = []string{"Basic <base64 encoded username:password>"}
Philipp Schraderfae8a7e2022-03-13 22:51:54 -0700124func parseUsername(req *http.Request) string {
125 auth, ok := req.Header["Authorization"]
126 if !ok {
127 return "unknown"
128 }
129
130 parts := strings.Split(auth[0], " ")
131 if !(len(parts) == 2 && parts[0] == "Basic") {
132 return "unknown"
133 }
134
135 info, err := base64.StdEncoding.DecodeString(parts[1])
136 if err != nil {
137 log.Println("ERROR: Failed to parse Basic authentication.")
138 return "unknown"
139 }
140
141 loginParts := strings.Split(string(info), ":")
142 if len(loginParts) != 2 {
143 return "unknown"
144 }
145 return loginParts[0]
146}
147
Philipp Schradercdb5cfc2022-02-20 14:57:07 -0800148// Handles a SubmitDataScouting request.
Philipp Schrader8747f1b2022-02-23 23:56:22 -0800149type submitDataScoutingHandler struct {
150 db Database
151}
152
153func (handler submitDataScoutingHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
Philipp Schraderfae8a7e2022-03-13 22:51:54 -0700154 // Get the username of the person submitting the data.
155 username := parseUsername(req)
Philipp Schraderfae8a7e2022-03-13 22:51:54 -0700156
Philipp Schradercdb5cfc2022-02-20 14:57:07 -0800157 requestBytes, err := io.ReadAll(req.Body)
158 if err != nil {
159 respondWithError(w, http.StatusBadRequest, fmt.Sprint("Failed to read request bytes:", err))
160 return
161 }
162
Philipp Schraderb7e75932022-03-26 16:18:34 -0700163 request, success := parseRequest[SubmitDataScouting](w, requestBytes, "SubmitDataScouting", submit_data_scouting.GetRootAsSubmitDataScouting)
Philipp Schradercdb5cfc2022-02-20 14:57:07 -0800164 if !success {
165 return
166 }
167
Philipp Schraderd7b6eba2022-03-18 22:21:25 -0700168 log.Println("Got data scouting data for match", request.Match(), "team", request.Team(), "from", username)
169
Philipp Schrader30005e42022-03-06 13:53:58 -0800170 stats := db.Stats{
Philipp Schraderfee07e12022-03-17 22:19:47 -0700171 TeamNumber: request.Team(),
172 MatchNumber: request.Match(),
Philipp Schrader30b4a682022-04-16 14:36:17 -0700173 SetNumber: request.SetNumber(),
Philipp Schrader4535b7e2022-04-08 20:27:00 -0700174 CompLevel: string(request.CompLevel()),
Philipp Schraderfee07e12022-03-17 22:19:47 -0700175 StartingQuadrant: request.StartingQuadrant(),
176 AutoBallPickedUp: [5]bool{
177 request.AutoBall1(), request.AutoBall2(), request.AutoBall3(),
178 request.AutoBall4(), request.AutoBall5(),
179 },
Philipp Schraderfa45d742022-03-18 19:29:05 -0700180 ShotsMissedAuto: request.MissedShotsAuto(),
181 UpperGoalAuto: request.UpperGoalAuto(),
182 LowerGoalAuto: request.LowerGoalAuto(),
183 ShotsMissed: request.MissedShotsTele(),
184 UpperGoalShots: request.UpperGoalTele(),
185 LowerGoalShots: request.LowerGoalTele(),
186 PlayedDefense: request.DefenseRating(),
187 DefenseReceivedScore: request.DefenseReceivedRating(),
188 Climbing: int32(request.ClimbLevel()),
189 CollectedBy: username,
190 Comment: string(request.Comment()),
Philipp Schrader30005e42022-03-06 13:53:58 -0800191 }
Philipp Schradercdb5cfc2022-02-20 14:57:07 -0800192
Philipp Schraderfee07e12022-03-17 22:19:47 -0700193 // Do some error checking.
194 if stats.StartingQuadrant < 1 || stats.StartingQuadrant > 4 {
195 respondWithError(w, http.StatusBadRequest, fmt.Sprint(
196 "Invalid starting_quadrant field value of ", stats.StartingQuadrant))
197 return
198 }
199
Philipp Schrader30005e42022-03-06 13:53:58 -0800200 err = handler.db.AddToStats(stats)
201 if err != nil {
202 respondWithError(w, http.StatusInternalServerError, fmt.Sprint("Failed to submit datascouting data: ", err))
Philipp Schraderfee07e12022-03-17 22:19:47 -0700203 return
Philipp Schrader30005e42022-03-06 13:53:58 -0800204 }
205
206 builder := flatbuffers.NewBuilder(50 * 1024)
207 builder.Finish((&SubmitDataScoutingResponseT{}).Pack(builder))
208 w.Write(builder.FinishedBytes())
Philipp Schradercdb5cfc2022-02-20 14:57:07 -0800209}
210
Philipp Schradercbf5c6a2022-02-27 23:25:19 -0800211// Handles a RequestAllMaches request.
212type requestAllMatchesHandler struct {
213 db Database
214}
215
Philipp Schrader0f7b6362023-03-11 14:02:48 -0800216// Change structure of match objects in the database(1 per team) to
217// the old match structure(1 per match) that the webserver uses.
218// We use the information in this struct to identify which match object
219// corresponds to which old match structure object.
220type MatchAssemblyKey struct {
221 MatchNumber int32
222 SetNumber int32
223 CompLevel string
224}
225
Emily Markovabf24c9e2023-02-08 20:31:11 -0800226func findIndexInList(list []string, comp_level string) (int, error) {
227 for index, value := range list {
228 if value == comp_level {
229 return index, nil
230 }
231 }
232 return -1, errors.New(fmt.Sprint("Failed to find comp level ", comp_level, " in list ", list))
233}
234
Emily Markovab8551572023-03-22 19:49:39 -0700235func (handler requestAllMatchesHandler) teamHasBeenDataScouted(key MatchAssemblyKey, teamNumber string) (bool, error) {
Philipp Schrader0f7b6362023-03-11 14:02:48 -0800236 stats, err := handler.db.ReturnStats2023ForTeam(
Emily Markovab8551572023-03-22 19:49:39 -0700237 teamNumber, key.MatchNumber, key.SetNumber, key.CompLevel)
Philipp Schrader0f7b6362023-03-11 14:02:48 -0800238 if err != nil {
239 return false, err
240 }
241 return (len(stats) > 0), nil
242}
243
Philipp Schradercbf5c6a2022-02-27 23:25:19 -0800244func (handler requestAllMatchesHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
245 requestBytes, err := io.ReadAll(req.Body)
246 if err != nil {
247 respondWithError(w, http.StatusBadRequest, fmt.Sprint("Failed to read request bytes:", err))
248 return
249 }
250
Philipp Schraderb7e75932022-03-26 16:18:34 -0700251 _, success := parseRequest(w, requestBytes, "RequestAllMatches", request_all_matches.GetRootAsRequestAllMatches)
Philipp Schradercbf5c6a2022-02-27 23:25:19 -0800252 if !success {
253 return
254 }
255
256 matches, err := handler.db.ReturnMatches()
257 if err != nil {
Philipp Schraderfae8a7e2022-03-13 22:51:54 -0700258 respondWithError(w, http.StatusInternalServerError, fmt.Sprint("Failed to query database: ", err))
Philipp Schrader2e7eb0002022-03-02 22:52:39 -0800259 return
Philipp Schradercbf5c6a2022-02-27 23:25:19 -0800260 }
261
Philipp Schrader0f7b6362023-03-11 14:02:48 -0800262 assembledMatches := map[MatchAssemblyKey]request_all_matches_response.MatchT{}
Emily Markovabf24c9e2023-02-08 20:31:11 -0800263
Philipp Schradercbf5c6a2022-02-27 23:25:19 -0800264 for _, match := range matches {
Philipp Schrader0f7b6362023-03-11 14:02:48 -0800265 key := MatchAssemblyKey{match.MatchNumber, match.SetNumber, match.CompLevel}
266
267 // Retrieve the converted match structure we have assembled so
268 // far. If we haven't started assembling one yet, then start a
269 // new one.
Emily Markovabf24c9e2023-02-08 20:31:11 -0800270 entry, ok := assembledMatches[key]
271 if !ok {
272 entry = request_all_matches_response.MatchT{
273 MatchNumber: match.MatchNumber,
274 SetNumber: match.SetNumber,
275 CompLevel: match.CompLevel,
Philipp Schrader0f7b6362023-03-11 14:02:48 -0800276 DataScouted: &request_all_matches_response.ScoutedLevelT{},
Emily Markovabf24c9e2023-02-08 20:31:11 -0800277 }
278 }
Philipp Schrader0f7b6362023-03-11 14:02:48 -0800279
Emily Markovab8551572023-03-22 19:49:39 -0700280 var team *string
Philipp Schrader0f7b6362023-03-11 14:02:48 -0800281 var dataScoutedTeam *bool
282
283 // Fill in the field for the match that we have in in the
284 // database. In the database, each match row only has 1 team
285 // number.
Emily Markovabf24c9e2023-02-08 20:31:11 -0800286 switch match.Alliance {
287 case "R":
288 switch match.AlliancePosition {
289 case 1:
Philipp Schrader0f7b6362023-03-11 14:02:48 -0800290 team = &entry.R1
291 dataScoutedTeam = &entry.DataScouted.R1
Emily Markovabf24c9e2023-02-08 20:31:11 -0800292 case 2:
Philipp Schrader0f7b6362023-03-11 14:02:48 -0800293 team = &entry.R2
294 dataScoutedTeam = &entry.DataScouted.R2
Emily Markovabf24c9e2023-02-08 20:31:11 -0800295 case 3:
Philipp Schrader0f7b6362023-03-11 14:02:48 -0800296 team = &entry.R3
297 dataScoutedTeam = &entry.DataScouted.R3
Emily Markovabf24c9e2023-02-08 20:31:11 -0800298 default:
299 respondWithError(w, http.StatusInternalServerError, fmt.Sprint("Unknown red position ", strconv.Itoa(int(match.AlliancePosition)), " in match ", strconv.Itoa(int(match.MatchNumber))))
300 return
301 }
302 case "B":
303 switch match.AlliancePosition {
304 case 1:
Philipp Schrader0f7b6362023-03-11 14:02:48 -0800305 team = &entry.B1
306 dataScoutedTeam = &entry.DataScouted.B1
Emily Markovabf24c9e2023-02-08 20:31:11 -0800307 case 2:
Philipp Schrader0f7b6362023-03-11 14:02:48 -0800308 team = &entry.B2
309 dataScoutedTeam = &entry.DataScouted.B2
Emily Markovabf24c9e2023-02-08 20:31:11 -0800310 case 3:
Philipp Schrader0f7b6362023-03-11 14:02:48 -0800311 team = &entry.B3
312 dataScoutedTeam = &entry.DataScouted.B3
Emily Markovabf24c9e2023-02-08 20:31:11 -0800313 default:
314 respondWithError(w, http.StatusInternalServerError, fmt.Sprint("Unknown blue position ", strconv.Itoa(int(match.AlliancePosition)), " in match ", strconv.Itoa(int(match.MatchNumber))))
315 return
316 }
317 default:
318 respondWithError(w, http.StatusInternalServerError, fmt.Sprint("Unknown alliance ", match.Alliance, " in match ", strconv.Itoa(int(match.AlliancePosition))))
319 return
320 }
Philipp Schrader0f7b6362023-03-11 14:02:48 -0800321
322 *team = match.TeamNumber
323
324 // Figure out if this team has been data scouted already.
325 *dataScoutedTeam, err = handler.teamHasBeenDataScouted(key, match.TeamNumber)
326 if err != nil {
327 respondWithError(w, http.StatusInternalServerError, fmt.Sprint(
328 "Failed to determine data scouting status for team ",
329 strconv.Itoa(int(match.AlliancePosition)),
330 " in match ",
331 strconv.Itoa(int(match.MatchNumber)),
332 err))
333 return
334 }
335
Emily Markovabf24c9e2023-02-08 20:31:11 -0800336 assembledMatches[key] = entry
337 }
338
339 var response RequestAllMatchesResponseT
340 for _, match := range assembledMatches {
341 copied_match := match
342 response.MatchList = append(response.MatchList, &copied_match)
343 }
344
345 var MATCH_TYPE_ORDERING = []string{"qm", "ef", "qf", "sf", "f"}
346
347 err = nil
348 sort.Slice(response.MatchList, func(i, j int) bool {
349 if err != nil {
350 return false
351 }
352 a := response.MatchList[i]
353 b := response.MatchList[j]
354
Emily Markovaabcac6e2023-02-18 17:50:03 -0800355 aMatchTypeIndex, err2 := findIndexInList(MATCH_TYPE_ORDERING, a.CompLevel)
356 if err2 != nil {
357 err = errors.New(fmt.Sprint("Comp level ", a.CompLevel, " not found in sorting list ", MATCH_TYPE_ORDERING, " : ", err2))
Emily Markovabf24c9e2023-02-08 20:31:11 -0800358 return false
359 }
Emily Markovaabcac6e2023-02-18 17:50:03 -0800360 bMatchTypeIndex, err2 := findIndexInList(MATCH_TYPE_ORDERING, b.CompLevel)
361 if err2 != nil {
362 err = errors.New(fmt.Sprint("Comp level ", b.CompLevel, " not found in sorting list ", MATCH_TYPE_ORDERING, " : ", err2))
Emily Markovabf24c9e2023-02-08 20:31:11 -0800363 return false
364 }
365
366 if aMatchTypeIndex < bMatchTypeIndex {
367 return true
368 }
369 if aMatchTypeIndex > bMatchTypeIndex {
370 return false
371 }
372
373 // Then sort by match number. E.g. in semi finals, all match 1 rounds
374 // are done first. Then come match 2 rounds. And then, if necessary,
375 // the match 3 rounds.
376 aMatchNumber := a.MatchNumber
377 bMatchNumber := b.MatchNumber
378 if aMatchNumber < bMatchNumber {
379 return true
380 }
381 if aMatchNumber > bMatchNumber {
382 return false
383 }
384 // Lastly, sort by set number. I.e. Semi Final 1 Match 1 happens first.
385 // Then comes Semi Final 2 Match 1. Then comes Semi Final 1 Match 2. Then
386 // Semi Final 2 Match 2.
387 aSetNumber := a.SetNumber
388 bSetNumber := b.SetNumber
389 if aSetNumber < bSetNumber {
390 return true
391 }
392 if aSetNumber > bSetNumber {
393 return false
394 }
395 return true
396 })
397
398 if err != nil {
399 // check if error happened during sorting and notify webpage if that
400 respondWithError(w, http.StatusInternalServerError, fmt.Sprint(err))
401 return
Philipp Schradercbf5c6a2022-02-27 23:25:19 -0800402 }
403
404 builder := flatbuffers.NewBuilder(50 * 1024)
405 builder.Finish((&response).Pack(builder))
406 w.Write(builder.FinishedBytes())
407}
408
Philipp Schraderacf96232022-03-01 22:03:30 -0800409// Handles a RequestDataScouting request.
410type requestDataScoutingHandler struct {
411 db Database
412}
413
414func (handler requestDataScoutingHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
415 requestBytes, err := io.ReadAll(req.Body)
416 if err != nil {
417 respondWithError(w, http.StatusBadRequest, fmt.Sprint("Failed to read request bytes:", err))
418 return
419 }
420
Philipp Schraderb7e75932022-03-26 16:18:34 -0700421 _, success := parseRequest(w, requestBytes, "RequestDataScouting", request_data_scouting.GetRootAsRequestDataScouting)
Philipp Schraderacf96232022-03-01 22:03:30 -0800422 if !success {
423 return
424 }
425
426 stats, err := handler.db.ReturnStats()
427 if err != nil {
Emily Markova290147d2023-03-03 22:40:06 -0800428 respondWithError(w, http.StatusInternalServerError, fmt.Sprint("Failed to query database: ", err))
Philipp Schrader2e7eb0002022-03-02 22:52:39 -0800429 return
Philipp Schraderacf96232022-03-01 22:03:30 -0800430 }
431
432 var response RequestDataScoutingResponseT
433 for _, stat := range stats {
434 response.StatsList = append(response.StatsList, &request_data_scouting_response.StatsT{
Philipp Schraderfa45d742022-03-18 19:29:05 -0700435 Team: stat.TeamNumber,
436 Match: stat.MatchNumber,
Philipp Schrader30b4a682022-04-16 14:36:17 -0700437 SetNumber: stat.SetNumber,
Philipp Schrader4535b7e2022-04-08 20:27:00 -0700438 CompLevel: stat.CompLevel,
Philipp Schraderfa45d742022-03-18 19:29:05 -0700439 StartingQuadrant: stat.StartingQuadrant,
440 AutoBall1: stat.AutoBallPickedUp[0],
441 AutoBall2: stat.AutoBallPickedUp[1],
442 AutoBall3: stat.AutoBallPickedUp[2],
443 AutoBall4: stat.AutoBallPickedUp[3],
444 AutoBall5: stat.AutoBallPickedUp[4],
445 MissedShotsAuto: stat.ShotsMissedAuto,
446 UpperGoalAuto: stat.UpperGoalAuto,
447 LowerGoalAuto: stat.LowerGoalAuto,
448 MissedShotsTele: stat.ShotsMissed,
449 UpperGoalTele: stat.UpperGoalShots,
450 LowerGoalTele: stat.LowerGoalShots,
451 DefenseRating: stat.PlayedDefense,
452 DefenseReceivedRating: stat.DefenseReceivedScore,
453 ClimbLevel: request_data_scouting_response.ClimbLevel(stat.Climbing),
454 CollectedBy: stat.CollectedBy,
455 Comment: stat.Comment,
Philipp Schraderacf96232022-03-01 22:03:30 -0800456 })
457 }
458
459 builder := flatbuffers.NewBuilder(50 * 1024)
460 builder.Finish((&response).Pack(builder))
461 w.Write(builder.FinishedBytes())
462}
463
Alex Perry81f96ba2022-03-13 18:26:19 -0700464type submitNoteScoutingHandler struct {
465 db Database
466}
467
468func (handler submitNoteScoutingHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
469 requestBytes, err := io.ReadAll(req.Body)
470 if err != nil {
471 respondWithError(w, http.StatusBadRequest, fmt.Sprint("Failed to read request bytes:", err))
472 return
473 }
474
Philipp Schraderb7e75932022-03-26 16:18:34 -0700475 request, success := parseRequest(w, requestBytes, "SubmitNotes", submit_notes.GetRootAsSubmitNotes)
Alex Perry81f96ba2022-03-13 18:26:19 -0700476 if !success {
477 return
478 }
479
Filip Kujawaf947cb42022-11-21 10:00:30 -0800480 err = handler.db.AddNotes(db.NotesData{
Filip Kujawa7ddd5652023-03-07 19:56:15 -0800481 TeamNumber: request.Team(),
482 Notes: string(request.Notes()),
483 GoodDriving: bool(request.GoodDriving()),
484 BadDriving: bool(request.BadDriving()),
Filip Kujawa6f7f0b32023-03-30 13:26:08 -0700485 SolidPickup: bool(request.SolidPickup()),
Filip Kujawa7ddd5652023-03-07 19:56:15 -0800486 SketchyPlacing: bool(request.SketchyPlacing()),
487 GoodDefense: bool(request.GoodDefense()),
488 BadDefense: bool(request.BadDefense()),
489 EasilyDefended: bool(request.EasilyDefended()),
Filip Kujawaf947cb42022-11-21 10:00:30 -0800490 })
Alex Perry81f96ba2022-03-13 18:26:19 -0700491 if err != nil {
492 respondWithError(w, http.StatusInternalServerError, fmt.Sprintf("Failed to insert notes: %v", err))
493 return
494 }
495
496 var response SubmitNotesResponseT
497 builder := flatbuffers.NewBuilder(10)
498 builder.Finish((&response).Pack(builder))
499 w.Write(builder.FinishedBytes())
500}
501
Emily Markova1abe9782023-03-11 19:45:38 -0800502func ConvertActionsToStat(submitActions *submit_actions.SubmitActions) (db.Stats2023, error) {
503 overall_time := int64(0)
504 cycles := int64(0)
505 picked_up := false
506 lastPlacedTime := int64(0)
507 stat := db.Stats2023{TeamNumber: string(submitActions.TeamNumber()), MatchNumber: submitActions.MatchNumber(), SetNumber: submitActions.SetNumber(), CompLevel: string(submitActions.CompLevel()),
508 StartingQuadrant: 0, LowCubesAuto: 0, MiddleCubesAuto: 0, HighCubesAuto: 0, CubesDroppedAuto: 0,
509 LowConesAuto: 0, MiddleConesAuto: 0, HighConesAuto: 0, ConesDroppedAuto: 0, LowCubes: 0, MiddleCubes: 0, HighCubes: 0,
510 CubesDropped: 0, LowCones: 0, MiddleCones: 0, HighCones: 0, ConesDropped: 0, AvgCycle: 0, CollectedBy: string(submitActions.CollectedBy()),
511 }
512 // Loop over all actions.
513 for i := 0; i < submitActions.ActionsListLength(); i++ {
514 var action submit_actions.Action
515 if !submitActions.ActionsList(&action, i) {
516 return db.Stats2023{}, errors.New(fmt.Sprintf("Failed to parse submit_actions.Action"))
517 }
518 actionTable := new(flatbuffers.Table)
519 action_type := action.ActionTakenType()
520 if !action.ActionTaken(actionTable) {
521 return db.Stats2023{}, errors.New(fmt.Sprint("Failed to parse sub-action or sub-action was missing"))
522 }
523 if action_type == submit_actions.ActionTypeStartMatchAction {
524 var startMatchAction submit_actions.StartMatchAction
525 startMatchAction.Init(actionTable.Bytes, actionTable.Pos)
526 stat.StartingQuadrant = startMatchAction.Position()
Emily Markova46a69bf2023-03-22 20:45:52 -0700527 } else if action_type == submit_actions.ActionTypeAutoBalanceAction {
528 var autoBalanceAction submit_actions.AutoBalanceAction
529 autoBalanceAction.Init(actionTable.Bytes, actionTable.Pos)
530 if autoBalanceAction.Docked() {
531 stat.DockedAuto = true
532 }
533 if autoBalanceAction.Engaged() {
534 stat.EngagedAuto = true
535 }
Emily Markova1abe9782023-03-11 19:45:38 -0800536 } else if action_type == submit_actions.ActionTypePickupObjectAction {
537 var pick_up_action submit_actions.PickupObjectAction
538 pick_up_action.Init(actionTable.Bytes, actionTable.Pos)
539 if picked_up == true {
540 object := pick_up_action.ObjectType().String()
541 auto := pick_up_action.Auto()
542 if object == "kCube" && auto == false {
543 stat.CubesDropped += 1
544 } else if object == "kCube" && auto == true {
545 stat.CubesDroppedAuto += 1
546 } else if object == "kCone" && auto == false {
547 stat.ConesDropped += 1
548 } else if object == "kCube" && auto == true {
549 stat.ConesDroppedAuto += 1
550 }
551 } else {
552 picked_up = true
553 }
554 } else if action_type == submit_actions.ActionTypePlaceObjectAction {
555 var place_action submit_actions.PlaceObjectAction
556 place_action.Init(actionTable.Bytes, actionTable.Pos)
557 if !picked_up {
558 return db.Stats2023{}, errors.New(fmt.Sprintf("Got PlaceObjectAction without corresponding PickupObjectAction"))
559 }
560 object := place_action.ObjectType()
561 level := place_action.ScoreLevel()
562 auto := place_action.Auto()
563 if object == 0 && level == 0 && auto == true {
564 stat.LowCubesAuto += 1
565 } else if object == 0 && level == 0 && auto == false {
566 stat.LowCubes += 1
567 } else if object == 0 && level == 1 && auto == true {
568 stat.MiddleCubesAuto += 1
569 } else if object == 0 && level == 1 && auto == false {
570 stat.MiddleCubes += 1
571 } else if object == 0 && level == 2 && auto == true {
572 stat.HighCubesAuto += 1
573 } else if object == 0 && level == 2 && auto == false {
574 stat.HighCubes += 1
575 } else if object == 1 && level == 0 && auto == true {
576 stat.LowConesAuto += 1
577 } else if object == 1 && level == 0 && auto == false {
578 stat.LowCones += 1
579 } else if object == 1 && level == 1 && auto == true {
580 stat.MiddleConesAuto += 1
581 } else if object == 1 && level == 1 && auto == false {
582 stat.MiddleCones += 1
583 } else if object == 1 && level == 2 && auto == true {
584 stat.HighConesAuto += 1
585 } else if object == 1 && level == 2 && auto == false {
586 stat.HighCones += 1
587 } else {
588 return db.Stats2023{}, errors.New(fmt.Sprintf("Got unknown ObjectType/ScoreLevel/Auto combination"))
589 }
590 picked_up = false
591 if lastPlacedTime != int64(0) {
592 // If this is not the first time we place,
593 // start counting cycle time. We define cycle
594 // time as the time between placements.
595 overall_time += int64(action.Timestamp()) - lastPlacedTime
596 cycles += 1
597 }
598 lastPlacedTime = int64(action.Timestamp())
Emily Markova46a69bf2023-03-22 20:45:52 -0700599 } else if action_type == submit_actions.ActionTypeEndMatchAction {
600 var endMatchAction submit_actions.EndMatchAction
601 endMatchAction.Init(actionTable.Bytes, actionTable.Pos)
602 if endMatchAction.Docked() {
603 stat.Docked = true
604 }
605 if endMatchAction.Engaged() {
606 stat.Engaged = true
607 }
Emily Markova1abe9782023-03-11 19:45:38 -0800608 }
609 }
610 if cycles != 0 {
Philipp Schrader8c878a22023-03-20 22:36:38 -0700611 stat.AvgCycle = overall_time / cycles
Emily Markova1abe9782023-03-11 19:45:38 -0800612 } else {
613 stat.AvgCycle = 0
614 }
615 return stat, nil
616}
617
Emily Markova290147d2023-03-03 22:40:06 -0800618// Handles a Request2023DataScouting request.
619type request2023DataScoutingHandler struct {
620 db Database
621}
622
623func (handler request2023DataScoutingHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
624 requestBytes, err := io.ReadAll(req.Body)
625 if err != nil {
626 respondWithError(w, http.StatusBadRequest, fmt.Sprint("Failed to read request bytes:", err))
627 return
628 }
629
630 _, success := parseRequest(w, requestBytes, "Request2023DataScouting", request_2023_data_scouting.GetRootAsRequest2023DataScouting)
631 if !success {
632 return
633 }
634
635 stats, err := handler.db.ReturnStats2023()
636 if err != nil {
637 respondWithError(w, http.StatusInternalServerError, fmt.Sprint("Failed to query database: ", err))
638 return
639 }
640
641 var response Request2023DataScoutingResponseT
642 for _, stat := range stats {
643 response.StatsList = append(response.StatsList, &request_2023_data_scouting_response.Stats2023T{
644 TeamNumber: stat.TeamNumber,
645 MatchNumber: stat.MatchNumber,
646 SetNumber: stat.SetNumber,
647 CompLevel: stat.CompLevel,
648 StartingQuadrant: stat.StartingQuadrant,
649 LowCubesAuto: stat.LowCubesAuto,
650 MiddleCubesAuto: stat.MiddleCubesAuto,
651 HighCubesAuto: stat.HighCubesAuto,
652 CubesDroppedAuto: stat.CubesDroppedAuto,
653 LowConesAuto: stat.LowConesAuto,
654 MiddleConesAuto: stat.MiddleConesAuto,
655 HighConesAuto: stat.HighConesAuto,
656 ConesDroppedAuto: stat.ConesDroppedAuto,
657 LowCubes: stat.LowCubes,
658 MiddleCubes: stat.MiddleCubes,
659 HighCubes: stat.HighCubes,
660 CubesDropped: stat.CubesDropped,
661 LowCones: stat.LowCones,
662 MiddleCones: stat.MiddleCones,
663 HighCones: stat.HighCones,
664 ConesDropped: stat.ConesDropped,
665 AvgCycle: stat.AvgCycle,
Emily Markova46a69bf2023-03-22 20:45:52 -0700666 DockedAuto: stat.DockedAuto,
667 EngagedAuto: stat.EngagedAuto,
668 Docked: stat.Docked,
669 Engaged: stat.Engaged,
Emily Markova290147d2023-03-03 22:40:06 -0800670 CollectedBy: stat.CollectedBy,
671 })
672 }
673
674 builder := flatbuffers.NewBuilder(50 * 1024)
675 builder.Finish((&response).Pack(builder))
676 w.Write(builder.FinishedBytes())
677}
678
Alex Perry81f96ba2022-03-13 18:26:19 -0700679type requestNotesForTeamHandler struct {
680 db Database
681}
682
683func (handler requestNotesForTeamHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
684 requestBytes, err := io.ReadAll(req.Body)
685 if err != nil {
686 respondWithError(w, http.StatusBadRequest, fmt.Sprint("Failed to read request bytes:", err))
687 return
688 }
689
Philipp Schraderb7e75932022-03-26 16:18:34 -0700690 request, success := parseRequest(w, requestBytes, "RequestNotesForTeam", request_notes_for_team.GetRootAsRequestNotesForTeam)
Alex Perry81f96ba2022-03-13 18:26:19 -0700691 if !success {
692 return
693 }
694
Philipp Schradereecb8962022-06-01 21:02:42 -0700695 notes, err := handler.db.QueryNotes(request.Team())
Alex Perry81f96ba2022-03-13 18:26:19 -0700696 if err != nil {
697 respondWithError(w, http.StatusInternalServerError, fmt.Sprintf("Failed to query notes: %v", err))
698 return
699 }
700
701 var response RequestNotesForTeamResponseT
Philipp Schradereecb8962022-06-01 21:02:42 -0700702 for _, data := range notes {
Alex Perry81f96ba2022-03-13 18:26:19 -0700703 response.Notes = append(response.Notes, &request_notes_for_team_response.NoteT{data})
704 }
705
706 builder := flatbuffers.NewBuilder(1024)
707 builder.Finish((&response).Pack(builder))
708 w.Write(builder.FinishedBytes())
709}
710
Milo Lin1d59f0c2022-06-22 20:30:58 -0700711type requestShiftScheduleHandler struct {
712 db Database
713}
714
715func (handler requestShiftScheduleHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
716 requestBytes, err := io.ReadAll(req.Body)
717 if err != nil {
718 respondWithError(w, http.StatusBadRequest, fmt.Sprint("Failed to read request bytes:", err))
719 return
720 }
721
722 _, success := parseRequest(w, requestBytes, "RequestShiftSchedule", request_shift_schedule.GetRootAsRequestShiftSchedule)
723 if !success {
724 return
725 }
726
727 shiftData, err := handler.db.ReturnAllShifts()
728 if err != nil {
729 respondWithError(w, http.StatusInternalServerError, fmt.Sprintf("Failed to query shift schedule: %v", err))
730 return
731 }
732
733 var response RequestShiftScheduleResponseT
734 for _, shifts := range shiftData {
735 response.ShiftSchedule = append(response.ShiftSchedule, &request_shift_schedule_response.MatchAssignmentT{
736 MatchNumber: shifts.MatchNumber,
737 R1scouter: shifts.R1scouter,
738 R2scouter: shifts.R2scouter,
739 R3scouter: shifts.R3scouter,
740 B1scouter: shifts.B1scouter,
741 B2scouter: shifts.B2scouter,
742 B3scouter: shifts.B3scouter,
743 })
744 }
745
746 builder := flatbuffers.NewBuilder(1024)
747 builder.Finish((&response).Pack(builder))
748 w.Write(builder.FinishedBytes())
749}
750
751type submitShiftScheduleHandler struct {
752 db Database
753}
754
755func (handler submitShiftScheduleHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
756 // Get the username of the person submitting the data.
757 username := parseUsername(req)
758
759 requestBytes, err := io.ReadAll(req.Body)
760 if err != nil {
761 respondWithError(w, http.StatusBadRequest, fmt.Sprint("Failed to read request bytes:", err))
762 return
763 }
764
765 request, success := parseRequest[SubmitShiftSchedule](w, requestBytes, "SubmitShiftSchedule", submit_shift_schedule.GetRootAsSubmitShiftSchedule)
766 if !success {
767 return
768 }
769
770 log.Println("Got shift schedule from", username)
771 shift_schedule_length := request.ShiftScheduleLength()
772 for i := 0; i < shift_schedule_length; i++ {
773 var match_assignment submit_shift_schedule.MatchAssignment
774 request.ShiftSchedule(&match_assignment, i)
775 current_shift := db.Shift{
776 MatchNumber: match_assignment.MatchNumber(),
777 R1scouter: string(match_assignment.R1scouter()),
778 R2scouter: string(match_assignment.R2scouter()),
779 R3scouter: string(match_assignment.R3scouter()),
780 B1scouter: string(match_assignment.B1scouter()),
781 B2scouter: string(match_assignment.B2scouter()),
782 B3scouter: string(match_assignment.B3scouter()),
783 }
784 err = handler.db.AddToShift(current_shift)
785 if err != nil {
786 respondWithError(w, http.StatusInternalServerError, fmt.Sprint("Failed to submit shift schedule: ", err))
787 return
788 }
789 }
790
791 builder := flatbuffers.NewBuilder(50 * 1024)
792 builder.Finish((&SubmitShiftScheduleResponseT{}).Pack(builder))
793 w.Write(builder.FinishedBytes())
794}
795
Filip Kujawa210a03b2022-11-24 14:41:11 -0800796type SubmitDriverRankingHandler struct {
797 db Database
798}
799
800func (handler SubmitDriverRankingHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
801 requestBytes, err := io.ReadAll(req.Body)
802 if err != nil {
803 respondWithError(w, http.StatusBadRequest, fmt.Sprint("Failed to read request bytes:", err))
804 return
805 }
806
807 request, success := parseRequest(w, requestBytes, "SubmitDriverRanking", submit_driver_ranking.GetRootAsSubmitDriverRanking)
808 if !success {
809 return
810 }
811
812 err = handler.db.AddDriverRanking(db.DriverRankingData{
813 MatchNumber: request.MatchNumber(),
814 Rank1: request.Rank1(),
815 Rank2: request.Rank2(),
816 Rank3: request.Rank3(),
817 })
818
819 if err != nil {
820 respondWithError(w, http.StatusInternalServerError, fmt.Sprintf("Failed to insert driver ranking: %v", err))
821 return
822 }
823
824 var response SubmitDriverRankingResponseT
825 builder := flatbuffers.NewBuilder(10)
826 builder.Finish((&response).Pack(builder))
827 w.Write(builder.FinishedBytes())
828}
829
Filip Kujawaf882e022022-12-14 13:14:08 -0800830type requestAllNotesHandler struct {
831 db Database
832}
833
834func (handler requestAllNotesHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
835 requestBytes, err := io.ReadAll(req.Body)
836 if err != nil {
837 respondWithError(w, http.StatusBadRequest, fmt.Sprint("Failed to read request bytes:", err))
838 return
839 }
840
841 _, success := parseRequest(w, requestBytes, "RequestAllNotes", request_all_notes.GetRootAsRequestAllNotes)
842 if !success {
843 return
844 }
845
846 notes, err := handler.db.ReturnAllNotes()
847 if err != nil {
848 respondWithError(w, http.StatusInternalServerError, fmt.Sprint("Failed to query database: ", err))
849 return
850 }
851
852 var response RequestAllNotesResponseT
853 for _, note := range notes {
854 response.NoteList = append(response.NoteList, &request_all_notes_response.NoteT{
Filip Kujawa7ddd5652023-03-07 19:56:15 -0800855 Team: note.TeamNumber,
856 Notes: note.Notes,
857 GoodDriving: note.GoodDriving,
858 BadDriving: note.BadDriving,
Filip Kujawa6f7f0b32023-03-30 13:26:08 -0700859 SolidPickup: note.SolidPickup,
Filip Kujawa7ddd5652023-03-07 19:56:15 -0800860 SketchyPlacing: note.SketchyPlacing,
861 GoodDefense: note.GoodDefense,
862 BadDefense: note.BadDefense,
863 EasilyDefended: note.EasilyDefended,
Filip Kujawaf882e022022-12-14 13:14:08 -0800864 })
865 }
866
867 builder := flatbuffers.NewBuilder(50 * 1024)
868 builder.Finish((&response).Pack(builder))
869 w.Write(builder.FinishedBytes())
870}
871
872type requestAllDriverRankingsHandler struct {
873 db Database
874}
875
876func (handler requestAllDriverRankingsHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
877 requestBytes, err := io.ReadAll(req.Body)
878 if err != nil {
879 respondWithError(w, http.StatusBadRequest, fmt.Sprint("Failed to read request bytes:", err))
880 return
881 }
882
883 _, success := parseRequest(w, requestBytes, "RequestAllDriverRankings", request_all_driver_rankings.GetRootAsRequestAllDriverRankings)
884 if !success {
885 return
886 }
887
888 rankings, err := handler.db.ReturnAllDriverRankings()
889 if err != nil {
890 respondWithError(w, http.StatusInternalServerError, fmt.Sprint("Failed to query database: ", err))
891 return
892 }
893
894 var response RequestAllDriverRankingsResponseT
895 for _, ranking := range rankings {
896 response.DriverRankingList = append(response.DriverRankingList, &request_all_driver_rankings_response.RankingT{
897 MatchNumber: ranking.MatchNumber,
898 Rank1: ranking.Rank1,
899 Rank2: ranking.Rank2,
900 Rank3: ranking.Rank3,
901 })
902 }
903
904 builder := flatbuffers.NewBuilder(50 * 1024)
905 builder.Finish((&response).Pack(builder))
906 w.Write(builder.FinishedBytes())
907}
908
Philipp Schrader43c730b2023-02-26 20:27:44 -0800909func HandleRequests(db Database, scoutingServer server.ScoutingServer) {
Philipp Schradercdb5cfc2022-02-20 14:57:07 -0800910 scoutingServer.HandleFunc("/requests", unknown)
Philipp Schrader8747f1b2022-02-23 23:56:22 -0800911 scoutingServer.Handle("/requests/submit/data_scouting", submitDataScoutingHandler{db})
Philipp Schradercbf5c6a2022-02-27 23:25:19 -0800912 scoutingServer.Handle("/requests/request/all_matches", requestAllMatchesHandler{db})
Filip Kujawaf882e022022-12-14 13:14:08 -0800913 scoutingServer.Handle("/requests/request/all_notes", requestAllNotesHandler{db})
914 scoutingServer.Handle("/requests/request/all_driver_rankings", requestAllDriverRankingsHandler{db})
Philipp Schraderacf96232022-03-01 22:03:30 -0800915 scoutingServer.Handle("/requests/request/data_scouting", requestDataScoutingHandler{db})
Emily Markova290147d2023-03-03 22:40:06 -0800916 scoutingServer.Handle("/requests/request/2023_data_scouting", request2023DataScoutingHandler{db})
Alex Perry81f96ba2022-03-13 18:26:19 -0700917 scoutingServer.Handle("/requests/submit/submit_notes", submitNoteScoutingHandler{db})
918 scoutingServer.Handle("/requests/request/notes_for_team", requestNotesForTeamHandler{db})
Milo Lin1d59f0c2022-06-22 20:30:58 -0700919 scoutingServer.Handle("/requests/submit/shift_schedule", submitShiftScheduleHandler{db})
920 scoutingServer.Handle("/requests/request/shift_schedule", requestShiftScheduleHandler{db})
Filip Kujawa210a03b2022-11-24 14:41:11 -0800921 scoutingServer.Handle("/requests/submit/submit_driver_ranking", SubmitDriverRankingHandler{db})
Philipp Schradercdb5cfc2022-02-20 14:57:07 -0800922}