blob: 321f2242eef2f9608fef1740a9511978fc199c4c [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"
Emily Markova521725a2024-03-21 18:46:04 -070013 "time"
Philipp Schradercdb5cfc2022-02-20 14:57:07 -080014
Philipp Schrader8747f1b2022-02-23 23:56:22 -080015 "github.com/frc971/971-Robot-Code/scouting/db"
Filip Kujawac1ded372023-05-27 14:33:43 -070016 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/delete_2023_data_scouting"
17 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/delete_2023_data_scouting_response"
Emily Markova8cb91312024-02-02 12:30:37 -080018 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/delete_2024_data_scouting"
19 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/delete_2024_data_scouting_response"
Philipp Schradercdb5cfc2022-02-20 14:57:07 -080020 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/error_response"
Emily Markova290147d2023-03-03 22:40:06 -080021 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_2023_data_scouting"
22 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_2023_data_scouting_response"
Emily Markova8cb91312024-02-02 12:30:37 -080023 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_2024_data_scouting"
24 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_2024_data_scouting_response"
Filip Kujawaf882e022022-12-14 13:14:08 -080025 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_all_driver_rankings"
26 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_all_driver_rankings_response"
Philipp Schradercbf5c6a2022-02-27 23:25:19 -080027 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_all_matches"
28 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_all_matches_response"
Filip Kujawaf882e022022-12-14 13:14:08 -080029 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_all_notes"
30 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_all_notes_response"
Emily Markova8e39f452023-12-23 12:17:30 -080031 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_all_pit_images"
32 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_all_pit_images_response"
Emily Markova521725a2024-03-21 18:46:04 -070033 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_current_scouting"
34 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_current_scouting_response"
Alex Perry81f96ba2022-03-13 18:26:19 -070035 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_notes_for_team"
36 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_notes_for_team_response"
Emily Markovafaecfe12023-07-01 12:40:03 -070037 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_pit_images"
38 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_pit_images_response"
Milo Lin1d59f0c2022-06-22 20:30:58 -070039 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_shift_schedule"
40 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_shift_schedule_response"
Emily Markova8cb91312024-02-02 12:30:37 -080041 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_2024_actions"
42 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_2024_actions_response"
Sabina Leaver759090b2023-01-14 20:42:56 -080043 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_actions"
44 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_actions_response"
Filip Kujawa210a03b2022-11-24 14:41:11 -080045 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_driver_ranking"
46 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_driver_ranking_response"
Alex Perry81f96ba2022-03-13 18:26:19 -070047 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_notes"
48 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_notes_response"
Emily Markovafaecfe12023-07-01 12:40:03 -070049 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_pit_image"
50 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_pit_image_response"
Milo Lin1d59f0c2022-06-22 20:30:58 -070051 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_shift_schedule"
52 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_shift_schedule_response"
Philipp Schradercdb5cfc2022-02-20 14:57:07 -080053 "github.com/frc971/971-Robot-Code/scouting/webserver/server"
54 flatbuffers "github.com/google/flatbuffers/go"
55)
56
Philipp Schradercbf5c6a2022-02-27 23:25:19 -080057type RequestAllMatches = request_all_matches.RequestAllMatches
58type RequestAllMatchesResponseT = request_all_matches_response.RequestAllMatchesResponseT
Filip Kujawaf882e022022-12-14 13:14:08 -080059type RequestAllDriverRankings = request_all_driver_rankings.RequestAllDriverRankings
60type RequestAllDriverRankingsResponseT = request_all_driver_rankings_response.RequestAllDriverRankingsResponseT
61type RequestAllNotes = request_all_notes.RequestAllNotes
62type RequestAllNotesResponseT = request_all_notes_response.RequestAllNotesResponseT
Emily Markova290147d2023-03-03 22:40:06 -080063type Request2023DataScouting = request_2023_data_scouting.Request2023DataScouting
64type Request2023DataScoutingResponseT = request_2023_data_scouting_response.Request2023DataScoutingResponseT
Emily Markova8cb91312024-02-02 12:30:37 -080065type Request2024DataScouting = request_2024_data_scouting.Request2024DataScouting
66type Request2024DataScoutingResponseT = request_2024_data_scouting_response.Request2024DataScoutingResponseT
Alex Perry81f96ba2022-03-13 18:26:19 -070067type SubmitNotes = submit_notes.SubmitNotes
68type SubmitNotesResponseT = submit_notes_response.SubmitNotesResponseT
Emily Markovafaecfe12023-07-01 12:40:03 -070069type SubmitPitImage = submit_pit_image.SubmitPitImage
70type SubmitPitImageResponseT = submit_pit_image_response.SubmitPitImageResponseT
71type RequestPitImages = request_pit_images.RequestPitImages
72type RequestPitImagesResponseT = request_pit_images_response.RequestPitImagesResponseT
Emily Markova8e39f452023-12-23 12:17:30 -080073type RequestAllPitImages = request_all_pit_images.RequestAllPitImages
74type RequestAllPitImagesResponseT = request_all_pit_images_response.RequestAllPitImagesResponseT
Emily Markova521725a2024-03-21 18:46:04 -070075type RequestCurrentScouting = request_current_scouting.RequestCurrentScouting
76type RequestCurrentScoutingResponseT = request_current_scouting_response.RequestCurrentScoutingResponseT
Alex Perry81f96ba2022-03-13 18:26:19 -070077type RequestNotesForTeam = request_notes_for_team.RequestNotesForTeam
78type RequestNotesForTeamResponseT = request_notes_for_team_response.RequestNotesForTeamResponseT
Milo Lin1d59f0c2022-06-22 20:30:58 -070079type RequestShiftSchedule = request_shift_schedule.RequestShiftSchedule
80type RequestShiftScheduleResponseT = request_shift_schedule_response.RequestShiftScheduleResponseT
81type SubmitShiftSchedule = submit_shift_schedule.SubmitShiftSchedule
82type SubmitShiftScheduleResponseT = submit_shift_schedule_response.SubmitShiftScheduleResponseT
Filip Kujawa210a03b2022-11-24 14:41:11 -080083type SubmitDriverRanking = submit_driver_ranking.SubmitDriverRanking
84type SubmitDriverRankingResponseT = submit_driver_ranking_response.SubmitDriverRankingResponseT
Sabina Leaver759090b2023-01-14 20:42:56 -080085type SubmitActions = submit_actions.SubmitActions
Sabina Leaver9b4eb312023-02-20 19:58:17 -080086type Action = submit_actions.Action
Emily Markova8cb91312024-02-02 12:30:37 -080087type Action2024 = submit_2024_actions.Action
Sabina Leaver759090b2023-01-14 20:42:56 -080088type SubmitActionsResponseT = submit_actions_response.SubmitActionsResponseT
Emily Markova8cb91312024-02-02 12:30:37 -080089type Submit2024Actions = submit_2024_actions.Submit2024Actions
90type Submit2024ActionsResponseT = submit_2024_actions_response.Submit2024ActionsResponseT
Filip Kujawac1ded372023-05-27 14:33:43 -070091type Delete2023DataScouting = delete_2023_data_scouting.Delete2023DataScouting
92type Delete2023DataScoutingResponseT = delete_2023_data_scouting_response.Delete2023DataScoutingResponseT
Emily Markova8cb91312024-02-02 12:30:37 -080093type Delete2024DataScouting = delete_2024_data_scouting.Delete2024DataScouting
94type Delete2024DataScoutingResponseT = delete_2024_data_scouting_response.Delete2024DataScoutingResponseT
Philipp Schradercbf5c6a2022-02-27 23:25:19 -080095
Philipp Schrader8747f1b2022-02-23 23:56:22 -080096// The interface we expect the database abstraction to conform to.
97// We use an interface here because it makes unit testing easier.
98type Database interface {
Emily Markovabf24c9e2023-02-08 20:31:11 -080099 AddToMatch(db.TeamMatch) error
Milo Lin1d59f0c2022-06-22 20:30:58 -0700100 AddToShift(db.Shift) error
Emily Markova290147d2023-03-03 22:40:06 -0800101 AddToStats2023(db.Stats2023) error
Emily Markova8cb91312024-02-02 12:30:37 -0800102 AddToStats2024(db.Stats2024) error
Emily Markovabf24c9e2023-02-08 20:31:11 -0800103 ReturnMatches() ([]db.TeamMatch, error)
Filip Kujawaf882e022022-12-14 13:14:08 -0800104 ReturnAllNotes() ([]db.NotesData, error)
105 ReturnAllDriverRankings() ([]db.DriverRankingData, error)
Milo Lin1d59f0c2022-06-22 20:30:58 -0700106 ReturnAllShifts() ([]db.Shift, error)
Emily Markova290147d2023-03-03 22:40:06 -0800107 ReturnStats2023() ([]db.Stats2023, error)
Filip Kujawaf3f9def2023-04-20 13:46:46 -0700108 ReturnStats2023ForTeam(teamNumber string, matchNumber int32, setNumber int32, compLevel string, preScouting bool) ([]db.Stats2023, error)
Emily Markova8cb91312024-02-02 12:30:37 -0800109 ReturnStats2024() ([]db.Stats2024, error)
Emily Markova9c18e9c2024-04-03 20:06:27 -0700110 ReturnStats2024ForTeam(teamNumber string, matchNumber int32, setNumber int32, compLevel string, compType string) ([]db.Stats2024, error)
Milo Lin1d59f0c2022-06-22 20:30:58 -0700111 QueryAllShifts(int) ([]db.Shift, error)
Emily Markovae68b7632023-12-30 14:17:55 -0800112 QueryNotes(string) ([]string, error)
Emily Markovafaecfe12023-07-01 12:40:03 -0700113 QueryPitImages(string) ([]db.RequestedPitImage, error)
Emily Markova8e39f452023-12-23 12:17:30 -0800114 ReturnPitImages() ([]db.PitImage, error)
Filip Kujawaf947cb42022-11-21 10:00:30 -0800115 AddNotes(db.NotesData) error
Emily Markovafaecfe12023-07-01 12:40:03 -0700116 AddPitImage(db.PitImage) error
Filip Kujawa210a03b2022-11-24 14:41:11 -0800117 AddDriverRanking(db.DriverRankingData) error
Sabina Leaver9b4eb312023-02-20 19:58:17 -0800118 AddAction(db.Action) error
Filip Kujawac1ded372023-05-27 14:33:43 -0700119 DeleteFromStats(string, int32, int32, string) error
Emily Markova8cb91312024-02-02 12:30:37 -0800120 DeleteFromStats2024(string, int32, int32, string) error
Filip Kujawac1ded372023-05-27 14:33:43 -0700121 DeleteFromActions(string, int32, int32, string) error
Philipp Schrader8747f1b2022-02-23 23:56:22 -0800122}
123
Emily Markova521725a2024-03-21 18:46:04 -0700124type Clock interface {
125 Now() time.Time
126}
127
128type RealClock struct{}
129
130func (RealClock) Now() time.Time {
131 return time.Now()
132}
133
Philipp Schradercdb5cfc2022-02-20 14:57:07 -0800134// Handles unknown requests. Just returns a 404.
135func unknown(w http.ResponseWriter, req *http.Request) {
136 w.WriteHeader(http.StatusNotFound)
137}
138
139func respondWithError(w http.ResponseWriter, statusCode int, errorMessage string) {
140 builder := flatbuffers.NewBuilder(1024)
141 builder.Finish((&error_response.ErrorResponseT{
142 ErrorMessage: errorMessage,
143 }).Pack(builder))
144 w.WriteHeader(statusCode)
145 w.Write(builder.FinishedBytes())
146}
147
148func respondNotImplemented(w http.ResponseWriter) {
149 respondWithError(w, http.StatusNotImplemented, "")
150}
151
Philipp Schraderb7e75932022-03-26 16:18:34 -0700152func 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 -0800153 success := true
154 defer func() {
155 if r := recover(); r != nil {
Philipp Schraderb7e75932022-03-26 16:18:34 -0700156 respondWithError(w, http.StatusBadRequest, fmt.Sprintf("Failed to parse %s: %v", requestName, r))
Philipp Schradercdb5cfc2022-02-20 14:57:07 -0800157 success = false
158 }
159 }()
Philipp Schraderb7e75932022-03-26 16:18:34 -0700160 result := parser(buf, 0)
Philipp Schradercdb5cfc2022-02-20 14:57:07 -0800161 return result, success
162}
163
Philipp Schraderfae8a7e2022-03-13 22:51:54 -0700164// Parses the authorization information that the browser inserts into the
165// headers. The authorization follows this format:
166//
Philipp Schrader35bb1532023-03-05 13:49:12 -0800167// req.Headers["Authorization"] = []string{"Basic <base64 encoded username:password>"}
Philipp Schraderfae8a7e2022-03-13 22:51:54 -0700168func parseUsername(req *http.Request) string {
169 auth, ok := req.Header["Authorization"]
170 if !ok {
171 return "unknown"
172 }
173
174 parts := strings.Split(auth[0], " ")
175 if !(len(parts) == 2 && parts[0] == "Basic") {
176 return "unknown"
177 }
178
179 info, err := base64.StdEncoding.DecodeString(parts[1])
180 if err != nil {
181 log.Println("ERROR: Failed to parse Basic authentication.")
182 return "unknown"
183 }
184
185 loginParts := strings.Split(string(info), ":")
186 if len(loginParts) != 2 {
187 return "unknown"
188 }
189 return loginParts[0]
190}
191
Philipp Schradercbf5c6a2022-02-27 23:25:19 -0800192// Handles a RequestAllMaches request.
193type requestAllMatchesHandler struct {
194 db Database
195}
196
Philipp Schrader0f7b6362023-03-11 14:02:48 -0800197// Change structure of match objects in the database(1 per team) to
198// the old match structure(1 per match) that the webserver uses.
199// We use the information in this struct to identify which match object
200// corresponds to which old match structure object.
201type MatchAssemblyKey struct {
202 MatchNumber int32
203 SetNumber int32
204 CompLevel string
205}
206
Emily Markovabf24c9e2023-02-08 20:31:11 -0800207func findIndexInList(list []string, comp_level string) (int, error) {
208 for index, value := range list {
209 if value == comp_level {
210 return index, nil
211 }
212 }
213 return -1, errors.New(fmt.Sprint("Failed to find comp level ", comp_level, " in list ", list))
214}
215
Emily Markovab8551572023-03-22 19:49:39 -0700216func (handler requestAllMatchesHandler) teamHasBeenDataScouted(key MatchAssemblyKey, teamNumber string) (bool, error) {
Emily Markovadcadcb62024-02-03 13:07:17 -0800217 stats, err := handler.db.ReturnStats2024ForTeam(
Emily Markova9c18e9c2024-04-03 20:06:27 -0700218 teamNumber, key.MatchNumber, key.SetNumber, key.CompLevel, "Regular")
Philipp Schrader0f7b6362023-03-11 14:02:48 -0800219 if err != nil {
220 return false, err
221 }
222 return (len(stats) > 0), nil
223}
224
Philipp Schradercbf5c6a2022-02-27 23:25:19 -0800225func (handler requestAllMatchesHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
226 requestBytes, err := io.ReadAll(req.Body)
227 if err != nil {
228 respondWithError(w, http.StatusBadRequest, fmt.Sprint("Failed to read request bytes:", err))
229 return
230 }
231
Philipp Schraderb7e75932022-03-26 16:18:34 -0700232 _, success := parseRequest(w, requestBytes, "RequestAllMatches", request_all_matches.GetRootAsRequestAllMatches)
Philipp Schradercbf5c6a2022-02-27 23:25:19 -0800233 if !success {
234 return
235 }
236
237 matches, err := handler.db.ReturnMatches()
238 if err != nil {
Philipp Schraderfae8a7e2022-03-13 22:51:54 -0700239 respondWithError(w, http.StatusInternalServerError, fmt.Sprint("Failed to query database: ", err))
Philipp Schrader2e7eb0002022-03-02 22:52:39 -0800240 return
Philipp Schradercbf5c6a2022-02-27 23:25:19 -0800241 }
242
Philipp Schrader0f7b6362023-03-11 14:02:48 -0800243 assembledMatches := map[MatchAssemblyKey]request_all_matches_response.MatchT{}
Emily Markovabf24c9e2023-02-08 20:31:11 -0800244
Philipp Schradercbf5c6a2022-02-27 23:25:19 -0800245 for _, match := range matches {
Philipp Schrader0f7b6362023-03-11 14:02:48 -0800246 key := MatchAssemblyKey{match.MatchNumber, match.SetNumber, match.CompLevel}
247
248 // Retrieve the converted match structure we have assembled so
249 // far. If we haven't started assembling one yet, then start a
250 // new one.
Emily Markovabf24c9e2023-02-08 20:31:11 -0800251 entry, ok := assembledMatches[key]
252 if !ok {
253 entry = request_all_matches_response.MatchT{
254 MatchNumber: match.MatchNumber,
255 SetNumber: match.SetNumber,
256 CompLevel: match.CompLevel,
Philipp Schrader0f7b6362023-03-11 14:02:48 -0800257 DataScouted: &request_all_matches_response.ScoutedLevelT{},
Emily Markovabf24c9e2023-02-08 20:31:11 -0800258 }
259 }
Philipp Schrader0f7b6362023-03-11 14:02:48 -0800260
Emily Markovab8551572023-03-22 19:49:39 -0700261 var team *string
Philipp Schrader0f7b6362023-03-11 14:02:48 -0800262 var dataScoutedTeam *bool
263
264 // Fill in the field for the match that we have in in the
265 // database. In the database, each match row only has 1 team
266 // number.
Emily Markovabf24c9e2023-02-08 20:31:11 -0800267 switch match.Alliance {
268 case "R":
269 switch match.AlliancePosition {
270 case 1:
Philipp Schrader0f7b6362023-03-11 14:02:48 -0800271 team = &entry.R1
272 dataScoutedTeam = &entry.DataScouted.R1
Emily Markovabf24c9e2023-02-08 20:31:11 -0800273 case 2:
Philipp Schrader0f7b6362023-03-11 14:02:48 -0800274 team = &entry.R2
275 dataScoutedTeam = &entry.DataScouted.R2
Emily Markovabf24c9e2023-02-08 20:31:11 -0800276 case 3:
Philipp Schrader0f7b6362023-03-11 14:02:48 -0800277 team = &entry.R3
278 dataScoutedTeam = &entry.DataScouted.R3
Emily Markovabf24c9e2023-02-08 20:31:11 -0800279 default:
280 respondWithError(w, http.StatusInternalServerError, fmt.Sprint("Unknown red position ", strconv.Itoa(int(match.AlliancePosition)), " in match ", strconv.Itoa(int(match.MatchNumber))))
281 return
282 }
283 case "B":
284 switch match.AlliancePosition {
285 case 1:
Philipp Schrader0f7b6362023-03-11 14:02:48 -0800286 team = &entry.B1
287 dataScoutedTeam = &entry.DataScouted.B1
Emily Markovabf24c9e2023-02-08 20:31:11 -0800288 case 2:
Philipp Schrader0f7b6362023-03-11 14:02:48 -0800289 team = &entry.B2
290 dataScoutedTeam = &entry.DataScouted.B2
Emily Markovabf24c9e2023-02-08 20:31:11 -0800291 case 3:
Philipp Schrader0f7b6362023-03-11 14:02:48 -0800292 team = &entry.B3
293 dataScoutedTeam = &entry.DataScouted.B3
Emily Markovabf24c9e2023-02-08 20:31:11 -0800294 default:
295 respondWithError(w, http.StatusInternalServerError, fmt.Sprint("Unknown blue position ", strconv.Itoa(int(match.AlliancePosition)), " in match ", strconv.Itoa(int(match.MatchNumber))))
296 return
297 }
298 default:
299 respondWithError(w, http.StatusInternalServerError, fmt.Sprint("Unknown alliance ", match.Alliance, " in match ", strconv.Itoa(int(match.AlliancePosition))))
300 return
301 }
Philipp Schrader0f7b6362023-03-11 14:02:48 -0800302
303 *team = match.TeamNumber
304
305 // Figure out if this team has been data scouted already.
306 *dataScoutedTeam, err = handler.teamHasBeenDataScouted(key, match.TeamNumber)
307 if err != nil {
308 respondWithError(w, http.StatusInternalServerError, fmt.Sprint(
309 "Failed to determine data scouting status for team ",
310 strconv.Itoa(int(match.AlliancePosition)),
311 " in match ",
312 strconv.Itoa(int(match.MatchNumber)),
313 err))
314 return
315 }
316
Emily Markovabf24c9e2023-02-08 20:31:11 -0800317 assembledMatches[key] = entry
318 }
319
320 var response RequestAllMatchesResponseT
321 for _, match := range assembledMatches {
322 copied_match := match
323 response.MatchList = append(response.MatchList, &copied_match)
324 }
325
326 var MATCH_TYPE_ORDERING = []string{"qm", "ef", "qf", "sf", "f"}
327
328 err = nil
329 sort.Slice(response.MatchList, func(i, j int) bool {
330 if err != nil {
331 return false
332 }
333 a := response.MatchList[i]
334 b := response.MatchList[j]
335
Emily Markovaabcac6e2023-02-18 17:50:03 -0800336 aMatchTypeIndex, err2 := findIndexInList(MATCH_TYPE_ORDERING, a.CompLevel)
337 if err2 != nil {
338 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 -0800339 return false
340 }
Emily Markovaabcac6e2023-02-18 17:50:03 -0800341 bMatchTypeIndex, err2 := findIndexInList(MATCH_TYPE_ORDERING, b.CompLevel)
342 if err2 != nil {
343 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 -0800344 return false
345 }
346
347 if aMatchTypeIndex < bMatchTypeIndex {
348 return true
349 }
350 if aMatchTypeIndex > bMatchTypeIndex {
351 return false
352 }
353
354 // Then sort by match number. E.g. in semi finals, all match 1 rounds
355 // are done first. Then come match 2 rounds. And then, if necessary,
356 // the match 3 rounds.
357 aMatchNumber := a.MatchNumber
358 bMatchNumber := b.MatchNumber
359 if aMatchNumber < bMatchNumber {
360 return true
361 }
362 if aMatchNumber > bMatchNumber {
363 return false
364 }
365 // Lastly, sort by set number. I.e. Semi Final 1 Match 1 happens first.
366 // Then comes Semi Final 2 Match 1. Then comes Semi Final 1 Match 2. Then
367 // Semi Final 2 Match 2.
368 aSetNumber := a.SetNumber
369 bSetNumber := b.SetNumber
370 if aSetNumber < bSetNumber {
371 return true
372 }
373 if aSetNumber > bSetNumber {
374 return false
375 }
376 return true
377 })
378
379 if err != nil {
380 // check if error happened during sorting and notify webpage if that
381 respondWithError(w, http.StatusInternalServerError, fmt.Sprint(err))
382 return
Philipp Schradercbf5c6a2022-02-27 23:25:19 -0800383 }
384
385 builder := flatbuffers.NewBuilder(50 * 1024)
386 builder.Finish((&response).Pack(builder))
387 w.Write(builder.FinishedBytes())
388}
389
Emily Markova521725a2024-03-21 18:46:04 -0700390type requestCurrentScoutingHandler struct {
391 // Map that has a key of team number with a value is a map of names to timestamps
392 // so there aren't duplicate timestamps for one person.
393 scoutingMap map[string]map[string]time.Time
394 db Database
395 clock Clock
396}
397
398func (handler requestCurrentScoutingHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
399 requestBytes, err := io.ReadAll(req.Body)
400 if err != nil {
401 respondWithError(w, http.StatusBadRequest, fmt.Sprint("Failed to read request bytes:", err))
402 return
403 }
404
405 request, success := parseRequest(w, requestBytes, "RequestCurrentScouting", request_current_scouting.GetRootAsRequestCurrentScouting)
406 if !success {
407 return
408 }
409 currentTime := handler.clock.Now()
410 teamNumber := string(request.TeamNumber())
411 collectedBy := parseUsername(req)
412
413 if handler.scoutingMap[teamNumber] == nil {
414 handler.scoutingMap[teamNumber] = map[string]time.Time{}
415 }
416 handler.scoutingMap[teamNumber][collectedBy] = currentTime
417 // Delete any scout information from 10+ seconds ago.
418 for team, teamMap := range handler.scoutingMap {
419 for name, timeStamp := range teamMap {
420 if currentTime.Sub(timeStamp) >= 10*time.Second {
421 delete(handler.scoutingMap[team], name)
422 }
423 }
424 }
425
426 var response RequestCurrentScoutingResponseT
427 for name, _ := range handler.scoutingMap[teamNumber] {
428 if name != collectedBy {
429 response.CollectedBy = append(response.CollectedBy, &request_current_scouting_response.CollectedByT{
430 Name: name,
431 })
432 }
433 }
434
435 builder := flatbuffers.NewBuilder(10)
436 builder.Finish((&response).Pack(builder))
437 w.Write(builder.FinishedBytes())
438}
439
Alex Perry81f96ba2022-03-13 18:26:19 -0700440type submitNoteScoutingHandler struct {
441 db Database
442}
443
444func (handler submitNoteScoutingHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
445 requestBytes, err := io.ReadAll(req.Body)
446 if err != nil {
447 respondWithError(w, http.StatusBadRequest, fmt.Sprint("Failed to read request bytes:", err))
448 return
449 }
450
Philipp Schraderb7e75932022-03-26 16:18:34 -0700451 request, success := parseRequest(w, requestBytes, "SubmitNotes", submit_notes.GetRootAsSubmitNotes)
Alex Perry81f96ba2022-03-13 18:26:19 -0700452 if !success {
453 return
454 }
455
Filip Kujawaf947cb42022-11-21 10:00:30 -0800456 err = handler.db.AddNotes(db.NotesData{
Emily Markovae68b7632023-12-30 14:17:55 -0800457 TeamNumber: string(request.Team()),
Filip Kujawa7ddd5652023-03-07 19:56:15 -0800458 Notes: string(request.Notes()),
459 GoodDriving: bool(request.GoodDriving()),
460 BadDriving: bool(request.BadDriving()),
Filip Kujawa11dc4c92023-04-13 08:55:43 -0700461 SolidPlacing: bool(request.SolidPlacing()),
Filip Kujawa7ddd5652023-03-07 19:56:15 -0800462 SketchyPlacing: bool(request.SketchyPlacing()),
463 GoodDefense: bool(request.GoodDefense()),
464 BadDefense: bool(request.BadDefense()),
465 EasilyDefended: bool(request.EasilyDefended()),
Emily Markovacf893f42024-03-13 19:03:10 -0700466 NoShow: bool(request.NoShow()),
467 MatchNumber: request.MatchNumber(),
468 SetNumber: request.SetNumber(),
469 CompLevel: string(request.CompLevel()),
Filip Kujawaf947cb42022-11-21 10:00:30 -0800470 })
Alex Perry81f96ba2022-03-13 18:26:19 -0700471 if err != nil {
472 respondWithError(w, http.StatusInternalServerError, fmt.Sprintf("Failed to insert notes: %v", err))
473 return
474 }
475
476 var response SubmitNotesResponseT
477 builder := flatbuffers.NewBuilder(10)
478 builder.Finish((&response).Pack(builder))
479 w.Write(builder.FinishedBytes())
480}
481
Emily Markovafaecfe12023-07-01 12:40:03 -0700482type submitPitImageScoutingHandler struct {
483 db Database
484}
485
486func (handler submitPitImageScoutingHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
487 requestBytes, err := io.ReadAll(req.Body)
488 if err != nil {
489 respondWithError(w, http.StatusBadRequest, fmt.Sprint("Failed to read request bytes:", err))
490 return
491 }
492
493 request, success := parseRequest(w, requestBytes, "SubmitPitImage", submit_pit_image.GetRootAsSubmitPitImage)
494 if !success {
495 return
496 }
497
498 err = handler.db.AddPitImage(db.PitImage{
499 TeamNumber: string(request.TeamNumber()),
500 CheckSum: db.ComputeSha256FromByteArray(request.ImageDataBytes()),
501 ImagePath: string(request.ImagePath()),
502 ImageData: request.ImageDataBytes(),
503 })
504 if err != nil {
505 respondWithError(w, http.StatusInternalServerError, fmt.Sprintf("Failed to insert notes: %v", err))
506 return
507 }
508
509 var response SubmitPitImageResponseT
510 builder := flatbuffers.NewBuilder(10)
511 builder.Finish((&response).Pack(builder))
512 w.Write(builder.FinishedBytes())
513}
514
Emily Markova8cb91312024-02-02 12:30:37 -0800515func ConvertActionsToStat2024(submit2024Actions *submit_2024_actions.Submit2024Actions) (db.Stats2024, error) {
516 overall_time := int64(0)
517 cycles := int64(0)
518 picked_up := false
519 lastPlacedTime := int64(0)
520 stat := db.Stats2024{
Emily Markova9c18e9c2024-04-03 20:06:27 -0700521 CompType: string(submit2024Actions.CompType()), TeamNumber: string(submit2024Actions.TeamNumber()),
522 MatchNumber: submit2024Actions.MatchNumber(), SetNumber: submit2024Actions.SetNumber(), CompLevel: string(submit2024Actions.CompLevel()),
Emily Markova8cb91312024-02-02 12:30:37 -0800523 StartingQuadrant: 0, SpeakerAuto: 0, AmpAuto: 0, NotesDroppedAuto: 0, MobilityAuto: false,
Emily Markovacd156942024-04-07 19:32:28 -0700524 Speaker: 0, Amp: 0, SpeakerAmplified: 0, NotesDropped: 0, Shuttled: 0, OutOfField: 0, Penalties: 0,
Emily Markovaf17f2812024-04-03 20:55:12 -0700525 TrapNote: false, Spotlight: false, AvgCycle: 0, Park: false, OnStage: false, Harmony: false, RobotDied: false, NoShow: false, CollectedBy: "",
Emily Markova8cb91312024-02-02 12:30:37 -0800526 }
527 // Loop over all actions.
528 for i := 0; i < submit2024Actions.ActionsListLength(); i++ {
529 var action submit_2024_actions.Action
530 if !submit2024Actions.ActionsList(&action, i) {
531 return db.Stats2024{}, errors.New(fmt.Sprintf("Failed to parse submit_2024_actions.Action"))
532 }
533 actionTable := new(flatbuffers.Table)
534 action_type := action.ActionTakenType()
535 if !action.ActionTaken(actionTable) {
536 return db.Stats2024{}, errors.New(fmt.Sprint("Failed to parse sub-action or sub-action was missing"))
537 }
538 if action_type == submit_2024_actions.ActionTypeStartMatchAction {
539 var startMatchAction submit_2024_actions.StartMatchAction
540 startMatchAction.Init(actionTable.Bytes, actionTable.Pos)
541 stat.StartingQuadrant = startMatchAction.Position()
542 } else if action_type == submit_2024_actions.ActionTypeMobilityAction {
543 var mobilityAction submit_2024_actions.MobilityAction
544 mobilityAction.Init(actionTable.Bytes, actionTable.Pos)
545 if mobilityAction.Mobility() {
546 stat.MobilityAuto = true
547 }
Emily Markova8cb91312024-02-02 12:30:37 -0800548 } else if action_type == submit_2024_actions.ActionTypePenaltyAction {
549 var penaltyAction submit_2024_actions.PenaltyAction
550 penaltyAction.Init(actionTable.Bytes, actionTable.Pos)
Emily Markovadcadcb62024-02-03 13:07:17 -0800551 stat.Penalties += penaltyAction.Penalties()
Emily Markova8cb91312024-02-02 12:30:37 -0800552
Emily Markova040123c2024-02-27 09:48:37 -0800553 } else if action_type == submit_2024_actions.ActionTypeRobotDeathAction {
554 var robotDeathAction submit_2024_actions.RobotDeathAction
555 robotDeathAction.Init(actionTable.Bytes, actionTable.Pos)
556 stat.RobotDied = true
557
Emily Markovaf17f2812024-04-03 20:55:12 -0700558 } else if action_type == submit_2024_actions.ActionTypeNoShowAction {
559 var NoShowAction submit_2024_actions.NoShowAction
560 NoShowAction.Init(actionTable.Bytes, actionTable.Pos)
561 stat.NoShow = true
562
Emily Markova8cb91312024-02-02 12:30:37 -0800563 } else if action_type == submit_2024_actions.ActionTypePickupNoteAction {
564 var pick_up_action submit_2024_actions.PickupNoteAction
565 pick_up_action.Init(actionTable.Bytes, actionTable.Pos)
Emily Markova040123c2024-02-27 09:48:37 -0800566 picked_up = true
Emily Markova8cb91312024-02-02 12:30:37 -0800567 } else if action_type == submit_2024_actions.ActionTypePlaceNoteAction {
568 var place_action submit_2024_actions.PlaceNoteAction
569 place_action.Init(actionTable.Bytes, actionTable.Pos)
570 if !picked_up {
571 return db.Stats2024{}, errors.New(fmt.Sprintf("Got PlaceNoteAction without corresponding PickupObjectAction"))
572 }
573 score_type := place_action.ScoreType()
574 auto := place_action.Auto()
Emily Markovacd156942024-04-07 19:32:28 -0700575 count_in_cycle := true
Emily Markova8cb91312024-02-02 12:30:37 -0800576 if score_type == submit_2024_actions.ScoreTypekAMP && auto {
577 stat.AmpAuto += 1
578 } else if score_type == submit_2024_actions.ScoreTypekAMP && !auto {
579 stat.Amp += 1
Emily Markova8cb91312024-02-02 12:30:37 -0800580 } else if score_type == submit_2024_actions.ScoreTypekSPEAKER && !auto {
581 stat.Speaker += 1
582 } else if score_type == submit_2024_actions.ScoreTypekSPEAKER && auto {
583 stat.SpeakerAuto += 1
584 } else if score_type == submit_2024_actions.ScoreTypekSPEAKER_AMPLIFIED && !auto {
585 stat.SpeakerAmplified += 1
Emily Markova040123c2024-02-27 09:48:37 -0800586 } else if score_type == submit_2024_actions.ScoreTypekDROPPED && auto {
587 stat.NotesDroppedAuto += 1
Emily Markovacd156942024-04-07 19:32:28 -0700588 count_in_cycle = false
Emily Markova040123c2024-02-27 09:48:37 -0800589 } else if score_type == submit_2024_actions.ScoreTypekDROPPED && !auto {
590 stat.NotesDropped += 1
Emily Markovacd156942024-04-07 19:32:28 -0700591 count_in_cycle = false
592 } else if score_type == submit_2024_actions.ScoreTypekSHUTTLED {
593 stat.Shuttled += 1
594 count_in_cycle = false
595 } else if score_type == submit_2024_actions.ScoreTypekOUT_OF_FIELD {
596 stat.OutOfField += 1
597 count_in_cycle = false
Emily Markova8cb91312024-02-02 12:30:37 -0800598 } else {
599 return db.Stats2024{}, errors.New(fmt.Sprintf("Got unknown ObjectType/ScoreLevel/Auto combination"))
600 }
601 picked_up = false
Emily Markovacd156942024-04-07 19:32:28 -0700602 if count_in_cycle {
603 // Assuming dropped, shuttled, and out of field
604 // notes are not counted in total cycle time.
605 if lastPlacedTime != int64(0) {
606 // If this is not the first time we place,
607 // start counting cycle time. We define cycle
608 // time as the time between placements.
609 overall_time += int64(action.Timestamp()) - lastPlacedTime
610 }
Emily Markova8cb91312024-02-02 12:30:37 -0800611 cycles += 1
Emily Markovacd156942024-04-07 19:32:28 -0700612 lastPlacedTime = int64(action.Timestamp())
Emily Markova8cb91312024-02-02 12:30:37 -0800613 }
Emily Markova8cb91312024-02-02 12:30:37 -0800614 } else if action_type == submit_2024_actions.ActionTypeEndMatchAction {
615 var endMatchAction submit_2024_actions.EndMatchAction
616 endMatchAction.Init(actionTable.Bytes, actionTable.Pos)
617 if endMatchAction.StageType() == submit_2024_actions.StageTypekON_STAGE {
618 stat.OnStage = true
619 } else if endMatchAction.StageType() == submit_2024_actions.StageTypekPARK {
620 stat.Park = true
621 } else if endMatchAction.StageType() == submit_2024_actions.StageTypekHARMONY {
622 stat.Harmony = true
623 }
624 stat.TrapNote = endMatchAction.TrapNote()
Emily Markova6079e2f2024-02-17 13:17:24 -0800625 stat.Spotlight = endMatchAction.Spotlight()
Emily Markova8cb91312024-02-02 12:30:37 -0800626 }
627 }
628 if cycles != 0 {
629 stat.AvgCycle = overall_time / cycles
630 } else {
631 stat.AvgCycle = 0
632 }
633 return stat, nil
634}
635
636// Handles a Request2024DataScouting request.
637type request2024DataScoutingHandler struct {
638 db Database
639}
640
641func (handler request2024DataScoutingHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
642 requestBytes, err := io.ReadAll(req.Body)
643 if err != nil {
644 respondWithError(w, http.StatusBadRequest, fmt.Sprint("Failed to read request bytes:", err))
645 return
646 }
647
648 _, success := parseRequest(w, requestBytes, "Request2024DataScouting", request_2024_data_scouting.GetRootAsRequest2024DataScouting)
649 if !success {
650 return
651 }
652
653 stats, err := handler.db.ReturnStats2024()
654 if err != nil {
655 respondWithError(w, http.StatusInternalServerError, fmt.Sprint("Failed to query database: ", err))
656 return
657 }
658
659 var response Request2024DataScoutingResponseT
660 for _, stat := range stats {
661 response.StatsList = append(response.StatsList, &request_2024_data_scouting_response.Stats2024T{
662 TeamNumber: stat.TeamNumber,
663 MatchNumber: stat.MatchNumber,
664 SetNumber: stat.SetNumber,
665 CompLevel: stat.CompLevel,
666 StartingQuadrant: stat.StartingQuadrant,
667 SpeakerAuto: stat.SpeakerAuto,
668 AmpAuto: stat.AmpAuto,
669 NotesDroppedAuto: stat.NotesDroppedAuto,
670 MobilityAuto: stat.MobilityAuto,
671 Speaker: stat.Speaker,
672 Amp: stat.Amp,
673 SpeakerAmplified: stat.SpeakerAmplified,
Emily Markova8cb91312024-02-02 12:30:37 -0800674 NotesDropped: stat.NotesDropped,
Emily Markovacd156942024-04-07 19:32:28 -0700675 Shuttled: stat.Shuttled,
676 OutOfField: stat.OutOfField,
Emily Markova8cb91312024-02-02 12:30:37 -0800677 Penalties: stat.Penalties,
678 TrapNote: stat.TrapNote,
Emily Markova6079e2f2024-02-17 13:17:24 -0800679 Spotlight: stat.Spotlight,
Emily Markova8cb91312024-02-02 12:30:37 -0800680 AvgCycle: stat.AvgCycle,
681 Park: stat.Park,
682 OnStage: stat.OnStage,
683 Harmony: stat.Harmony,
Emily Markova040123c2024-02-27 09:48:37 -0800684 RobotDied: stat.RobotDied,
Emily Markovaf17f2812024-04-03 20:55:12 -0700685 NoShow: stat.NoShow,
Emily Markova8cb91312024-02-02 12:30:37 -0800686 CollectedBy: stat.CollectedBy,
Emily Markova9c18e9c2024-04-03 20:06:27 -0700687 CompType: stat.CompType,
Emily Markova8cb91312024-02-02 12:30:37 -0800688 })
689 }
690
691 builder := flatbuffers.NewBuilder(50 * 1024)
692 builder.Finish((&response).Pack(builder))
693 w.Write(builder.FinishedBytes())
694}
695
Emily Markova1abe9782023-03-11 19:45:38 -0800696func ConvertActionsToStat(submitActions *submit_actions.SubmitActions) (db.Stats2023, error) {
697 overall_time := int64(0)
698 cycles := int64(0)
699 picked_up := false
700 lastPlacedTime := int64(0)
Philipp Schrader4b489222023-04-15 16:40:16 -0700701 stat := db.Stats2023{
702 PreScouting: submitActions.PreScouting(),
703 TeamNumber: string(submitActions.TeamNumber()), MatchNumber: submitActions.MatchNumber(), SetNumber: submitActions.SetNumber(), CompLevel: string(submitActions.CompLevel()),
Emily Markova1abe9782023-03-11 19:45:38 -0800704 StartingQuadrant: 0, LowCubesAuto: 0, MiddleCubesAuto: 0, HighCubesAuto: 0, CubesDroppedAuto: 0,
705 LowConesAuto: 0, MiddleConesAuto: 0, HighConesAuto: 0, ConesDroppedAuto: 0, LowCubes: 0, MiddleCubes: 0, HighCubes: 0,
Philipp Schradere11114f2023-04-15 17:04:25 -0700706 CubesDropped: 0, LowCones: 0, MiddleCones: 0, HighCones: 0, ConesDropped: 0, SuperchargedPieces: 0, AvgCycle: 0, CollectedBy: "",
Emily Markova1abe9782023-03-11 19:45:38 -0800707 }
708 // Loop over all actions.
709 for i := 0; i < submitActions.ActionsListLength(); i++ {
710 var action submit_actions.Action
711 if !submitActions.ActionsList(&action, i) {
712 return db.Stats2023{}, errors.New(fmt.Sprintf("Failed to parse submit_actions.Action"))
713 }
714 actionTable := new(flatbuffers.Table)
715 action_type := action.ActionTakenType()
716 if !action.ActionTaken(actionTable) {
717 return db.Stats2023{}, errors.New(fmt.Sprint("Failed to parse sub-action or sub-action was missing"))
718 }
719 if action_type == submit_actions.ActionTypeStartMatchAction {
720 var startMatchAction submit_actions.StartMatchAction
721 startMatchAction.Init(actionTable.Bytes, actionTable.Pos)
722 stat.StartingQuadrant = startMatchAction.Position()
Filip Kujawa0b4b1e52023-04-15 14:05:40 -0700723 } else if action_type == submit_actions.ActionTypeMobilityAction {
724 var mobilityAction submit_actions.MobilityAction
725 mobilityAction.Init(actionTable.Bytes, actionTable.Pos)
726 if mobilityAction.Mobility() {
727 stat.Mobility = true
728 }
729
Emily Markova46a69bf2023-03-22 20:45:52 -0700730 } else if action_type == submit_actions.ActionTypeAutoBalanceAction {
731 var autoBalanceAction submit_actions.AutoBalanceAction
732 autoBalanceAction.Init(actionTable.Bytes, actionTable.Pos)
733 if autoBalanceAction.Docked() {
734 stat.DockedAuto = true
735 }
736 if autoBalanceAction.Engaged() {
737 stat.EngagedAuto = true
738 }
Emily Markova63c63f62023-03-29 20:57:35 -0700739 if autoBalanceAction.BalanceAttempt() {
740 stat.BalanceAttemptAuto = true
741 }
Emily Markova1abe9782023-03-11 19:45:38 -0800742 } else if action_type == submit_actions.ActionTypePickupObjectAction {
743 var pick_up_action submit_actions.PickupObjectAction
744 pick_up_action.Init(actionTable.Bytes, actionTable.Pos)
745 if picked_up == true {
746 object := pick_up_action.ObjectType().String()
747 auto := pick_up_action.Auto()
748 if object == "kCube" && auto == false {
749 stat.CubesDropped += 1
750 } else if object == "kCube" && auto == true {
751 stat.CubesDroppedAuto += 1
752 } else if object == "kCone" && auto == false {
753 stat.ConesDropped += 1
754 } else if object == "kCube" && auto == true {
755 stat.ConesDroppedAuto += 1
756 }
757 } else {
758 picked_up = true
759 }
760 } else if action_type == submit_actions.ActionTypePlaceObjectAction {
761 var place_action submit_actions.PlaceObjectAction
762 place_action.Init(actionTable.Bytes, actionTable.Pos)
763 if !picked_up {
764 return db.Stats2023{}, errors.New(fmt.Sprintf("Got PlaceObjectAction without corresponding PickupObjectAction"))
765 }
766 object := place_action.ObjectType()
767 level := place_action.ScoreLevel()
768 auto := place_action.Auto()
769 if object == 0 && level == 0 && auto == true {
770 stat.LowCubesAuto += 1
771 } else if object == 0 && level == 0 && auto == false {
772 stat.LowCubes += 1
773 } else if object == 0 && level == 1 && auto == true {
774 stat.MiddleCubesAuto += 1
775 } else if object == 0 && level == 1 && auto == false {
776 stat.MiddleCubes += 1
777 } else if object == 0 && level == 2 && auto == true {
778 stat.HighCubesAuto += 1
779 } else if object == 0 && level == 2 && auto == false {
780 stat.HighCubes += 1
781 } else if object == 1 && level == 0 && auto == true {
782 stat.LowConesAuto += 1
783 } else if object == 1 && level == 0 && auto == false {
784 stat.LowCones += 1
785 } else if object == 1 && level == 1 && auto == true {
786 stat.MiddleConesAuto += 1
787 } else if object == 1 && level == 1 && auto == false {
788 stat.MiddleCones += 1
789 } else if object == 1 && level == 2 && auto == true {
790 stat.HighConesAuto += 1
791 } else if object == 1 && level == 2 && auto == false {
792 stat.HighCones += 1
Filip Kujawa7a045e72023-04-13 08:41:09 -0700793 } else if level == 3 {
794 stat.SuperchargedPieces += 1
Emily Markova1abe9782023-03-11 19:45:38 -0800795 } else {
796 return db.Stats2023{}, errors.New(fmt.Sprintf("Got unknown ObjectType/ScoreLevel/Auto combination"))
797 }
798 picked_up = false
799 if lastPlacedTime != int64(0) {
800 // If this is not the first time we place,
801 // start counting cycle time. We define cycle
802 // time as the time between placements.
803 overall_time += int64(action.Timestamp()) - lastPlacedTime
804 cycles += 1
805 }
806 lastPlacedTime = int64(action.Timestamp())
Emily Markova46a69bf2023-03-22 20:45:52 -0700807 } else if action_type == submit_actions.ActionTypeEndMatchAction {
808 var endMatchAction submit_actions.EndMatchAction
809 endMatchAction.Init(actionTable.Bytes, actionTable.Pos)
810 if endMatchAction.Docked() {
811 stat.Docked = true
812 }
813 if endMatchAction.Engaged() {
814 stat.Engaged = true
815 }
Emily Markova63c63f62023-03-29 20:57:35 -0700816 if endMatchAction.BalanceAttempt() {
817 stat.BalanceAttempt = true
818 }
Emily Markova1abe9782023-03-11 19:45:38 -0800819 }
820 }
821 if cycles != 0 {
Philipp Schrader8c878a22023-03-20 22:36:38 -0700822 stat.AvgCycle = overall_time / cycles
Emily Markova1abe9782023-03-11 19:45:38 -0800823 } else {
824 stat.AvgCycle = 0
825 }
826 return stat, nil
827}
828
Emily Markova290147d2023-03-03 22:40:06 -0800829// Handles a Request2023DataScouting request.
830type request2023DataScoutingHandler struct {
831 db Database
832}
833
834func (handler request2023DataScoutingHandler) 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, "Request2023DataScouting", request_2023_data_scouting.GetRootAsRequest2023DataScouting)
842 if !success {
843 return
844 }
845
846 stats, err := handler.db.ReturnStats2023()
847 if err != nil {
848 respondWithError(w, http.StatusInternalServerError, fmt.Sprint("Failed to query database: ", err))
849 return
850 }
851
852 var response Request2023DataScoutingResponseT
853 for _, stat := range stats {
854 response.StatsList = append(response.StatsList, &request_2023_data_scouting_response.Stats2023T{
Emily Markova63c63f62023-03-29 20:57:35 -0700855 TeamNumber: stat.TeamNumber,
856 MatchNumber: stat.MatchNumber,
857 SetNumber: stat.SetNumber,
858 CompLevel: stat.CompLevel,
859 StartingQuadrant: stat.StartingQuadrant,
860 LowCubesAuto: stat.LowCubesAuto,
861 MiddleCubesAuto: stat.MiddleCubesAuto,
862 HighCubesAuto: stat.HighCubesAuto,
863 CubesDroppedAuto: stat.CubesDroppedAuto,
864 LowConesAuto: stat.LowConesAuto,
865 MiddleConesAuto: stat.MiddleConesAuto,
866 HighConesAuto: stat.HighConesAuto,
867 ConesDroppedAuto: stat.ConesDroppedAuto,
868 LowCubes: stat.LowCubes,
869 MiddleCubes: stat.MiddleCubes,
870 HighCubes: stat.HighCubes,
871 CubesDropped: stat.CubesDropped,
872 LowCones: stat.LowCones,
873 MiddleCones: stat.MiddleCones,
874 HighCones: stat.HighCones,
875 ConesDropped: stat.ConesDropped,
Filip Kujawa7a045e72023-04-13 08:41:09 -0700876 SuperchargedPieces: stat.SuperchargedPieces,
Emily Markova63c63f62023-03-29 20:57:35 -0700877 AvgCycle: stat.AvgCycle,
Filip Kujawa0b4b1e52023-04-15 14:05:40 -0700878 Mobility: stat.Mobility,
Emily Markova63c63f62023-03-29 20:57:35 -0700879 DockedAuto: stat.DockedAuto,
880 EngagedAuto: stat.EngagedAuto,
881 BalanceAttemptAuto: stat.BalanceAttemptAuto,
882 Docked: stat.Docked,
883 Engaged: stat.Engaged,
884 BalanceAttempt: stat.BalanceAttempt,
885 CollectedBy: stat.CollectedBy,
Emily Markova290147d2023-03-03 22:40:06 -0800886 })
887 }
888
889 builder := flatbuffers.NewBuilder(50 * 1024)
890 builder.Finish((&response).Pack(builder))
891 w.Write(builder.FinishedBytes())
892}
893
Emily Markova8e39f452023-12-23 12:17:30 -0800894type requestAllPitImagesHandler struct {
895 db Database
896}
897
898func (handler requestAllPitImagesHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
899 requestBytes, err := io.ReadAll(req.Body)
900 if err != nil {
901 respondWithError(w, http.StatusBadRequest, fmt.Sprint("Failed to read request bytes:", err))
902 return
903 }
904
905 _, success := parseRequest(w, requestBytes, "RequestAllPitImages", request_all_pit_images.GetRootAsRequestAllPitImages)
906 if !success {
907 return
908 }
909
910 images, err := handler.db.ReturnPitImages()
911 if err != nil {
912 respondWithError(w, http.StatusInternalServerError, fmt.Sprintf("Failed to get pit images: %v", err))
913 return
914 }
915
916 var response RequestAllPitImagesResponseT
917 for _, data := range images {
918 response.PitImageList = append(response.PitImageList, &request_all_pit_images_response.PitImageT{
919 TeamNumber: data.TeamNumber,
920 ImagePath: data.ImagePath,
921 CheckSum: data.CheckSum,
922 })
923 }
924
925 builder := flatbuffers.NewBuilder(1024)
926 builder.Finish((&response).Pack(builder))
927 w.Write(builder.FinishedBytes())
928}
929
Emily Markovafaecfe12023-07-01 12:40:03 -0700930type requestPitImagesHandler struct {
931 db Database
932}
933
934func (handler requestPitImagesHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
935 requestBytes, err := io.ReadAll(req.Body)
936 if err != nil {
937 respondWithError(w, http.StatusBadRequest, fmt.Sprint("Failed to read request bytes:", err))
938 return
939 }
940
941 request, success := parseRequest(w, requestBytes, "RequestPitImages", request_pit_images.GetRootAsRequestPitImages)
942 if !success {
943 return
944 }
945
946 images, err := handler.db.QueryPitImages(string(request.TeamNumber()))
947 if err != nil {
948 respondWithError(w, http.StatusInternalServerError, fmt.Sprintf("Failed to query pit images: %v", err))
949 return
950 }
951
952 var response RequestPitImagesResponseT
953 for _, data := range images {
954 response.PitImageList = append(response.PitImageList, &request_pit_images_response.PitImageT{
955 TeamNumber: data.TeamNumber,
956 ImagePath: data.ImagePath,
957 CheckSum: data.CheckSum,
958 })
959 }
960
961 builder := flatbuffers.NewBuilder(1024)
962 builder.Finish((&response).Pack(builder))
963 w.Write(builder.FinishedBytes())
964}
965
Alex Perry81f96ba2022-03-13 18:26:19 -0700966type requestNotesForTeamHandler struct {
967 db Database
968}
969
970func (handler requestNotesForTeamHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
971 requestBytes, err := io.ReadAll(req.Body)
972 if err != nil {
973 respondWithError(w, http.StatusBadRequest, fmt.Sprint("Failed to read request bytes:", err))
974 return
975 }
976
Philipp Schraderb7e75932022-03-26 16:18:34 -0700977 request, success := parseRequest(w, requestBytes, "RequestNotesForTeam", request_notes_for_team.GetRootAsRequestNotesForTeam)
Alex Perry81f96ba2022-03-13 18:26:19 -0700978 if !success {
979 return
980 }
981
Emily Markovae68b7632023-12-30 14:17:55 -0800982 notes, err := handler.db.QueryNotes(string(request.Team()))
Alex Perry81f96ba2022-03-13 18:26:19 -0700983 if err != nil {
984 respondWithError(w, http.StatusInternalServerError, fmt.Sprintf("Failed to query notes: %v", err))
985 return
986 }
987
988 var response RequestNotesForTeamResponseT
Philipp Schradereecb8962022-06-01 21:02:42 -0700989 for _, data := range notes {
Alex Perry81f96ba2022-03-13 18:26:19 -0700990 response.Notes = append(response.Notes, &request_notes_for_team_response.NoteT{data})
991 }
992
993 builder := flatbuffers.NewBuilder(1024)
994 builder.Finish((&response).Pack(builder))
995 w.Write(builder.FinishedBytes())
996}
997
Milo Lin1d59f0c2022-06-22 20:30:58 -0700998type requestShiftScheduleHandler struct {
999 db Database
1000}
1001
1002func (handler requestShiftScheduleHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
1003 requestBytes, err := io.ReadAll(req.Body)
1004 if err != nil {
1005 respondWithError(w, http.StatusBadRequest, fmt.Sprint("Failed to read request bytes:", err))
1006 return
1007 }
1008
1009 _, success := parseRequest(w, requestBytes, "RequestShiftSchedule", request_shift_schedule.GetRootAsRequestShiftSchedule)
1010 if !success {
1011 return
1012 }
1013
1014 shiftData, err := handler.db.ReturnAllShifts()
1015 if err != nil {
1016 respondWithError(w, http.StatusInternalServerError, fmt.Sprintf("Failed to query shift schedule: %v", err))
1017 return
1018 }
1019
1020 var response RequestShiftScheduleResponseT
1021 for _, shifts := range shiftData {
1022 response.ShiftSchedule = append(response.ShiftSchedule, &request_shift_schedule_response.MatchAssignmentT{
1023 MatchNumber: shifts.MatchNumber,
Philipp Schrader2ff455b2023-05-03 22:11:50 -07001024 R1Scouter: shifts.R1scouter,
1025 R2Scouter: shifts.R2scouter,
1026 R3Scouter: shifts.R3scouter,
1027 B1Scouter: shifts.B1scouter,
1028 B2Scouter: shifts.B2scouter,
1029 B3Scouter: shifts.B3scouter,
Milo Lin1d59f0c2022-06-22 20:30:58 -07001030 })
1031 }
1032
1033 builder := flatbuffers.NewBuilder(1024)
1034 builder.Finish((&response).Pack(builder))
1035 w.Write(builder.FinishedBytes())
1036}
1037
1038type submitShiftScheduleHandler struct {
1039 db Database
1040}
1041
1042func (handler submitShiftScheduleHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
1043 // Get the username of the person submitting the data.
1044 username := parseUsername(req)
1045
1046 requestBytes, err := io.ReadAll(req.Body)
1047 if err != nil {
1048 respondWithError(w, http.StatusBadRequest, fmt.Sprint("Failed to read request bytes:", err))
1049 return
1050 }
1051
1052 request, success := parseRequest[SubmitShiftSchedule](w, requestBytes, "SubmitShiftSchedule", submit_shift_schedule.GetRootAsSubmitShiftSchedule)
1053 if !success {
1054 return
1055 }
1056
1057 log.Println("Got shift schedule from", username)
1058 shift_schedule_length := request.ShiftScheduleLength()
1059 for i := 0; i < shift_schedule_length; i++ {
1060 var match_assignment submit_shift_schedule.MatchAssignment
1061 request.ShiftSchedule(&match_assignment, i)
1062 current_shift := db.Shift{
1063 MatchNumber: match_assignment.MatchNumber(),
Philipp Schrader2ff455b2023-05-03 22:11:50 -07001064 R1scouter: string(match_assignment.R1Scouter()),
1065 R2scouter: string(match_assignment.R2Scouter()),
1066 R3scouter: string(match_assignment.R3Scouter()),
1067 B1scouter: string(match_assignment.B1Scouter()),
1068 B2scouter: string(match_assignment.B2Scouter()),
1069 B3scouter: string(match_assignment.B3Scouter()),
Milo Lin1d59f0c2022-06-22 20:30:58 -07001070 }
1071 err = handler.db.AddToShift(current_shift)
1072 if err != nil {
1073 respondWithError(w, http.StatusInternalServerError, fmt.Sprint("Failed to submit shift schedule: ", err))
1074 return
1075 }
1076 }
1077
1078 builder := flatbuffers.NewBuilder(50 * 1024)
1079 builder.Finish((&SubmitShiftScheduleResponseT{}).Pack(builder))
1080 w.Write(builder.FinishedBytes())
1081}
1082
Filip Kujawa210a03b2022-11-24 14:41:11 -08001083type SubmitDriverRankingHandler struct {
1084 db Database
1085}
1086
1087func (handler SubmitDriverRankingHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
1088 requestBytes, err := io.ReadAll(req.Body)
1089 if err != nil {
1090 respondWithError(w, http.StatusBadRequest, fmt.Sprint("Failed to read request bytes:", err))
1091 return
1092 }
1093
1094 request, success := parseRequest(w, requestBytes, "SubmitDriverRanking", submit_driver_ranking.GetRootAsSubmitDriverRanking)
1095 if !success {
1096 return
1097 }
1098
1099 err = handler.db.AddDriverRanking(db.DriverRankingData{
1100 MatchNumber: request.MatchNumber(),
Emily Markovae68b7632023-12-30 14:17:55 -08001101 Rank1: string(request.Rank1()),
1102 Rank2: string(request.Rank2()),
1103 Rank3: string(request.Rank3()),
Filip Kujawa210a03b2022-11-24 14:41:11 -08001104 })
1105
1106 if err != nil {
1107 respondWithError(w, http.StatusInternalServerError, fmt.Sprintf("Failed to insert driver ranking: %v", err))
1108 return
1109 }
1110
1111 var response SubmitDriverRankingResponseT
1112 builder := flatbuffers.NewBuilder(10)
1113 builder.Finish((&response).Pack(builder))
1114 w.Write(builder.FinishedBytes())
1115}
1116
Filip Kujawaf882e022022-12-14 13:14:08 -08001117type requestAllNotesHandler struct {
1118 db Database
1119}
1120
1121func (handler requestAllNotesHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
1122 requestBytes, err := io.ReadAll(req.Body)
1123 if err != nil {
1124 respondWithError(w, http.StatusBadRequest, fmt.Sprint("Failed to read request bytes:", err))
1125 return
1126 }
1127
1128 _, success := parseRequest(w, requestBytes, "RequestAllNotes", request_all_notes.GetRootAsRequestAllNotes)
1129 if !success {
1130 return
1131 }
1132
1133 notes, err := handler.db.ReturnAllNotes()
1134 if err != nil {
1135 respondWithError(w, http.StatusInternalServerError, fmt.Sprint("Failed to query database: ", err))
1136 return
1137 }
1138
1139 var response RequestAllNotesResponseT
1140 for _, note := range notes {
1141 response.NoteList = append(response.NoteList, &request_all_notes_response.NoteT{
Filip Kujawa7ddd5652023-03-07 19:56:15 -08001142 Team: note.TeamNumber,
1143 Notes: note.Notes,
1144 GoodDriving: note.GoodDriving,
1145 BadDriving: note.BadDriving,
Filip Kujawa11dc4c92023-04-13 08:55:43 -07001146 SolidPlacing: note.SolidPlacing,
Filip Kujawa7ddd5652023-03-07 19:56:15 -08001147 SketchyPlacing: note.SketchyPlacing,
1148 GoodDefense: note.GoodDefense,
1149 BadDefense: note.BadDefense,
1150 EasilyDefended: note.EasilyDefended,
Emily Markovacf893f42024-03-13 19:03:10 -07001151 NoShow: note.NoShow,
1152 MatchNumber: note.MatchNumber,
1153 CompLevel: note.CompLevel,
1154 SetNumber: note.SetNumber,
Filip Kujawaf882e022022-12-14 13:14:08 -08001155 })
1156 }
1157
1158 builder := flatbuffers.NewBuilder(50 * 1024)
1159 builder.Finish((&response).Pack(builder))
1160 w.Write(builder.FinishedBytes())
1161}
1162
1163type requestAllDriverRankingsHandler struct {
1164 db Database
1165}
1166
1167func (handler requestAllDriverRankingsHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
1168 requestBytes, err := io.ReadAll(req.Body)
1169 if err != nil {
1170 respondWithError(w, http.StatusBadRequest, fmt.Sprint("Failed to read request bytes:", err))
1171 return
1172 }
1173
1174 _, success := parseRequest(w, requestBytes, "RequestAllDriverRankings", request_all_driver_rankings.GetRootAsRequestAllDriverRankings)
1175 if !success {
1176 return
1177 }
1178
1179 rankings, err := handler.db.ReturnAllDriverRankings()
1180 if err != nil {
1181 respondWithError(w, http.StatusInternalServerError, fmt.Sprint("Failed to query database: ", err))
1182 return
1183 }
1184
1185 var response RequestAllDriverRankingsResponseT
1186 for _, ranking := range rankings {
1187 response.DriverRankingList = append(response.DriverRankingList, &request_all_driver_rankings_response.RankingT{
1188 MatchNumber: ranking.MatchNumber,
1189 Rank1: ranking.Rank1,
1190 Rank2: ranking.Rank2,
1191 Rank3: ranking.Rank3,
1192 })
1193 }
1194
1195 builder := flatbuffers.NewBuilder(50 * 1024)
1196 builder.Finish((&response).Pack(builder))
1197 w.Write(builder.FinishedBytes())
1198}
1199
Emily Markova8cb91312024-02-02 12:30:37 -08001200type submit2024ActionsHandler struct {
1201 db Database
1202}
1203
1204func (handler submit2024ActionsHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
1205 // Get the username of the person submitting the data.
1206 username := parseUsername(req)
1207
1208 requestBytes, err := io.ReadAll(req.Body)
1209 if err != nil {
Philipp Schradere9719242024-04-18 09:30:34 -07001210 log.Println("Failed to receive submission request from", username)
Emily Markova8cb91312024-02-02 12:30:37 -08001211 respondWithError(w, http.StatusBadRequest, fmt.Sprint("Failed to read request bytes:", err))
1212 return
1213 }
1214
1215 request, success := parseRequest(w, requestBytes, "Submit2024Actions", submit_2024_actions.GetRootAsSubmit2024Actions)
1216 if !success {
Philipp Schradere9719242024-04-18 09:30:34 -07001217 log.Println("Failed to parse submission request from", username)
Emily Markova8cb91312024-02-02 12:30:37 -08001218 return
1219 }
1220
Philipp Schradere9719242024-04-18 09:30:34 -07001221 log.Println("Got actions for match", request.MatchNumber(), "team", string(request.TeamNumber()), "type", string(request.CompType()), "from", username)
Emily Markova8cb91312024-02-02 12:30:37 -08001222
1223 for i := 0; i < request.ActionsListLength(); i++ {
1224
1225 var action Action2024
1226 request.ActionsList(&action, i)
1227
1228 dbAction := db.Action{
Emily Markova9c18e9c2024-04-03 20:06:27 -07001229 CompType: string(request.CompType()),
Emily Markova8cb91312024-02-02 12:30:37 -08001230 TeamNumber: string(request.TeamNumber()),
1231 MatchNumber: request.MatchNumber(),
1232 SetNumber: request.SetNumber(),
1233 CompLevel: string(request.CompLevel()),
1234 //TODO: Serialize CompletedAction
1235 CompletedAction: []byte{},
1236 Timestamp: action.Timestamp(),
1237 CollectedBy: username,
1238 }
1239
1240 // Do some error checking.
1241 if action.Timestamp() < 0 {
Philipp Schradere9719242024-04-18 09:30:34 -07001242 log.Println("Got action with invalid timestamp (", action.Timestamp(), ") from", username)
Emily Markova8cb91312024-02-02 12:30:37 -08001243 respondWithError(w, http.StatusBadRequest, fmt.Sprint(
1244 "Invalid timestamp field value of ", action.Timestamp()))
1245 return
1246 }
1247
1248 err = handler.db.AddAction(dbAction)
1249 if err != nil {
Philipp Schradere9719242024-04-18 09:30:34 -07001250 log.Println("Failed to add action from", username, "to the database:", err)
Emily Markova8cb91312024-02-02 12:30:37 -08001251 respondWithError(w, http.StatusInternalServerError, fmt.Sprint("Failed to add action to database: ", err))
1252 return
1253 }
1254 }
1255
1256 stats, err := ConvertActionsToStat2024(request)
1257 if err != nil {
Philipp Schradere9719242024-04-18 09:30:34 -07001258 log.Println("Failed to add action from", username, "to the database:", err)
Emily Markova8cb91312024-02-02 12:30:37 -08001259 respondWithError(w, http.StatusInternalServerError, fmt.Sprint("Failed to convert actions to stats: ", err))
1260 return
1261 }
1262
1263 stats.CollectedBy = username
1264
1265 err = handler.db.AddToStats2024(stats)
1266 if err != nil {
Philipp Schradere9719242024-04-18 09:30:34 -07001267 log.Println("Failed to submit stats from", username, "to the database:", err)
Emily Markovadcadcb62024-02-03 13:07:17 -08001268 respondWithError(w, http.StatusInternalServerError, fmt.Sprint("Failed to submit stats2024: ", stats, ": ", err))
Emily Markova8cb91312024-02-02 12:30:37 -08001269 return
1270 }
1271
1272 builder := flatbuffers.NewBuilder(50 * 1024)
Emily Markovadcadcb62024-02-03 13:07:17 -08001273 builder.Finish((&Submit2024ActionsResponseT{}).Pack(builder))
Emily Markova8cb91312024-02-02 12:30:37 -08001274 w.Write(builder.FinishedBytes())
Philipp Schradere9719242024-04-18 09:30:34 -07001275
1276 log.Println("Successfully added stats from", username)
Emily Markova8cb91312024-02-02 12:30:37 -08001277}
1278
Emily Markova8cb91312024-02-02 12:30:37 -08001279type Delete2024DataScoutingHandler struct {
1280 db Database
1281}
1282
1283func (handler Delete2024DataScoutingHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
1284 requestBytes, err := io.ReadAll(req.Body)
1285 if err != nil {
1286 respondWithError(w, http.StatusBadRequest, fmt.Sprint("Failed to read request bytes:", err))
1287 return
1288 }
1289
1290 request, success := parseRequest(w, requestBytes, "Delete2024DataScouting", delete_2024_data_scouting.GetRootAsDelete2024DataScouting)
1291 if !success {
1292 return
1293 }
1294
1295 err = handler.db.DeleteFromStats2024(
1296 string(request.CompLevel()),
1297 request.MatchNumber(),
1298 request.SetNumber(),
1299 string(request.TeamNumber()))
1300
1301 if err != nil {
1302 respondWithError(w, http.StatusInternalServerError, fmt.Sprintf("Failed to delete from stats2024: %v", err))
1303 return
1304 }
1305
1306 err = handler.db.DeleteFromActions(
1307 string(request.CompLevel()),
1308 request.MatchNumber(),
1309 request.SetNumber(),
1310 string(request.TeamNumber()))
1311
1312 if err != nil {
1313 respondWithError(w, http.StatusInternalServerError, fmt.Sprintf("Failed to delete from actions: %v", err))
1314 return
1315 }
1316
1317 var response Delete2024DataScoutingResponseT
1318 builder := flatbuffers.NewBuilder(10)
1319 builder.Finish((&response).Pack(builder))
1320 w.Write(builder.FinishedBytes())
1321}
1322
Filip Kujawac1ded372023-05-27 14:33:43 -07001323type Delete2023DataScoutingHandler struct {
1324 db Database
1325}
1326
1327func (handler Delete2023DataScoutingHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
1328 requestBytes, err := io.ReadAll(req.Body)
1329 if err != nil {
1330 respondWithError(w, http.StatusBadRequest, fmt.Sprint("Failed to read request bytes:", err))
1331 return
1332 }
1333
1334 request, success := parseRequest(w, requestBytes, "Delete2023DataScouting", delete_2023_data_scouting.GetRootAsDelete2023DataScouting)
1335 if !success {
1336 return
1337 }
1338
1339 err = handler.db.DeleteFromStats(
1340 string(request.CompLevel()),
1341 request.MatchNumber(),
1342 request.SetNumber(),
1343 string(request.TeamNumber()))
1344
1345 if err != nil {
1346 respondWithError(w, http.StatusInternalServerError, fmt.Sprintf("Failed to delete from stats: %v", err))
1347 return
1348 }
1349
1350 err = handler.db.DeleteFromActions(
1351 string(request.CompLevel()),
1352 request.MatchNumber(),
1353 request.SetNumber(),
1354 string(request.TeamNumber()))
1355
1356 if err != nil {
1357 respondWithError(w, http.StatusInternalServerError, fmt.Sprintf("Failed to delete from actions: %v", err))
1358 return
1359 }
1360
1361 var response Delete2023DataScoutingResponseT
1362 builder := flatbuffers.NewBuilder(10)
1363 builder.Finish((&response).Pack(builder))
1364 w.Write(builder.FinishedBytes())
1365}
1366
Emily Markova521725a2024-03-21 18:46:04 -07001367func HandleRequests(db Database, scoutingServer server.ScoutingServer, clock Clock) {
Philipp Schradercdb5cfc2022-02-20 14:57:07 -08001368 scoutingServer.HandleFunc("/requests", unknown)
Philipp Schradercbf5c6a2022-02-27 23:25:19 -08001369 scoutingServer.Handle("/requests/request/all_matches", requestAllMatchesHandler{db})
Filip Kujawaf882e022022-12-14 13:14:08 -08001370 scoutingServer.Handle("/requests/request/all_notes", requestAllNotesHandler{db})
1371 scoutingServer.Handle("/requests/request/all_driver_rankings", requestAllDriverRankingsHandler{db})
Emily Markova290147d2023-03-03 22:40:06 -08001372 scoutingServer.Handle("/requests/request/2023_data_scouting", request2023DataScoutingHandler{db})
Emily Markova8cb91312024-02-02 12:30:37 -08001373 scoutingServer.Handle("/requests/request/2024_data_scouting", request2024DataScoutingHandler{db})
Alex Perry81f96ba2022-03-13 18:26:19 -07001374 scoutingServer.Handle("/requests/submit/submit_notes", submitNoteScoutingHandler{db})
Emily Markovafaecfe12023-07-01 12:40:03 -07001375 scoutingServer.Handle("/requests/submit/submit_pit_image", submitPitImageScoutingHandler{db})
1376 scoutingServer.Handle("/requests/request/pit_images", requestPitImagesHandler{db})
Emily Markova8e39f452023-12-23 12:17:30 -08001377 scoutingServer.Handle("/requests/request/all_pit_images", requestAllPitImagesHandler{db})
Emily Markova521725a2024-03-21 18:46:04 -07001378 scoutingServer.Handle("/requests/request/current_scouting", requestCurrentScoutingHandler{make(map[string]map[string]time.Time), db, clock})
Alex Perry81f96ba2022-03-13 18:26:19 -07001379 scoutingServer.Handle("/requests/request/notes_for_team", requestNotesForTeamHandler{db})
Milo Lin1d59f0c2022-06-22 20:30:58 -07001380 scoutingServer.Handle("/requests/submit/shift_schedule", submitShiftScheduleHandler{db})
1381 scoutingServer.Handle("/requests/request/shift_schedule", requestShiftScheduleHandler{db})
Filip Kujawa210a03b2022-11-24 14:41:11 -08001382 scoutingServer.Handle("/requests/submit/submit_driver_ranking", SubmitDriverRankingHandler{db})
Emily Markova8cb91312024-02-02 12:30:37 -08001383 scoutingServer.Handle("/requests/submit/submit_2024_actions", submit2024ActionsHandler{db})
Filip Kujawac1ded372023-05-27 14:33:43 -07001384 scoutingServer.Handle("/requests/delete/delete_2023_data_scouting", Delete2023DataScoutingHandler{db})
Emily Markova8cb91312024-02-02 12:30:37 -08001385 scoutingServer.Handle("/requests/delete/delete_2024_data_scouting", Delete2024DataScoutingHandler{db})
Philipp Schradercdb5cfc2022-02-20 14:57:07 -08001386}