Philipp Schrader | cdb5cfc | 2022-02-20 14:57:07 -0800 | [diff] [blame] | 1 | package requests |
| 2 | |
| 3 | import ( |
Philipp Schrader | fae8a7e | 2022-03-13 22:51:54 -0700 | [diff] [blame] | 4 | "encoding/base64" |
Philipp Schrader | d3fac19 | 2022-03-02 20:35:46 -0800 | [diff] [blame] | 5 | "errors" |
Philipp Schrader | cdb5cfc | 2022-02-20 14:57:07 -0800 | [diff] [blame] | 6 | "fmt" |
| 7 | "io" |
Philipp Schrader | fae8a7e | 2022-03-13 22:51:54 -0700 | [diff] [blame] | 8 | "log" |
Philipp Schrader | cdb5cfc | 2022-02-20 14:57:07 -0800 | [diff] [blame] | 9 | "net/http" |
Emily Markova | bf24c9e | 2023-02-08 20:31:11 -0800 | [diff] [blame] | 10 | "sort" |
Philipp Schrader | d3fac19 | 2022-03-02 20:35:46 -0800 | [diff] [blame] | 11 | "strconv" |
| 12 | "strings" |
Emily Markova | 521725a | 2024-03-21 18:46:04 -0700 | [diff] [blame] | 13 | "time" |
Philipp Schrader | cdb5cfc | 2022-02-20 14:57:07 -0800 | [diff] [blame] | 14 | |
Philipp Schrader | 8747f1b | 2022-02-23 23:56:22 -0800 | [diff] [blame] | 15 | "github.com/frc971/971-Robot-Code/scouting/db" |
Emily Markova | 8cb9131 | 2024-02-02 12:30:37 -0800 | [diff] [blame] | 16 | "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/delete_2024_data_scouting" |
| 17 | "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/delete_2024_data_scouting_response" |
Philipp Schrader | cdb5cfc | 2022-02-20 14:57:07 -0800 | [diff] [blame] | 18 | "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/error_response" |
Emily Markova | 8cb9131 | 2024-02-02 12:30:37 -0800 | [diff] [blame] | 19 | "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_2024_data_scouting" |
| 20 | "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_2024_data_scouting_response" |
Filip Kujawa | f882e02 | 2022-12-14 13:14:08 -0800 | [diff] [blame] | 21 | "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_all_driver_rankings" |
| 22 | "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_all_driver_rankings_response" |
Philipp Schrader | cbf5c6a | 2022-02-27 23:25:19 -0800 | [diff] [blame] | 23 | "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_all_matches" |
| 24 | "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_all_matches_response" |
Filip Kujawa | f882e02 | 2022-12-14 13:14:08 -0800 | [diff] [blame] | 25 | "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_all_notes" |
| 26 | "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_all_notes_response" |
Emily Markova | 8e39f45 | 2023-12-23 12:17:30 -0800 | [diff] [blame] | 27 | "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_all_pit_images" |
| 28 | "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_all_pit_images_response" |
Emily Markova | 521725a | 2024-03-21 18:46:04 -0700 | [diff] [blame] | 29 | "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_current_scouting" |
| 30 | "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_current_scouting_response" |
Alex Perry | 81f96ba | 2022-03-13 18:26:19 -0700 | [diff] [blame] | 31 | "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_notes_for_team" |
| 32 | "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_notes_for_team_response" |
Emily Markova | faecfe1 | 2023-07-01 12:40:03 -0700 | [diff] [blame] | 33 | "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_pit_images" |
| 34 | "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_pit_images_response" |
Milo Lin | 1d59f0c | 2022-06-22 20:30:58 -0700 | [diff] [blame] | 35 | "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_shift_schedule" |
| 36 | "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_shift_schedule_response" |
Emily Markova | 8cb9131 | 2024-02-02 12:30:37 -0800 | [diff] [blame] | 37 | "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_2024_actions" |
| 38 | "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_2024_actions_response" |
Filip Kujawa | 210a03b | 2022-11-24 14:41:11 -0800 | [diff] [blame] | 39 | "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_driver_ranking" |
| 40 | "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_driver_ranking_response" |
Alex Perry | 81f96ba | 2022-03-13 18:26:19 -0700 | [diff] [blame] | 41 | "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_notes" |
| 42 | "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_notes_response" |
Emily Markova | faecfe1 | 2023-07-01 12:40:03 -0700 | [diff] [blame] | 43 | "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_pit_image" |
| 44 | "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_pit_image_response" |
Milo Lin | 1d59f0c | 2022-06-22 20:30:58 -0700 | [diff] [blame] | 45 | "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_shift_schedule" |
| 46 | "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_shift_schedule_response" |
Philipp Schrader | cdb5cfc | 2022-02-20 14:57:07 -0800 | [diff] [blame] | 47 | "github.com/frc971/971-Robot-Code/scouting/webserver/server" |
| 48 | flatbuffers "github.com/google/flatbuffers/go" |
| 49 | ) |
| 50 | |
Philipp Schrader | cbf5c6a | 2022-02-27 23:25:19 -0800 | [diff] [blame] | 51 | type RequestAllMatches = request_all_matches.RequestAllMatches |
| 52 | type RequestAllMatchesResponseT = request_all_matches_response.RequestAllMatchesResponseT |
Filip Kujawa | f882e02 | 2022-12-14 13:14:08 -0800 | [diff] [blame] | 53 | type RequestAllDriverRankings = request_all_driver_rankings.RequestAllDriverRankings |
| 54 | type RequestAllDriverRankingsResponseT = request_all_driver_rankings_response.RequestAllDriverRankingsResponseT |
| 55 | type RequestAllNotes = request_all_notes.RequestAllNotes |
| 56 | type RequestAllNotesResponseT = request_all_notes_response.RequestAllNotesResponseT |
Emily Markova | 8cb9131 | 2024-02-02 12:30:37 -0800 | [diff] [blame] | 57 | type Request2024DataScouting = request_2024_data_scouting.Request2024DataScouting |
| 58 | type Request2024DataScoutingResponseT = request_2024_data_scouting_response.Request2024DataScoutingResponseT |
Alex Perry | 81f96ba | 2022-03-13 18:26:19 -0700 | [diff] [blame] | 59 | type SubmitNotes = submit_notes.SubmitNotes |
| 60 | type SubmitNotesResponseT = submit_notes_response.SubmitNotesResponseT |
Emily Markova | faecfe1 | 2023-07-01 12:40:03 -0700 | [diff] [blame] | 61 | type SubmitPitImage = submit_pit_image.SubmitPitImage |
| 62 | type SubmitPitImageResponseT = submit_pit_image_response.SubmitPitImageResponseT |
| 63 | type RequestPitImages = request_pit_images.RequestPitImages |
| 64 | type RequestPitImagesResponseT = request_pit_images_response.RequestPitImagesResponseT |
Emily Markova | 8e39f45 | 2023-12-23 12:17:30 -0800 | [diff] [blame] | 65 | type RequestAllPitImages = request_all_pit_images.RequestAllPitImages |
| 66 | type RequestAllPitImagesResponseT = request_all_pit_images_response.RequestAllPitImagesResponseT |
Emily Markova | 521725a | 2024-03-21 18:46:04 -0700 | [diff] [blame] | 67 | type RequestCurrentScouting = request_current_scouting.RequestCurrentScouting |
| 68 | type RequestCurrentScoutingResponseT = request_current_scouting_response.RequestCurrentScoutingResponseT |
Alex Perry | 81f96ba | 2022-03-13 18:26:19 -0700 | [diff] [blame] | 69 | type RequestNotesForTeam = request_notes_for_team.RequestNotesForTeam |
| 70 | type RequestNotesForTeamResponseT = request_notes_for_team_response.RequestNotesForTeamResponseT |
Milo Lin | 1d59f0c | 2022-06-22 20:30:58 -0700 | [diff] [blame] | 71 | type RequestShiftSchedule = request_shift_schedule.RequestShiftSchedule |
| 72 | type RequestShiftScheduleResponseT = request_shift_schedule_response.RequestShiftScheduleResponseT |
| 73 | type SubmitShiftSchedule = submit_shift_schedule.SubmitShiftSchedule |
| 74 | type SubmitShiftScheduleResponseT = submit_shift_schedule_response.SubmitShiftScheduleResponseT |
Filip Kujawa | 210a03b | 2022-11-24 14:41:11 -0800 | [diff] [blame] | 75 | type SubmitDriverRanking = submit_driver_ranking.SubmitDriverRanking |
| 76 | type SubmitDriverRankingResponseT = submit_driver_ranking_response.SubmitDriverRankingResponseT |
Emily Markova | 8cb9131 | 2024-02-02 12:30:37 -0800 | [diff] [blame] | 77 | type Action2024 = submit_2024_actions.Action |
Emily Markova | 8cb9131 | 2024-02-02 12:30:37 -0800 | [diff] [blame] | 78 | type Submit2024Actions = submit_2024_actions.Submit2024Actions |
| 79 | type Submit2024ActionsResponseT = submit_2024_actions_response.Submit2024ActionsResponseT |
Emily Markova | 8cb9131 | 2024-02-02 12:30:37 -0800 | [diff] [blame] | 80 | type Delete2024DataScouting = delete_2024_data_scouting.Delete2024DataScouting |
| 81 | type Delete2024DataScoutingResponseT = delete_2024_data_scouting_response.Delete2024DataScoutingResponseT |
Philipp Schrader | cbf5c6a | 2022-02-27 23:25:19 -0800 | [diff] [blame] | 82 | |
Philipp Schrader | 8747f1b | 2022-02-23 23:56:22 -0800 | [diff] [blame] | 83 | // The interface we expect the database abstraction to conform to. |
| 84 | // We use an interface here because it makes unit testing easier. |
| 85 | type Database interface { |
Emily Markova | bf24c9e | 2023-02-08 20:31:11 -0800 | [diff] [blame] | 86 | AddToMatch(db.TeamMatch) error |
Milo Lin | 1d59f0c | 2022-06-22 20:30:58 -0700 | [diff] [blame] | 87 | AddToShift(db.Shift) error |
Emily Markova | 8cb9131 | 2024-02-02 12:30:37 -0800 | [diff] [blame] | 88 | AddToStats2024(db.Stats2024) error |
Emily Markova | bf24c9e | 2023-02-08 20:31:11 -0800 | [diff] [blame] | 89 | ReturnMatches() ([]db.TeamMatch, error) |
Filip Kujawa | f882e02 | 2022-12-14 13:14:08 -0800 | [diff] [blame] | 90 | ReturnAllNotes() ([]db.NotesData, error) |
| 91 | ReturnAllDriverRankings() ([]db.DriverRankingData, error) |
Milo Lin | 1d59f0c | 2022-06-22 20:30:58 -0700 | [diff] [blame] | 92 | ReturnAllShifts() ([]db.Shift, error) |
Emily Markova | 8cb9131 | 2024-02-02 12:30:37 -0800 | [diff] [blame] | 93 | ReturnStats2024() ([]db.Stats2024, error) |
Emily Markova | 9c18e9c | 2024-04-03 20:06:27 -0700 | [diff] [blame] | 94 | ReturnStats2024ForTeam(teamNumber string, matchNumber int32, setNumber int32, compLevel string, compType string) ([]db.Stats2024, error) |
Milo Lin | 1d59f0c | 2022-06-22 20:30:58 -0700 | [diff] [blame] | 95 | QueryAllShifts(int) ([]db.Shift, error) |
Emily Markova | e68b763 | 2023-12-30 14:17:55 -0800 | [diff] [blame] | 96 | QueryNotes(string) ([]string, error) |
Emily Markova | faecfe1 | 2023-07-01 12:40:03 -0700 | [diff] [blame] | 97 | QueryPitImages(string) ([]db.RequestedPitImage, error) |
Emily Markova | 8e39f45 | 2023-12-23 12:17:30 -0800 | [diff] [blame] | 98 | ReturnPitImages() ([]db.PitImage, error) |
Filip Kujawa | f947cb4 | 2022-11-21 10:00:30 -0800 | [diff] [blame] | 99 | AddNotes(db.NotesData) error |
Emily Markova | faecfe1 | 2023-07-01 12:40:03 -0700 | [diff] [blame] | 100 | AddPitImage(db.PitImage) error |
Filip Kujawa | 210a03b | 2022-11-24 14:41:11 -0800 | [diff] [blame] | 101 | AddDriverRanking(db.DriverRankingData) error |
Sabina Leaver | 9b4eb31 | 2023-02-20 19:58:17 -0800 | [diff] [blame] | 102 | AddAction(db.Action) error |
Emily Markova | 8cb9131 | 2024-02-02 12:30:37 -0800 | [diff] [blame] | 103 | DeleteFromStats2024(string, int32, int32, string) error |
Filip Kujawa | c1ded37 | 2023-05-27 14:33:43 -0700 | [diff] [blame] | 104 | DeleteFromActions(string, int32, int32, string) error |
Philipp Schrader | 8747f1b | 2022-02-23 23:56:22 -0800 | [diff] [blame] | 105 | } |
| 106 | |
Emily Markova | 521725a | 2024-03-21 18:46:04 -0700 | [diff] [blame] | 107 | type Clock interface { |
| 108 | Now() time.Time |
| 109 | } |
| 110 | |
| 111 | type RealClock struct{} |
| 112 | |
| 113 | func (RealClock) Now() time.Time { |
| 114 | return time.Now() |
| 115 | } |
| 116 | |
Philipp Schrader | cdb5cfc | 2022-02-20 14:57:07 -0800 | [diff] [blame] | 117 | // Handles unknown requests. Just returns a 404. |
| 118 | func unknown(w http.ResponseWriter, req *http.Request) { |
| 119 | w.WriteHeader(http.StatusNotFound) |
| 120 | } |
| 121 | |
| 122 | func respondWithError(w http.ResponseWriter, statusCode int, errorMessage string) { |
| 123 | builder := flatbuffers.NewBuilder(1024) |
| 124 | builder.Finish((&error_response.ErrorResponseT{ |
| 125 | ErrorMessage: errorMessage, |
| 126 | }).Pack(builder)) |
| 127 | w.WriteHeader(statusCode) |
| 128 | w.Write(builder.FinishedBytes()) |
| 129 | } |
| 130 | |
| 131 | func respondNotImplemented(w http.ResponseWriter) { |
| 132 | respondWithError(w, http.StatusNotImplemented, "") |
| 133 | } |
| 134 | |
Philipp Schrader | b7e7593 | 2022-03-26 16:18:34 -0700 | [diff] [blame] | 135 | func parseRequest[T interface{}](w http.ResponseWriter, buf []byte, requestName string, parser func([]byte, flatbuffers.UOffsetT) *T) (*T, bool) { |
Philipp Schrader | cdb5cfc | 2022-02-20 14:57:07 -0800 | [diff] [blame] | 136 | success := true |
| 137 | defer func() { |
| 138 | if r := recover(); r != nil { |
Philipp Schrader | b7e7593 | 2022-03-26 16:18:34 -0700 | [diff] [blame] | 139 | respondWithError(w, http.StatusBadRequest, fmt.Sprintf("Failed to parse %s: %v", requestName, r)) |
Philipp Schrader | cdb5cfc | 2022-02-20 14:57:07 -0800 | [diff] [blame] | 140 | success = false |
| 141 | } |
| 142 | }() |
Philipp Schrader | b7e7593 | 2022-03-26 16:18:34 -0700 | [diff] [blame] | 143 | result := parser(buf, 0) |
Philipp Schrader | cdb5cfc | 2022-02-20 14:57:07 -0800 | [diff] [blame] | 144 | return result, success |
| 145 | } |
| 146 | |
Philipp Schrader | fae8a7e | 2022-03-13 22:51:54 -0700 | [diff] [blame] | 147 | // Parses the authorization information that the browser inserts into the |
| 148 | // headers. The authorization follows this format: |
| 149 | // |
Philipp Schrader | 35bb153 | 2023-03-05 13:49:12 -0800 | [diff] [blame] | 150 | // req.Headers["Authorization"] = []string{"Basic <base64 encoded username:password>"} |
Philipp Schrader | fae8a7e | 2022-03-13 22:51:54 -0700 | [diff] [blame] | 151 | func parseUsername(req *http.Request) string { |
| 152 | auth, ok := req.Header["Authorization"] |
| 153 | if !ok { |
| 154 | return "unknown" |
| 155 | } |
| 156 | |
| 157 | parts := strings.Split(auth[0], " ") |
| 158 | if !(len(parts) == 2 && parts[0] == "Basic") { |
| 159 | return "unknown" |
| 160 | } |
| 161 | |
| 162 | info, err := base64.StdEncoding.DecodeString(parts[1]) |
| 163 | if err != nil { |
| 164 | log.Println("ERROR: Failed to parse Basic authentication.") |
| 165 | return "unknown" |
| 166 | } |
| 167 | |
| 168 | loginParts := strings.Split(string(info), ":") |
| 169 | if len(loginParts) != 2 { |
| 170 | return "unknown" |
| 171 | } |
| 172 | return loginParts[0] |
| 173 | } |
| 174 | |
Philipp Schrader | cbf5c6a | 2022-02-27 23:25:19 -0800 | [diff] [blame] | 175 | // Handles a RequestAllMaches request. |
| 176 | type requestAllMatchesHandler struct { |
| 177 | db Database |
| 178 | } |
| 179 | |
Philipp Schrader | 0f7b636 | 2023-03-11 14:02:48 -0800 | [diff] [blame] | 180 | // Change structure of match objects in the database(1 per team) to |
| 181 | // the old match structure(1 per match) that the webserver uses. |
| 182 | // We use the information in this struct to identify which match object |
| 183 | // corresponds to which old match structure object. |
| 184 | type MatchAssemblyKey struct { |
| 185 | MatchNumber int32 |
| 186 | SetNumber int32 |
| 187 | CompLevel string |
| 188 | } |
| 189 | |
Emily Markova | bf24c9e | 2023-02-08 20:31:11 -0800 | [diff] [blame] | 190 | func findIndexInList(list []string, comp_level string) (int, error) { |
| 191 | for index, value := range list { |
| 192 | if value == comp_level { |
| 193 | return index, nil |
| 194 | } |
| 195 | } |
| 196 | return -1, errors.New(fmt.Sprint("Failed to find comp level ", comp_level, " in list ", list)) |
| 197 | } |
| 198 | |
Emily Markova | b855157 | 2023-03-22 19:49:39 -0700 | [diff] [blame] | 199 | func (handler requestAllMatchesHandler) teamHasBeenDataScouted(key MatchAssemblyKey, teamNumber string) (bool, error) { |
Emily Markova | dcadcb6 | 2024-02-03 13:07:17 -0800 | [diff] [blame] | 200 | stats, err := handler.db.ReturnStats2024ForTeam( |
Emily Markova | 9c18e9c | 2024-04-03 20:06:27 -0700 | [diff] [blame] | 201 | teamNumber, key.MatchNumber, key.SetNumber, key.CompLevel, "Regular") |
Philipp Schrader | 0f7b636 | 2023-03-11 14:02:48 -0800 | [diff] [blame] | 202 | if err != nil { |
| 203 | return false, err |
| 204 | } |
| 205 | return (len(stats) > 0), nil |
| 206 | } |
| 207 | |
Philipp Schrader | cbf5c6a | 2022-02-27 23:25:19 -0800 | [diff] [blame] | 208 | func (handler requestAllMatchesHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { |
| 209 | requestBytes, err := io.ReadAll(req.Body) |
| 210 | if err != nil { |
| 211 | respondWithError(w, http.StatusBadRequest, fmt.Sprint("Failed to read request bytes:", err)) |
| 212 | return |
| 213 | } |
| 214 | |
Philipp Schrader | b7e7593 | 2022-03-26 16:18:34 -0700 | [diff] [blame] | 215 | _, success := parseRequest(w, requestBytes, "RequestAllMatches", request_all_matches.GetRootAsRequestAllMatches) |
Philipp Schrader | cbf5c6a | 2022-02-27 23:25:19 -0800 | [diff] [blame] | 216 | if !success { |
| 217 | return |
| 218 | } |
| 219 | |
| 220 | matches, err := handler.db.ReturnMatches() |
| 221 | if err != nil { |
Philipp Schrader | fae8a7e | 2022-03-13 22:51:54 -0700 | [diff] [blame] | 222 | respondWithError(w, http.StatusInternalServerError, fmt.Sprint("Failed to query database: ", err)) |
Philipp Schrader | 2e7eb000 | 2022-03-02 22:52:39 -0800 | [diff] [blame] | 223 | return |
Philipp Schrader | cbf5c6a | 2022-02-27 23:25:19 -0800 | [diff] [blame] | 224 | } |
| 225 | |
Philipp Schrader | 0f7b636 | 2023-03-11 14:02:48 -0800 | [diff] [blame] | 226 | assembledMatches := map[MatchAssemblyKey]request_all_matches_response.MatchT{} |
Emily Markova | bf24c9e | 2023-02-08 20:31:11 -0800 | [diff] [blame] | 227 | |
Philipp Schrader | cbf5c6a | 2022-02-27 23:25:19 -0800 | [diff] [blame] | 228 | for _, match := range matches { |
Philipp Schrader | 0f7b636 | 2023-03-11 14:02:48 -0800 | [diff] [blame] | 229 | key := MatchAssemblyKey{match.MatchNumber, match.SetNumber, match.CompLevel} |
| 230 | |
| 231 | // Retrieve the converted match structure we have assembled so |
| 232 | // far. If we haven't started assembling one yet, then start a |
| 233 | // new one. |
Emily Markova | bf24c9e | 2023-02-08 20:31:11 -0800 | [diff] [blame] | 234 | entry, ok := assembledMatches[key] |
| 235 | if !ok { |
| 236 | entry = request_all_matches_response.MatchT{ |
| 237 | MatchNumber: match.MatchNumber, |
| 238 | SetNumber: match.SetNumber, |
| 239 | CompLevel: match.CompLevel, |
Philipp Schrader | 0f7b636 | 2023-03-11 14:02:48 -0800 | [diff] [blame] | 240 | DataScouted: &request_all_matches_response.ScoutedLevelT{}, |
Emily Markova | bf24c9e | 2023-02-08 20:31:11 -0800 | [diff] [blame] | 241 | } |
| 242 | } |
Philipp Schrader | 0f7b636 | 2023-03-11 14:02:48 -0800 | [diff] [blame] | 243 | |
Emily Markova | b855157 | 2023-03-22 19:49:39 -0700 | [diff] [blame] | 244 | var team *string |
Philipp Schrader | 0f7b636 | 2023-03-11 14:02:48 -0800 | [diff] [blame] | 245 | var dataScoutedTeam *bool |
| 246 | |
| 247 | // Fill in the field for the match that we have in in the |
| 248 | // database. In the database, each match row only has 1 team |
| 249 | // number. |
Emily Markova | bf24c9e | 2023-02-08 20:31:11 -0800 | [diff] [blame] | 250 | switch match.Alliance { |
| 251 | case "R": |
| 252 | switch match.AlliancePosition { |
| 253 | case 1: |
Philipp Schrader | 0f7b636 | 2023-03-11 14:02:48 -0800 | [diff] [blame] | 254 | team = &entry.R1 |
| 255 | dataScoutedTeam = &entry.DataScouted.R1 |
Emily Markova | bf24c9e | 2023-02-08 20:31:11 -0800 | [diff] [blame] | 256 | case 2: |
Philipp Schrader | 0f7b636 | 2023-03-11 14:02:48 -0800 | [diff] [blame] | 257 | team = &entry.R2 |
| 258 | dataScoutedTeam = &entry.DataScouted.R2 |
Emily Markova | bf24c9e | 2023-02-08 20:31:11 -0800 | [diff] [blame] | 259 | case 3: |
Philipp Schrader | 0f7b636 | 2023-03-11 14:02:48 -0800 | [diff] [blame] | 260 | team = &entry.R3 |
| 261 | dataScoutedTeam = &entry.DataScouted.R3 |
Emily Markova | bf24c9e | 2023-02-08 20:31:11 -0800 | [diff] [blame] | 262 | default: |
| 263 | respondWithError(w, http.StatusInternalServerError, fmt.Sprint("Unknown red position ", strconv.Itoa(int(match.AlliancePosition)), " in match ", strconv.Itoa(int(match.MatchNumber)))) |
| 264 | return |
| 265 | } |
| 266 | case "B": |
| 267 | switch match.AlliancePosition { |
| 268 | case 1: |
Philipp Schrader | 0f7b636 | 2023-03-11 14:02:48 -0800 | [diff] [blame] | 269 | team = &entry.B1 |
| 270 | dataScoutedTeam = &entry.DataScouted.B1 |
Emily Markova | bf24c9e | 2023-02-08 20:31:11 -0800 | [diff] [blame] | 271 | case 2: |
Philipp Schrader | 0f7b636 | 2023-03-11 14:02:48 -0800 | [diff] [blame] | 272 | team = &entry.B2 |
| 273 | dataScoutedTeam = &entry.DataScouted.B2 |
Emily Markova | bf24c9e | 2023-02-08 20:31:11 -0800 | [diff] [blame] | 274 | case 3: |
Philipp Schrader | 0f7b636 | 2023-03-11 14:02:48 -0800 | [diff] [blame] | 275 | team = &entry.B3 |
| 276 | dataScoutedTeam = &entry.DataScouted.B3 |
Emily Markova | bf24c9e | 2023-02-08 20:31:11 -0800 | [diff] [blame] | 277 | default: |
| 278 | respondWithError(w, http.StatusInternalServerError, fmt.Sprint("Unknown blue position ", strconv.Itoa(int(match.AlliancePosition)), " in match ", strconv.Itoa(int(match.MatchNumber)))) |
| 279 | return |
| 280 | } |
| 281 | default: |
| 282 | respondWithError(w, http.StatusInternalServerError, fmt.Sprint("Unknown alliance ", match.Alliance, " in match ", strconv.Itoa(int(match.AlliancePosition)))) |
| 283 | return |
| 284 | } |
Philipp Schrader | 0f7b636 | 2023-03-11 14:02:48 -0800 | [diff] [blame] | 285 | |
| 286 | *team = match.TeamNumber |
| 287 | |
| 288 | // Figure out if this team has been data scouted already. |
| 289 | *dataScoutedTeam, err = handler.teamHasBeenDataScouted(key, match.TeamNumber) |
| 290 | if err != nil { |
| 291 | respondWithError(w, http.StatusInternalServerError, fmt.Sprint( |
| 292 | "Failed to determine data scouting status for team ", |
| 293 | strconv.Itoa(int(match.AlliancePosition)), |
| 294 | " in match ", |
| 295 | strconv.Itoa(int(match.MatchNumber)), |
| 296 | err)) |
| 297 | return |
| 298 | } |
| 299 | |
Emily Markova | bf24c9e | 2023-02-08 20:31:11 -0800 | [diff] [blame] | 300 | assembledMatches[key] = entry |
| 301 | } |
| 302 | |
| 303 | var response RequestAllMatchesResponseT |
| 304 | for _, match := range assembledMatches { |
| 305 | copied_match := match |
| 306 | response.MatchList = append(response.MatchList, &copied_match) |
| 307 | } |
| 308 | |
| 309 | var MATCH_TYPE_ORDERING = []string{"qm", "ef", "qf", "sf", "f"} |
| 310 | |
| 311 | err = nil |
| 312 | sort.Slice(response.MatchList, func(i, j int) bool { |
| 313 | if err != nil { |
| 314 | return false |
| 315 | } |
| 316 | a := response.MatchList[i] |
| 317 | b := response.MatchList[j] |
| 318 | |
Emily Markova | abcac6e | 2023-02-18 17:50:03 -0800 | [diff] [blame] | 319 | aMatchTypeIndex, err2 := findIndexInList(MATCH_TYPE_ORDERING, a.CompLevel) |
| 320 | if err2 != nil { |
| 321 | err = errors.New(fmt.Sprint("Comp level ", a.CompLevel, " not found in sorting list ", MATCH_TYPE_ORDERING, " : ", err2)) |
Emily Markova | bf24c9e | 2023-02-08 20:31:11 -0800 | [diff] [blame] | 322 | return false |
| 323 | } |
Emily Markova | abcac6e | 2023-02-18 17:50:03 -0800 | [diff] [blame] | 324 | bMatchTypeIndex, err2 := findIndexInList(MATCH_TYPE_ORDERING, b.CompLevel) |
| 325 | if err2 != nil { |
| 326 | err = errors.New(fmt.Sprint("Comp level ", b.CompLevel, " not found in sorting list ", MATCH_TYPE_ORDERING, " : ", err2)) |
Emily Markova | bf24c9e | 2023-02-08 20:31:11 -0800 | [diff] [blame] | 327 | return false |
| 328 | } |
| 329 | |
| 330 | if aMatchTypeIndex < bMatchTypeIndex { |
| 331 | return true |
| 332 | } |
| 333 | if aMatchTypeIndex > bMatchTypeIndex { |
| 334 | return false |
| 335 | } |
| 336 | |
| 337 | // Then sort by match number. E.g. in semi finals, all match 1 rounds |
| 338 | // are done first. Then come match 2 rounds. And then, if necessary, |
| 339 | // the match 3 rounds. |
| 340 | aMatchNumber := a.MatchNumber |
| 341 | bMatchNumber := b.MatchNumber |
| 342 | if aMatchNumber < bMatchNumber { |
| 343 | return true |
| 344 | } |
| 345 | if aMatchNumber > bMatchNumber { |
| 346 | return false |
| 347 | } |
| 348 | // Lastly, sort by set number. I.e. Semi Final 1 Match 1 happens first. |
| 349 | // Then comes Semi Final 2 Match 1. Then comes Semi Final 1 Match 2. Then |
| 350 | // Semi Final 2 Match 2. |
| 351 | aSetNumber := a.SetNumber |
| 352 | bSetNumber := b.SetNumber |
| 353 | if aSetNumber < bSetNumber { |
| 354 | return true |
| 355 | } |
| 356 | if aSetNumber > bSetNumber { |
| 357 | return false |
| 358 | } |
| 359 | return true |
| 360 | }) |
| 361 | |
| 362 | if err != nil { |
| 363 | // check if error happened during sorting and notify webpage if that |
| 364 | respondWithError(w, http.StatusInternalServerError, fmt.Sprint(err)) |
| 365 | return |
Philipp Schrader | cbf5c6a | 2022-02-27 23:25:19 -0800 | [diff] [blame] | 366 | } |
| 367 | |
| 368 | builder := flatbuffers.NewBuilder(50 * 1024) |
| 369 | builder.Finish((&response).Pack(builder)) |
| 370 | w.Write(builder.FinishedBytes()) |
| 371 | } |
| 372 | |
Emily Markova | 521725a | 2024-03-21 18:46:04 -0700 | [diff] [blame] | 373 | type requestCurrentScoutingHandler struct { |
| 374 | // Map that has a key of team number with a value is a map of names to timestamps |
| 375 | // so there aren't duplicate timestamps for one person. |
| 376 | scoutingMap map[string]map[string]time.Time |
| 377 | db Database |
| 378 | clock Clock |
| 379 | } |
| 380 | |
| 381 | func (handler requestCurrentScoutingHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { |
| 382 | requestBytes, err := io.ReadAll(req.Body) |
| 383 | if err != nil { |
| 384 | respondWithError(w, http.StatusBadRequest, fmt.Sprint("Failed to read request bytes:", err)) |
| 385 | return |
| 386 | } |
| 387 | |
| 388 | request, success := parseRequest(w, requestBytes, "RequestCurrentScouting", request_current_scouting.GetRootAsRequestCurrentScouting) |
| 389 | if !success { |
| 390 | return |
| 391 | } |
| 392 | currentTime := handler.clock.Now() |
| 393 | teamNumber := string(request.TeamNumber()) |
| 394 | collectedBy := parseUsername(req) |
| 395 | |
| 396 | if handler.scoutingMap[teamNumber] == nil { |
| 397 | handler.scoutingMap[teamNumber] = map[string]time.Time{} |
| 398 | } |
| 399 | handler.scoutingMap[teamNumber][collectedBy] = currentTime |
| 400 | // Delete any scout information from 10+ seconds ago. |
| 401 | for team, teamMap := range handler.scoutingMap { |
| 402 | for name, timeStamp := range teamMap { |
| 403 | if currentTime.Sub(timeStamp) >= 10*time.Second { |
| 404 | delete(handler.scoutingMap[team], name) |
| 405 | } |
| 406 | } |
| 407 | } |
| 408 | |
| 409 | var response RequestCurrentScoutingResponseT |
| 410 | for name, _ := range handler.scoutingMap[teamNumber] { |
| 411 | if name != collectedBy { |
| 412 | response.CollectedBy = append(response.CollectedBy, &request_current_scouting_response.CollectedByT{ |
| 413 | Name: name, |
| 414 | }) |
| 415 | } |
| 416 | } |
| 417 | |
| 418 | builder := flatbuffers.NewBuilder(10) |
| 419 | builder.Finish((&response).Pack(builder)) |
| 420 | w.Write(builder.FinishedBytes()) |
| 421 | } |
| 422 | |
Alex Perry | 81f96ba | 2022-03-13 18:26:19 -0700 | [diff] [blame] | 423 | type submitNoteScoutingHandler struct { |
| 424 | db Database |
| 425 | } |
| 426 | |
| 427 | func (handler submitNoteScoutingHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { |
| 428 | requestBytes, err := io.ReadAll(req.Body) |
| 429 | if err != nil { |
| 430 | respondWithError(w, http.StatusBadRequest, fmt.Sprint("Failed to read request bytes:", err)) |
| 431 | return |
| 432 | } |
| 433 | |
Philipp Schrader | b7e7593 | 2022-03-26 16:18:34 -0700 | [diff] [blame] | 434 | request, success := parseRequest(w, requestBytes, "SubmitNotes", submit_notes.GetRootAsSubmitNotes) |
Alex Perry | 81f96ba | 2022-03-13 18:26:19 -0700 | [diff] [blame] | 435 | if !success { |
| 436 | return |
| 437 | } |
| 438 | |
Filip Kujawa | f947cb4 | 2022-11-21 10:00:30 -0800 | [diff] [blame] | 439 | err = handler.db.AddNotes(db.NotesData{ |
Emily Markova | e68b763 | 2023-12-30 14:17:55 -0800 | [diff] [blame] | 440 | TeamNumber: string(request.Team()), |
Filip Kujawa | 7ddd565 | 2023-03-07 19:56:15 -0800 | [diff] [blame] | 441 | Notes: string(request.Notes()), |
| 442 | GoodDriving: bool(request.GoodDriving()), |
| 443 | BadDriving: bool(request.BadDriving()), |
Filip Kujawa | 11dc4c9 | 2023-04-13 08:55:43 -0700 | [diff] [blame] | 444 | SolidPlacing: bool(request.SolidPlacing()), |
Filip Kujawa | 7ddd565 | 2023-03-07 19:56:15 -0800 | [diff] [blame] | 445 | SketchyPlacing: bool(request.SketchyPlacing()), |
| 446 | GoodDefense: bool(request.GoodDefense()), |
| 447 | BadDefense: bool(request.BadDefense()), |
| 448 | EasilyDefended: bool(request.EasilyDefended()), |
Emily Markova | cf893f4 | 2024-03-13 19:03:10 -0700 | [diff] [blame] | 449 | NoShow: bool(request.NoShow()), |
| 450 | MatchNumber: request.MatchNumber(), |
| 451 | SetNumber: request.SetNumber(), |
| 452 | CompLevel: string(request.CompLevel()), |
Filip Kujawa | f947cb4 | 2022-11-21 10:00:30 -0800 | [diff] [blame] | 453 | }) |
Alex Perry | 81f96ba | 2022-03-13 18:26:19 -0700 | [diff] [blame] | 454 | if err != nil { |
| 455 | respondWithError(w, http.StatusInternalServerError, fmt.Sprintf("Failed to insert notes: %v", err)) |
| 456 | return |
| 457 | } |
| 458 | |
| 459 | var response SubmitNotesResponseT |
| 460 | builder := flatbuffers.NewBuilder(10) |
| 461 | builder.Finish((&response).Pack(builder)) |
| 462 | w.Write(builder.FinishedBytes()) |
| 463 | } |
| 464 | |
Emily Markova | faecfe1 | 2023-07-01 12:40:03 -0700 | [diff] [blame] | 465 | type submitPitImageScoutingHandler struct { |
| 466 | db Database |
| 467 | } |
| 468 | |
| 469 | func (handler submitPitImageScoutingHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { |
| 470 | requestBytes, err := io.ReadAll(req.Body) |
| 471 | if err != nil { |
| 472 | respondWithError(w, http.StatusBadRequest, fmt.Sprint("Failed to read request bytes:", err)) |
| 473 | return |
| 474 | } |
| 475 | |
| 476 | request, success := parseRequest(w, requestBytes, "SubmitPitImage", submit_pit_image.GetRootAsSubmitPitImage) |
| 477 | if !success { |
| 478 | return |
| 479 | } |
| 480 | |
| 481 | err = handler.db.AddPitImage(db.PitImage{ |
| 482 | TeamNumber: string(request.TeamNumber()), |
| 483 | CheckSum: db.ComputeSha256FromByteArray(request.ImageDataBytes()), |
| 484 | ImagePath: string(request.ImagePath()), |
| 485 | ImageData: request.ImageDataBytes(), |
| 486 | }) |
| 487 | if err != nil { |
| 488 | respondWithError(w, http.StatusInternalServerError, fmt.Sprintf("Failed to insert notes: %v", err)) |
| 489 | return |
| 490 | } |
| 491 | |
| 492 | var response SubmitPitImageResponseT |
| 493 | builder := flatbuffers.NewBuilder(10) |
| 494 | builder.Finish((&response).Pack(builder)) |
| 495 | w.Write(builder.FinishedBytes()) |
| 496 | } |
| 497 | |
Emily Markova | 8cb9131 | 2024-02-02 12:30:37 -0800 | [diff] [blame] | 498 | func ConvertActionsToStat2024(submit2024Actions *submit_2024_actions.Submit2024Actions) (db.Stats2024, error) { |
| 499 | overall_time := int64(0) |
| 500 | cycles := int64(0) |
| 501 | picked_up := false |
| 502 | lastPlacedTime := int64(0) |
| 503 | stat := db.Stats2024{ |
Emily Markova | 9c18e9c | 2024-04-03 20:06:27 -0700 | [diff] [blame] | 504 | CompType: string(submit2024Actions.CompType()), TeamNumber: string(submit2024Actions.TeamNumber()), |
| 505 | MatchNumber: submit2024Actions.MatchNumber(), SetNumber: submit2024Actions.SetNumber(), CompLevel: string(submit2024Actions.CompLevel()), |
Emily Markova | 8cb9131 | 2024-02-02 12:30:37 -0800 | [diff] [blame] | 506 | StartingQuadrant: 0, SpeakerAuto: 0, AmpAuto: 0, NotesDroppedAuto: 0, MobilityAuto: false, |
Emily Markova | cd15694 | 2024-04-07 19:32:28 -0700 | [diff] [blame] | 507 | Speaker: 0, Amp: 0, SpeakerAmplified: 0, NotesDropped: 0, Shuttled: 0, OutOfField: 0, Penalties: 0, |
Emily Markova | f17f281 | 2024-04-03 20:55:12 -0700 | [diff] [blame] | 508 | TrapNote: false, Spotlight: false, AvgCycle: 0, Park: false, OnStage: false, Harmony: false, RobotDied: false, NoShow: false, CollectedBy: "", |
Emily Markova | 8cb9131 | 2024-02-02 12:30:37 -0800 | [diff] [blame] | 509 | } |
| 510 | // Loop over all actions. |
| 511 | for i := 0; i < submit2024Actions.ActionsListLength(); i++ { |
| 512 | var action submit_2024_actions.Action |
| 513 | if !submit2024Actions.ActionsList(&action, i) { |
| 514 | return db.Stats2024{}, errors.New(fmt.Sprintf("Failed to parse submit_2024_actions.Action")) |
| 515 | } |
| 516 | actionTable := new(flatbuffers.Table) |
| 517 | action_type := action.ActionTakenType() |
| 518 | if !action.ActionTaken(actionTable) { |
| 519 | return db.Stats2024{}, errors.New(fmt.Sprint("Failed to parse sub-action or sub-action was missing")) |
| 520 | } |
| 521 | if action_type == submit_2024_actions.ActionTypeStartMatchAction { |
| 522 | var startMatchAction submit_2024_actions.StartMatchAction |
| 523 | startMatchAction.Init(actionTable.Bytes, actionTable.Pos) |
| 524 | stat.StartingQuadrant = startMatchAction.Position() |
| 525 | } else if action_type == submit_2024_actions.ActionTypeMobilityAction { |
| 526 | var mobilityAction submit_2024_actions.MobilityAction |
| 527 | mobilityAction.Init(actionTable.Bytes, actionTable.Pos) |
| 528 | if mobilityAction.Mobility() { |
| 529 | stat.MobilityAuto = true |
| 530 | } |
Emily Markova | 8cb9131 | 2024-02-02 12:30:37 -0800 | [diff] [blame] | 531 | } else if action_type == submit_2024_actions.ActionTypePenaltyAction { |
| 532 | var penaltyAction submit_2024_actions.PenaltyAction |
| 533 | penaltyAction.Init(actionTable.Bytes, actionTable.Pos) |
Emily Markova | dcadcb6 | 2024-02-03 13:07:17 -0800 | [diff] [blame] | 534 | stat.Penalties += penaltyAction.Penalties() |
Emily Markova | 8cb9131 | 2024-02-02 12:30:37 -0800 | [diff] [blame] | 535 | |
Emily Markova | 040123c | 2024-02-27 09:48:37 -0800 | [diff] [blame] | 536 | } else if action_type == submit_2024_actions.ActionTypeRobotDeathAction { |
| 537 | var robotDeathAction submit_2024_actions.RobotDeathAction |
| 538 | robotDeathAction.Init(actionTable.Bytes, actionTable.Pos) |
| 539 | stat.RobotDied = true |
| 540 | |
Emily Markova | f17f281 | 2024-04-03 20:55:12 -0700 | [diff] [blame] | 541 | } else if action_type == submit_2024_actions.ActionTypeNoShowAction { |
| 542 | var NoShowAction submit_2024_actions.NoShowAction |
| 543 | NoShowAction.Init(actionTable.Bytes, actionTable.Pos) |
| 544 | stat.NoShow = true |
| 545 | |
Emily Markova | 8cb9131 | 2024-02-02 12:30:37 -0800 | [diff] [blame] | 546 | } else if action_type == submit_2024_actions.ActionTypePickupNoteAction { |
| 547 | var pick_up_action submit_2024_actions.PickupNoteAction |
| 548 | pick_up_action.Init(actionTable.Bytes, actionTable.Pos) |
Emily Markova | 040123c | 2024-02-27 09:48:37 -0800 | [diff] [blame] | 549 | picked_up = true |
Emily Markova | 8cb9131 | 2024-02-02 12:30:37 -0800 | [diff] [blame] | 550 | } else if action_type == submit_2024_actions.ActionTypePlaceNoteAction { |
| 551 | var place_action submit_2024_actions.PlaceNoteAction |
| 552 | place_action.Init(actionTable.Bytes, actionTable.Pos) |
| 553 | if !picked_up { |
| 554 | return db.Stats2024{}, errors.New(fmt.Sprintf("Got PlaceNoteAction without corresponding PickupObjectAction")) |
| 555 | } |
| 556 | score_type := place_action.ScoreType() |
| 557 | auto := place_action.Auto() |
Emily Markova | cd15694 | 2024-04-07 19:32:28 -0700 | [diff] [blame] | 558 | count_in_cycle := true |
Emily Markova | 8cb9131 | 2024-02-02 12:30:37 -0800 | [diff] [blame] | 559 | if score_type == submit_2024_actions.ScoreTypekAMP && auto { |
| 560 | stat.AmpAuto += 1 |
| 561 | } else if score_type == submit_2024_actions.ScoreTypekAMP && !auto { |
| 562 | stat.Amp += 1 |
Emily Markova | 8cb9131 | 2024-02-02 12:30:37 -0800 | [diff] [blame] | 563 | } else if score_type == submit_2024_actions.ScoreTypekSPEAKER && !auto { |
| 564 | stat.Speaker += 1 |
| 565 | } else if score_type == submit_2024_actions.ScoreTypekSPEAKER && auto { |
| 566 | stat.SpeakerAuto += 1 |
| 567 | } else if score_type == submit_2024_actions.ScoreTypekSPEAKER_AMPLIFIED && !auto { |
| 568 | stat.SpeakerAmplified += 1 |
Emily Markova | 040123c | 2024-02-27 09:48:37 -0800 | [diff] [blame] | 569 | } else if score_type == submit_2024_actions.ScoreTypekDROPPED && auto { |
| 570 | stat.NotesDroppedAuto += 1 |
Emily Markova | cd15694 | 2024-04-07 19:32:28 -0700 | [diff] [blame] | 571 | count_in_cycle = false |
Emily Markova | 040123c | 2024-02-27 09:48:37 -0800 | [diff] [blame] | 572 | } else if score_type == submit_2024_actions.ScoreTypekDROPPED && !auto { |
| 573 | stat.NotesDropped += 1 |
Emily Markova | cd15694 | 2024-04-07 19:32:28 -0700 | [diff] [blame] | 574 | count_in_cycle = false |
| 575 | } else if score_type == submit_2024_actions.ScoreTypekSHUTTLED { |
| 576 | stat.Shuttled += 1 |
| 577 | count_in_cycle = false |
| 578 | } else if score_type == submit_2024_actions.ScoreTypekOUT_OF_FIELD { |
| 579 | stat.OutOfField += 1 |
| 580 | count_in_cycle = false |
Emily Markova | 8cb9131 | 2024-02-02 12:30:37 -0800 | [diff] [blame] | 581 | } else { |
| 582 | return db.Stats2024{}, errors.New(fmt.Sprintf("Got unknown ObjectType/ScoreLevel/Auto combination")) |
| 583 | } |
| 584 | picked_up = false |
Emily Markova | cd15694 | 2024-04-07 19:32:28 -0700 | [diff] [blame] | 585 | if count_in_cycle { |
| 586 | // Assuming dropped, shuttled, and out of field |
| 587 | // notes are not counted in total cycle time. |
| 588 | if lastPlacedTime != int64(0) { |
| 589 | // If this is not the first time we place, |
| 590 | // start counting cycle time. We define cycle |
| 591 | // time as the time between placements. |
| 592 | overall_time += int64(action.Timestamp()) - lastPlacedTime |
| 593 | } |
Emily Markova | 8cb9131 | 2024-02-02 12:30:37 -0800 | [diff] [blame] | 594 | cycles += 1 |
Emily Markova | cd15694 | 2024-04-07 19:32:28 -0700 | [diff] [blame] | 595 | lastPlacedTime = int64(action.Timestamp()) |
Emily Markova | 8cb9131 | 2024-02-02 12:30:37 -0800 | [diff] [blame] | 596 | } |
Emily Markova | 8cb9131 | 2024-02-02 12:30:37 -0800 | [diff] [blame] | 597 | } else if action_type == submit_2024_actions.ActionTypeEndMatchAction { |
| 598 | var endMatchAction submit_2024_actions.EndMatchAction |
| 599 | endMatchAction.Init(actionTable.Bytes, actionTable.Pos) |
| 600 | if endMatchAction.StageType() == submit_2024_actions.StageTypekON_STAGE { |
| 601 | stat.OnStage = true |
| 602 | } else if endMatchAction.StageType() == submit_2024_actions.StageTypekPARK { |
| 603 | stat.Park = true |
| 604 | } else if endMatchAction.StageType() == submit_2024_actions.StageTypekHARMONY { |
| 605 | stat.Harmony = true |
| 606 | } |
| 607 | stat.TrapNote = endMatchAction.TrapNote() |
Emily Markova | 6079e2f | 2024-02-17 13:17:24 -0800 | [diff] [blame] | 608 | stat.Spotlight = endMatchAction.Spotlight() |
Emily Markova | 8cb9131 | 2024-02-02 12:30:37 -0800 | [diff] [blame] | 609 | } |
| 610 | } |
| 611 | if cycles != 0 { |
| 612 | stat.AvgCycle = overall_time / cycles |
| 613 | } else { |
| 614 | stat.AvgCycle = 0 |
| 615 | } |
| 616 | return stat, nil |
| 617 | } |
| 618 | |
| 619 | // Handles a Request2024DataScouting request. |
| 620 | type request2024DataScoutingHandler struct { |
| 621 | db Database |
| 622 | } |
| 623 | |
| 624 | func (handler request2024DataScoutingHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { |
| 625 | requestBytes, err := io.ReadAll(req.Body) |
| 626 | if err != nil { |
| 627 | respondWithError(w, http.StatusBadRequest, fmt.Sprint("Failed to read request bytes:", err)) |
| 628 | return |
| 629 | } |
| 630 | |
| 631 | _, success := parseRequest(w, requestBytes, "Request2024DataScouting", request_2024_data_scouting.GetRootAsRequest2024DataScouting) |
| 632 | if !success { |
| 633 | return |
| 634 | } |
| 635 | |
| 636 | stats, err := handler.db.ReturnStats2024() |
| 637 | if err != nil { |
| 638 | respondWithError(w, http.StatusInternalServerError, fmt.Sprint("Failed to query database: ", err)) |
| 639 | return |
| 640 | } |
| 641 | |
| 642 | var response Request2024DataScoutingResponseT |
| 643 | for _, stat := range stats { |
| 644 | response.StatsList = append(response.StatsList, &request_2024_data_scouting_response.Stats2024T{ |
| 645 | TeamNumber: stat.TeamNumber, |
| 646 | MatchNumber: stat.MatchNumber, |
| 647 | SetNumber: stat.SetNumber, |
| 648 | CompLevel: stat.CompLevel, |
| 649 | StartingQuadrant: stat.StartingQuadrant, |
| 650 | SpeakerAuto: stat.SpeakerAuto, |
| 651 | AmpAuto: stat.AmpAuto, |
| 652 | NotesDroppedAuto: stat.NotesDroppedAuto, |
| 653 | MobilityAuto: stat.MobilityAuto, |
| 654 | Speaker: stat.Speaker, |
| 655 | Amp: stat.Amp, |
| 656 | SpeakerAmplified: stat.SpeakerAmplified, |
Emily Markova | 8cb9131 | 2024-02-02 12:30:37 -0800 | [diff] [blame] | 657 | NotesDropped: stat.NotesDropped, |
Emily Markova | cd15694 | 2024-04-07 19:32:28 -0700 | [diff] [blame] | 658 | Shuttled: stat.Shuttled, |
| 659 | OutOfField: stat.OutOfField, |
Emily Markova | 8cb9131 | 2024-02-02 12:30:37 -0800 | [diff] [blame] | 660 | Penalties: stat.Penalties, |
| 661 | TrapNote: stat.TrapNote, |
Emily Markova | 6079e2f | 2024-02-17 13:17:24 -0800 | [diff] [blame] | 662 | Spotlight: stat.Spotlight, |
Emily Markova | 8cb9131 | 2024-02-02 12:30:37 -0800 | [diff] [blame] | 663 | AvgCycle: stat.AvgCycle, |
| 664 | Park: stat.Park, |
| 665 | OnStage: stat.OnStage, |
| 666 | Harmony: stat.Harmony, |
Emily Markova | 040123c | 2024-02-27 09:48:37 -0800 | [diff] [blame] | 667 | RobotDied: stat.RobotDied, |
Emily Markova | f17f281 | 2024-04-03 20:55:12 -0700 | [diff] [blame] | 668 | NoShow: stat.NoShow, |
Emily Markova | 8cb9131 | 2024-02-02 12:30:37 -0800 | [diff] [blame] | 669 | CollectedBy: stat.CollectedBy, |
Emily Markova | 9c18e9c | 2024-04-03 20:06:27 -0700 | [diff] [blame] | 670 | CompType: stat.CompType, |
Emily Markova | 8cb9131 | 2024-02-02 12:30:37 -0800 | [diff] [blame] | 671 | }) |
| 672 | } |
| 673 | |
| 674 | builder := flatbuffers.NewBuilder(50 * 1024) |
| 675 | builder.Finish((&response).Pack(builder)) |
| 676 | w.Write(builder.FinishedBytes()) |
| 677 | } |
| 678 | |
Emily Markova | 8e39f45 | 2023-12-23 12:17:30 -0800 | [diff] [blame] | 679 | type requestAllPitImagesHandler struct { |
| 680 | db Database |
| 681 | } |
| 682 | |
| 683 | func (handler requestAllPitImagesHandler) 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 | |
| 690 | _, success := parseRequest(w, requestBytes, "RequestAllPitImages", request_all_pit_images.GetRootAsRequestAllPitImages) |
| 691 | if !success { |
| 692 | return |
| 693 | } |
| 694 | |
| 695 | images, err := handler.db.ReturnPitImages() |
| 696 | if err != nil { |
| 697 | respondWithError(w, http.StatusInternalServerError, fmt.Sprintf("Failed to get pit images: %v", err)) |
| 698 | return |
| 699 | } |
| 700 | |
| 701 | var response RequestAllPitImagesResponseT |
| 702 | for _, data := range images { |
| 703 | response.PitImageList = append(response.PitImageList, &request_all_pit_images_response.PitImageT{ |
| 704 | TeamNumber: data.TeamNumber, |
| 705 | ImagePath: data.ImagePath, |
| 706 | CheckSum: data.CheckSum, |
| 707 | }) |
| 708 | } |
| 709 | |
| 710 | builder := flatbuffers.NewBuilder(1024) |
| 711 | builder.Finish((&response).Pack(builder)) |
| 712 | w.Write(builder.FinishedBytes()) |
| 713 | } |
| 714 | |
Emily Markova | faecfe1 | 2023-07-01 12:40:03 -0700 | [diff] [blame] | 715 | type requestPitImagesHandler struct { |
| 716 | db Database |
| 717 | } |
| 718 | |
| 719 | func (handler requestPitImagesHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { |
| 720 | requestBytes, err := io.ReadAll(req.Body) |
| 721 | if err != nil { |
| 722 | respondWithError(w, http.StatusBadRequest, fmt.Sprint("Failed to read request bytes:", err)) |
| 723 | return |
| 724 | } |
| 725 | |
| 726 | request, success := parseRequest(w, requestBytes, "RequestPitImages", request_pit_images.GetRootAsRequestPitImages) |
| 727 | if !success { |
| 728 | return |
| 729 | } |
| 730 | |
| 731 | images, err := handler.db.QueryPitImages(string(request.TeamNumber())) |
| 732 | if err != nil { |
| 733 | respondWithError(w, http.StatusInternalServerError, fmt.Sprintf("Failed to query pit images: %v", err)) |
| 734 | return |
| 735 | } |
| 736 | |
| 737 | var response RequestPitImagesResponseT |
| 738 | for _, data := range images { |
| 739 | response.PitImageList = append(response.PitImageList, &request_pit_images_response.PitImageT{ |
| 740 | TeamNumber: data.TeamNumber, |
| 741 | ImagePath: data.ImagePath, |
| 742 | CheckSum: data.CheckSum, |
| 743 | }) |
| 744 | } |
| 745 | |
| 746 | builder := flatbuffers.NewBuilder(1024) |
| 747 | builder.Finish((&response).Pack(builder)) |
| 748 | w.Write(builder.FinishedBytes()) |
| 749 | } |
| 750 | |
Alex Perry | 81f96ba | 2022-03-13 18:26:19 -0700 | [diff] [blame] | 751 | type requestNotesForTeamHandler struct { |
| 752 | db Database |
| 753 | } |
| 754 | |
| 755 | func (handler requestNotesForTeamHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { |
| 756 | requestBytes, err := io.ReadAll(req.Body) |
| 757 | if err != nil { |
| 758 | respondWithError(w, http.StatusBadRequest, fmt.Sprint("Failed to read request bytes:", err)) |
| 759 | return |
| 760 | } |
| 761 | |
Philipp Schrader | b7e7593 | 2022-03-26 16:18:34 -0700 | [diff] [blame] | 762 | request, success := parseRequest(w, requestBytes, "RequestNotesForTeam", request_notes_for_team.GetRootAsRequestNotesForTeam) |
Alex Perry | 81f96ba | 2022-03-13 18:26:19 -0700 | [diff] [blame] | 763 | if !success { |
| 764 | return |
| 765 | } |
| 766 | |
Emily Markova | e68b763 | 2023-12-30 14:17:55 -0800 | [diff] [blame] | 767 | notes, err := handler.db.QueryNotes(string(request.Team())) |
Alex Perry | 81f96ba | 2022-03-13 18:26:19 -0700 | [diff] [blame] | 768 | if err != nil { |
| 769 | respondWithError(w, http.StatusInternalServerError, fmt.Sprintf("Failed to query notes: %v", err)) |
| 770 | return |
| 771 | } |
| 772 | |
| 773 | var response RequestNotesForTeamResponseT |
Philipp Schrader | eecb896 | 2022-06-01 21:02:42 -0700 | [diff] [blame] | 774 | for _, data := range notes { |
Alex Perry | 81f96ba | 2022-03-13 18:26:19 -0700 | [diff] [blame] | 775 | response.Notes = append(response.Notes, &request_notes_for_team_response.NoteT{data}) |
| 776 | } |
| 777 | |
| 778 | builder := flatbuffers.NewBuilder(1024) |
| 779 | builder.Finish((&response).Pack(builder)) |
| 780 | w.Write(builder.FinishedBytes()) |
| 781 | } |
| 782 | |
Milo Lin | 1d59f0c | 2022-06-22 20:30:58 -0700 | [diff] [blame] | 783 | type requestShiftScheduleHandler struct { |
| 784 | db Database |
| 785 | } |
| 786 | |
| 787 | func (handler requestShiftScheduleHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { |
| 788 | requestBytes, err := io.ReadAll(req.Body) |
| 789 | if err != nil { |
| 790 | respondWithError(w, http.StatusBadRequest, fmt.Sprint("Failed to read request bytes:", err)) |
| 791 | return |
| 792 | } |
| 793 | |
| 794 | _, success := parseRequest(w, requestBytes, "RequestShiftSchedule", request_shift_schedule.GetRootAsRequestShiftSchedule) |
| 795 | if !success { |
| 796 | return |
| 797 | } |
| 798 | |
| 799 | shiftData, err := handler.db.ReturnAllShifts() |
| 800 | if err != nil { |
| 801 | respondWithError(w, http.StatusInternalServerError, fmt.Sprintf("Failed to query shift schedule: %v", err)) |
| 802 | return |
| 803 | } |
| 804 | |
| 805 | var response RequestShiftScheduleResponseT |
| 806 | for _, shifts := range shiftData { |
| 807 | response.ShiftSchedule = append(response.ShiftSchedule, &request_shift_schedule_response.MatchAssignmentT{ |
| 808 | MatchNumber: shifts.MatchNumber, |
Philipp Schrader | 2ff455b | 2023-05-03 22:11:50 -0700 | [diff] [blame] | 809 | R1Scouter: shifts.R1scouter, |
| 810 | R2Scouter: shifts.R2scouter, |
| 811 | R3Scouter: shifts.R3scouter, |
| 812 | B1Scouter: shifts.B1scouter, |
| 813 | B2Scouter: shifts.B2scouter, |
| 814 | B3Scouter: shifts.B3scouter, |
Milo Lin | 1d59f0c | 2022-06-22 20:30:58 -0700 | [diff] [blame] | 815 | }) |
| 816 | } |
| 817 | |
| 818 | builder := flatbuffers.NewBuilder(1024) |
| 819 | builder.Finish((&response).Pack(builder)) |
| 820 | w.Write(builder.FinishedBytes()) |
| 821 | } |
| 822 | |
| 823 | type submitShiftScheduleHandler struct { |
| 824 | db Database |
| 825 | } |
| 826 | |
| 827 | func (handler submitShiftScheduleHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { |
| 828 | // Get the username of the person submitting the data. |
| 829 | username := parseUsername(req) |
| 830 | |
| 831 | requestBytes, err := io.ReadAll(req.Body) |
| 832 | if err != nil { |
| 833 | respondWithError(w, http.StatusBadRequest, fmt.Sprint("Failed to read request bytes:", err)) |
| 834 | return |
| 835 | } |
| 836 | |
| 837 | request, success := parseRequest[SubmitShiftSchedule](w, requestBytes, "SubmitShiftSchedule", submit_shift_schedule.GetRootAsSubmitShiftSchedule) |
| 838 | if !success { |
| 839 | return |
| 840 | } |
| 841 | |
| 842 | log.Println("Got shift schedule from", username) |
| 843 | shift_schedule_length := request.ShiftScheduleLength() |
| 844 | for i := 0; i < shift_schedule_length; i++ { |
| 845 | var match_assignment submit_shift_schedule.MatchAssignment |
| 846 | request.ShiftSchedule(&match_assignment, i) |
| 847 | current_shift := db.Shift{ |
| 848 | MatchNumber: match_assignment.MatchNumber(), |
Philipp Schrader | 2ff455b | 2023-05-03 22:11:50 -0700 | [diff] [blame] | 849 | R1scouter: string(match_assignment.R1Scouter()), |
| 850 | R2scouter: string(match_assignment.R2Scouter()), |
| 851 | R3scouter: string(match_assignment.R3Scouter()), |
| 852 | B1scouter: string(match_assignment.B1Scouter()), |
| 853 | B2scouter: string(match_assignment.B2Scouter()), |
| 854 | B3scouter: string(match_assignment.B3Scouter()), |
Milo Lin | 1d59f0c | 2022-06-22 20:30:58 -0700 | [diff] [blame] | 855 | } |
| 856 | err = handler.db.AddToShift(current_shift) |
| 857 | if err != nil { |
| 858 | respondWithError(w, http.StatusInternalServerError, fmt.Sprint("Failed to submit shift schedule: ", err)) |
| 859 | return |
| 860 | } |
| 861 | } |
| 862 | |
| 863 | builder := flatbuffers.NewBuilder(50 * 1024) |
| 864 | builder.Finish((&SubmitShiftScheduleResponseT{}).Pack(builder)) |
| 865 | w.Write(builder.FinishedBytes()) |
| 866 | } |
| 867 | |
Filip Kujawa | 210a03b | 2022-11-24 14:41:11 -0800 | [diff] [blame] | 868 | type SubmitDriverRankingHandler struct { |
| 869 | db Database |
| 870 | } |
| 871 | |
| 872 | func (handler SubmitDriverRankingHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { |
| 873 | requestBytes, err := io.ReadAll(req.Body) |
| 874 | if err != nil { |
| 875 | respondWithError(w, http.StatusBadRequest, fmt.Sprint("Failed to read request bytes:", err)) |
| 876 | return |
| 877 | } |
| 878 | |
| 879 | request, success := parseRequest(w, requestBytes, "SubmitDriverRanking", submit_driver_ranking.GetRootAsSubmitDriverRanking) |
| 880 | if !success { |
| 881 | return |
| 882 | } |
| 883 | |
| 884 | err = handler.db.AddDriverRanking(db.DriverRankingData{ |
| 885 | MatchNumber: request.MatchNumber(), |
Emily Markova | e68b763 | 2023-12-30 14:17:55 -0800 | [diff] [blame] | 886 | Rank1: string(request.Rank1()), |
| 887 | Rank2: string(request.Rank2()), |
| 888 | Rank3: string(request.Rank3()), |
Filip Kujawa | 210a03b | 2022-11-24 14:41:11 -0800 | [diff] [blame] | 889 | }) |
| 890 | |
| 891 | if err != nil { |
| 892 | respondWithError(w, http.StatusInternalServerError, fmt.Sprintf("Failed to insert driver ranking: %v", err)) |
| 893 | return |
| 894 | } |
| 895 | |
| 896 | var response SubmitDriverRankingResponseT |
| 897 | builder := flatbuffers.NewBuilder(10) |
| 898 | builder.Finish((&response).Pack(builder)) |
| 899 | w.Write(builder.FinishedBytes()) |
| 900 | } |
| 901 | |
Filip Kujawa | f882e02 | 2022-12-14 13:14:08 -0800 | [diff] [blame] | 902 | type requestAllNotesHandler struct { |
| 903 | db Database |
| 904 | } |
| 905 | |
| 906 | func (handler requestAllNotesHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { |
| 907 | requestBytes, err := io.ReadAll(req.Body) |
| 908 | if err != nil { |
| 909 | respondWithError(w, http.StatusBadRequest, fmt.Sprint("Failed to read request bytes:", err)) |
| 910 | return |
| 911 | } |
| 912 | |
| 913 | _, success := parseRequest(w, requestBytes, "RequestAllNotes", request_all_notes.GetRootAsRequestAllNotes) |
| 914 | if !success { |
| 915 | return |
| 916 | } |
| 917 | |
| 918 | notes, err := handler.db.ReturnAllNotes() |
| 919 | if err != nil { |
| 920 | respondWithError(w, http.StatusInternalServerError, fmt.Sprint("Failed to query database: ", err)) |
| 921 | return |
| 922 | } |
| 923 | |
| 924 | var response RequestAllNotesResponseT |
| 925 | for _, note := range notes { |
| 926 | response.NoteList = append(response.NoteList, &request_all_notes_response.NoteT{ |
Filip Kujawa | 7ddd565 | 2023-03-07 19:56:15 -0800 | [diff] [blame] | 927 | Team: note.TeamNumber, |
| 928 | Notes: note.Notes, |
| 929 | GoodDriving: note.GoodDriving, |
| 930 | BadDriving: note.BadDriving, |
Filip Kujawa | 11dc4c9 | 2023-04-13 08:55:43 -0700 | [diff] [blame] | 931 | SolidPlacing: note.SolidPlacing, |
Filip Kujawa | 7ddd565 | 2023-03-07 19:56:15 -0800 | [diff] [blame] | 932 | SketchyPlacing: note.SketchyPlacing, |
| 933 | GoodDefense: note.GoodDefense, |
| 934 | BadDefense: note.BadDefense, |
| 935 | EasilyDefended: note.EasilyDefended, |
Emily Markova | cf893f4 | 2024-03-13 19:03:10 -0700 | [diff] [blame] | 936 | NoShow: note.NoShow, |
| 937 | MatchNumber: note.MatchNumber, |
| 938 | CompLevel: note.CompLevel, |
| 939 | SetNumber: note.SetNumber, |
Filip Kujawa | f882e02 | 2022-12-14 13:14:08 -0800 | [diff] [blame] | 940 | }) |
| 941 | } |
| 942 | |
| 943 | builder := flatbuffers.NewBuilder(50 * 1024) |
| 944 | builder.Finish((&response).Pack(builder)) |
| 945 | w.Write(builder.FinishedBytes()) |
| 946 | } |
| 947 | |
| 948 | type requestAllDriverRankingsHandler struct { |
| 949 | db Database |
| 950 | } |
| 951 | |
| 952 | func (handler requestAllDriverRankingsHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { |
| 953 | requestBytes, err := io.ReadAll(req.Body) |
| 954 | if err != nil { |
| 955 | respondWithError(w, http.StatusBadRequest, fmt.Sprint("Failed to read request bytes:", err)) |
| 956 | return |
| 957 | } |
| 958 | |
| 959 | _, success := parseRequest(w, requestBytes, "RequestAllDriverRankings", request_all_driver_rankings.GetRootAsRequestAllDriverRankings) |
| 960 | if !success { |
| 961 | return |
| 962 | } |
| 963 | |
| 964 | rankings, err := handler.db.ReturnAllDriverRankings() |
| 965 | if err != nil { |
| 966 | respondWithError(w, http.StatusInternalServerError, fmt.Sprint("Failed to query database: ", err)) |
| 967 | return |
| 968 | } |
| 969 | |
| 970 | var response RequestAllDriverRankingsResponseT |
| 971 | for _, ranking := range rankings { |
| 972 | response.DriverRankingList = append(response.DriverRankingList, &request_all_driver_rankings_response.RankingT{ |
| 973 | MatchNumber: ranking.MatchNumber, |
| 974 | Rank1: ranking.Rank1, |
| 975 | Rank2: ranking.Rank2, |
| 976 | Rank3: ranking.Rank3, |
| 977 | }) |
| 978 | } |
| 979 | |
| 980 | builder := flatbuffers.NewBuilder(50 * 1024) |
| 981 | builder.Finish((&response).Pack(builder)) |
| 982 | w.Write(builder.FinishedBytes()) |
| 983 | } |
| 984 | |
Emily Markova | 8cb9131 | 2024-02-02 12:30:37 -0800 | [diff] [blame] | 985 | type submit2024ActionsHandler struct { |
| 986 | db Database |
| 987 | } |
| 988 | |
| 989 | func (handler submit2024ActionsHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { |
| 990 | // Get the username of the person submitting the data. |
| 991 | username := parseUsername(req) |
| 992 | |
| 993 | requestBytes, err := io.ReadAll(req.Body) |
| 994 | if err != nil { |
Philipp Schrader | e971924 | 2024-04-18 09:30:34 -0700 | [diff] [blame] | 995 | log.Println("Failed to receive submission request from", username) |
Emily Markova | 8cb9131 | 2024-02-02 12:30:37 -0800 | [diff] [blame] | 996 | respondWithError(w, http.StatusBadRequest, fmt.Sprint("Failed to read request bytes:", err)) |
| 997 | return |
| 998 | } |
| 999 | |
| 1000 | request, success := parseRequest(w, requestBytes, "Submit2024Actions", submit_2024_actions.GetRootAsSubmit2024Actions) |
| 1001 | if !success { |
Philipp Schrader | e971924 | 2024-04-18 09:30:34 -0700 | [diff] [blame] | 1002 | log.Println("Failed to parse submission request from", username) |
Emily Markova | 8cb9131 | 2024-02-02 12:30:37 -0800 | [diff] [blame] | 1003 | return |
| 1004 | } |
| 1005 | |
Philipp Schrader | e971924 | 2024-04-18 09:30:34 -0700 | [diff] [blame] | 1006 | log.Println("Got actions for match", request.MatchNumber(), "team", string(request.TeamNumber()), "type", string(request.CompType()), "from", username) |
Emily Markova | 8cb9131 | 2024-02-02 12:30:37 -0800 | [diff] [blame] | 1007 | |
| 1008 | for i := 0; i < request.ActionsListLength(); i++ { |
| 1009 | |
| 1010 | var action Action2024 |
| 1011 | request.ActionsList(&action, i) |
| 1012 | |
| 1013 | dbAction := db.Action{ |
Emily Markova | 9c18e9c | 2024-04-03 20:06:27 -0700 | [diff] [blame] | 1014 | CompType: string(request.CompType()), |
Emily Markova | 8cb9131 | 2024-02-02 12:30:37 -0800 | [diff] [blame] | 1015 | TeamNumber: string(request.TeamNumber()), |
| 1016 | MatchNumber: request.MatchNumber(), |
| 1017 | SetNumber: request.SetNumber(), |
| 1018 | CompLevel: string(request.CompLevel()), |
| 1019 | //TODO: Serialize CompletedAction |
| 1020 | CompletedAction: []byte{}, |
| 1021 | Timestamp: action.Timestamp(), |
| 1022 | CollectedBy: username, |
| 1023 | } |
| 1024 | |
| 1025 | // Do some error checking. |
| 1026 | if action.Timestamp() < 0 { |
Philipp Schrader | e971924 | 2024-04-18 09:30:34 -0700 | [diff] [blame] | 1027 | log.Println("Got action with invalid timestamp (", action.Timestamp(), ") from", username) |
Emily Markova | 8cb9131 | 2024-02-02 12:30:37 -0800 | [diff] [blame] | 1028 | respondWithError(w, http.StatusBadRequest, fmt.Sprint( |
| 1029 | "Invalid timestamp field value of ", action.Timestamp())) |
| 1030 | return |
| 1031 | } |
| 1032 | |
| 1033 | err = handler.db.AddAction(dbAction) |
| 1034 | if err != nil { |
Philipp Schrader | e971924 | 2024-04-18 09:30:34 -0700 | [diff] [blame] | 1035 | log.Println("Failed to add action from", username, "to the database:", err) |
Emily Markova | 8cb9131 | 2024-02-02 12:30:37 -0800 | [diff] [blame] | 1036 | respondWithError(w, http.StatusInternalServerError, fmt.Sprint("Failed to add action to database: ", err)) |
| 1037 | return |
| 1038 | } |
| 1039 | } |
| 1040 | |
| 1041 | stats, err := ConvertActionsToStat2024(request) |
| 1042 | if err != nil { |
Philipp Schrader | e971924 | 2024-04-18 09:30:34 -0700 | [diff] [blame] | 1043 | log.Println("Failed to add action from", username, "to the database:", err) |
Emily Markova | 8cb9131 | 2024-02-02 12:30:37 -0800 | [diff] [blame] | 1044 | respondWithError(w, http.StatusInternalServerError, fmt.Sprint("Failed to convert actions to stats: ", err)) |
| 1045 | return |
| 1046 | } |
| 1047 | |
| 1048 | stats.CollectedBy = username |
| 1049 | |
| 1050 | err = handler.db.AddToStats2024(stats) |
| 1051 | if err != nil { |
Philipp Schrader | e971924 | 2024-04-18 09:30:34 -0700 | [diff] [blame] | 1052 | log.Println("Failed to submit stats from", username, "to the database:", err) |
Emily Markova | dcadcb6 | 2024-02-03 13:07:17 -0800 | [diff] [blame] | 1053 | respondWithError(w, http.StatusInternalServerError, fmt.Sprint("Failed to submit stats2024: ", stats, ": ", err)) |
Emily Markova | 8cb9131 | 2024-02-02 12:30:37 -0800 | [diff] [blame] | 1054 | return |
| 1055 | } |
| 1056 | |
| 1057 | builder := flatbuffers.NewBuilder(50 * 1024) |
Emily Markova | dcadcb6 | 2024-02-03 13:07:17 -0800 | [diff] [blame] | 1058 | builder.Finish((&Submit2024ActionsResponseT{}).Pack(builder)) |
Emily Markova | 8cb9131 | 2024-02-02 12:30:37 -0800 | [diff] [blame] | 1059 | w.Write(builder.FinishedBytes()) |
Philipp Schrader | e971924 | 2024-04-18 09:30:34 -0700 | [diff] [blame] | 1060 | |
| 1061 | log.Println("Successfully added stats from", username) |
Emily Markova | 8cb9131 | 2024-02-02 12:30:37 -0800 | [diff] [blame] | 1062 | } |
| 1063 | |
Emily Markova | 8cb9131 | 2024-02-02 12:30:37 -0800 | [diff] [blame] | 1064 | type Delete2024DataScoutingHandler struct { |
| 1065 | db Database |
| 1066 | } |
| 1067 | |
| 1068 | func (handler Delete2024DataScoutingHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { |
| 1069 | requestBytes, err := io.ReadAll(req.Body) |
| 1070 | if err != nil { |
| 1071 | respondWithError(w, http.StatusBadRequest, fmt.Sprint("Failed to read request bytes:", err)) |
| 1072 | return |
| 1073 | } |
| 1074 | |
| 1075 | request, success := parseRequest(w, requestBytes, "Delete2024DataScouting", delete_2024_data_scouting.GetRootAsDelete2024DataScouting) |
| 1076 | if !success { |
| 1077 | return |
| 1078 | } |
| 1079 | |
| 1080 | err = handler.db.DeleteFromStats2024( |
| 1081 | string(request.CompLevel()), |
| 1082 | request.MatchNumber(), |
| 1083 | request.SetNumber(), |
| 1084 | string(request.TeamNumber())) |
| 1085 | |
| 1086 | if err != nil { |
| 1087 | respondWithError(w, http.StatusInternalServerError, fmt.Sprintf("Failed to delete from stats2024: %v", err)) |
| 1088 | return |
| 1089 | } |
| 1090 | |
| 1091 | err = handler.db.DeleteFromActions( |
| 1092 | string(request.CompLevel()), |
| 1093 | request.MatchNumber(), |
| 1094 | request.SetNumber(), |
| 1095 | string(request.TeamNumber())) |
| 1096 | |
| 1097 | if err != nil { |
| 1098 | respondWithError(w, http.StatusInternalServerError, fmt.Sprintf("Failed to delete from actions: %v", err)) |
| 1099 | return |
| 1100 | } |
| 1101 | |
| 1102 | var response Delete2024DataScoutingResponseT |
| 1103 | builder := flatbuffers.NewBuilder(10) |
| 1104 | builder.Finish((&response).Pack(builder)) |
| 1105 | w.Write(builder.FinishedBytes()) |
| 1106 | } |
| 1107 | |
Emily Markova | 521725a | 2024-03-21 18:46:04 -0700 | [diff] [blame] | 1108 | func HandleRequests(db Database, scoutingServer server.ScoutingServer, clock Clock) { |
Philipp Schrader | cdb5cfc | 2022-02-20 14:57:07 -0800 | [diff] [blame] | 1109 | scoutingServer.HandleFunc("/requests", unknown) |
Philipp Schrader | cbf5c6a | 2022-02-27 23:25:19 -0800 | [diff] [blame] | 1110 | scoutingServer.Handle("/requests/request/all_matches", requestAllMatchesHandler{db}) |
Filip Kujawa | f882e02 | 2022-12-14 13:14:08 -0800 | [diff] [blame] | 1111 | scoutingServer.Handle("/requests/request/all_notes", requestAllNotesHandler{db}) |
| 1112 | scoutingServer.Handle("/requests/request/all_driver_rankings", requestAllDriverRankingsHandler{db}) |
Emily Markova | 8cb9131 | 2024-02-02 12:30:37 -0800 | [diff] [blame] | 1113 | scoutingServer.Handle("/requests/request/2024_data_scouting", request2024DataScoutingHandler{db}) |
Alex Perry | 81f96ba | 2022-03-13 18:26:19 -0700 | [diff] [blame] | 1114 | scoutingServer.Handle("/requests/submit/submit_notes", submitNoteScoutingHandler{db}) |
Emily Markova | faecfe1 | 2023-07-01 12:40:03 -0700 | [diff] [blame] | 1115 | scoutingServer.Handle("/requests/submit/submit_pit_image", submitPitImageScoutingHandler{db}) |
| 1116 | scoutingServer.Handle("/requests/request/pit_images", requestPitImagesHandler{db}) |
Emily Markova | 8e39f45 | 2023-12-23 12:17:30 -0800 | [diff] [blame] | 1117 | scoutingServer.Handle("/requests/request/all_pit_images", requestAllPitImagesHandler{db}) |
Emily Markova | 521725a | 2024-03-21 18:46:04 -0700 | [diff] [blame] | 1118 | scoutingServer.Handle("/requests/request/current_scouting", requestCurrentScoutingHandler{make(map[string]map[string]time.Time), db, clock}) |
Alex Perry | 81f96ba | 2022-03-13 18:26:19 -0700 | [diff] [blame] | 1119 | scoutingServer.Handle("/requests/request/notes_for_team", requestNotesForTeamHandler{db}) |
Milo Lin | 1d59f0c | 2022-06-22 20:30:58 -0700 | [diff] [blame] | 1120 | scoutingServer.Handle("/requests/submit/shift_schedule", submitShiftScheduleHandler{db}) |
| 1121 | scoutingServer.Handle("/requests/request/shift_schedule", requestShiftScheduleHandler{db}) |
Filip Kujawa | 210a03b | 2022-11-24 14:41:11 -0800 | [diff] [blame] | 1122 | scoutingServer.Handle("/requests/submit/submit_driver_ranking", SubmitDriverRankingHandler{db}) |
Emily Markova | 8cb9131 | 2024-02-02 12:30:37 -0800 | [diff] [blame] | 1123 | scoutingServer.Handle("/requests/submit/submit_2024_actions", submit2024ActionsHandler{db}) |
Emily Markova | 8cb9131 | 2024-02-02 12:30:37 -0800 | [diff] [blame] | 1124 | scoutingServer.Handle("/requests/delete/delete_2024_data_scouting", Delete2024DataScoutingHandler{db}) |
Philipp Schrader | cdb5cfc | 2022-02-20 14:57:07 -0800 | [diff] [blame] | 1125 | } |