blob: cef87aa9746a62ad87ff50e5061480b996c5b216 [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"
Philipp Schraderd3fac192022-03-02 20:35:46 -080010 "strconv"
11 "strings"
Philipp Schradercdb5cfc2022-02-20 14:57:07 -080012
Philipp Schrader8747f1b2022-02-23 23:56:22 -080013 "github.com/frc971/971-Robot-Code/scouting/db"
Philipp Schraderd3fac192022-03-02 20:35:46 -080014 "github.com/frc971/971-Robot-Code/scouting/scraping"
Philipp Schradercdb5cfc2022-02-20 14:57:07 -080015 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/error_response"
Philipp Schraderd3fac192022-03-02 20:35:46 -080016 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/refresh_match_list"
17 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/refresh_match_list_response"
Philipp Schradercbf5c6a2022-02-27 23:25:19 -080018 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_all_matches"
19 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_all_matches_response"
Philipp Schraderacf96232022-03-01 22:03:30 -080020 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_data_scouting"
21 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_data_scouting_response"
Philipp Schraderd1c4bef2022-02-28 22:51:30 -080022 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_matches_for_team"
23 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_matches_for_team_response"
Alex Perry81f96ba2022-03-13 18:26:19 -070024 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_notes_for_team"
25 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_notes_for_team_response"
Philipp Schradercdb5cfc2022-02-20 14:57:07 -080026 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_data_scouting"
Philipp Schrader30005e42022-03-06 13:53:58 -080027 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_data_scouting_response"
Alex Perry81f96ba2022-03-13 18:26:19 -070028 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_notes"
29 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_notes_response"
Philipp Schradercdb5cfc2022-02-20 14:57:07 -080030 "github.com/frc971/971-Robot-Code/scouting/webserver/server"
31 flatbuffers "github.com/google/flatbuffers/go"
32)
33
Philipp Schradercbf5c6a2022-02-27 23:25:19 -080034type SubmitDataScouting = submit_data_scouting.SubmitDataScouting
Philipp Schrader30005e42022-03-06 13:53:58 -080035type SubmitDataScoutingResponseT = submit_data_scouting_response.SubmitDataScoutingResponseT
Philipp Schradercbf5c6a2022-02-27 23:25:19 -080036type RequestAllMatches = request_all_matches.RequestAllMatches
37type RequestAllMatchesResponseT = request_all_matches_response.RequestAllMatchesResponseT
Philipp Schraderd1c4bef2022-02-28 22:51:30 -080038type RequestMatchesForTeam = request_matches_for_team.RequestMatchesForTeam
39type RequestMatchesForTeamResponseT = request_matches_for_team_response.RequestMatchesForTeamResponseT
Philipp Schraderacf96232022-03-01 22:03:30 -080040type RequestDataScouting = request_data_scouting.RequestDataScouting
41type RequestDataScoutingResponseT = request_data_scouting_response.RequestDataScoutingResponseT
Philipp Schraderd3fac192022-03-02 20:35:46 -080042type RefreshMatchList = refresh_match_list.RefreshMatchList
43type RefreshMatchListResponseT = refresh_match_list_response.RefreshMatchListResponseT
Alex Perry81f96ba2022-03-13 18:26:19 -070044type SubmitNotes = submit_notes.SubmitNotes
45type SubmitNotesResponseT = submit_notes_response.SubmitNotesResponseT
46type RequestNotesForTeam = request_notes_for_team.RequestNotesForTeam
47type RequestNotesForTeamResponseT = request_notes_for_team_response.RequestNotesForTeamResponseT
Philipp Schradercbf5c6a2022-02-27 23:25:19 -080048
Philipp Schrader8747f1b2022-02-23 23:56:22 -080049// The interface we expect the database abstraction to conform to.
50// We use an interface here because it makes unit testing easier.
51type Database interface {
52 AddToMatch(db.Match) error
53 AddToStats(db.Stats) error
54 ReturnMatches() ([]db.Match, error)
55 ReturnStats() ([]db.Stats, error)
Philipp Schraderd1c4bef2022-02-28 22:51:30 -080056 QueryMatches(int32) ([]db.Match, error)
Philipp Schrader8747f1b2022-02-23 23:56:22 -080057 QueryStats(int) ([]db.Stats, error)
Alex Perry81f96ba2022-03-13 18:26:19 -070058 QueryNotes(int32) (db.NotesData, error)
59 AddNotes(db.NotesData) error
Philipp Schrader8747f1b2022-02-23 23:56:22 -080060}
61
Philipp Schraderd3fac192022-03-02 20:35:46 -080062type ScrapeMatchList func(int32, string) ([]scraping.Match, error)
63
Philipp Schradercdb5cfc2022-02-20 14:57:07 -080064// Handles unknown requests. Just returns a 404.
65func unknown(w http.ResponseWriter, req *http.Request) {
66 w.WriteHeader(http.StatusNotFound)
67}
68
69func respondWithError(w http.ResponseWriter, statusCode int, errorMessage string) {
70 builder := flatbuffers.NewBuilder(1024)
71 builder.Finish((&error_response.ErrorResponseT{
72 ErrorMessage: errorMessage,
73 }).Pack(builder))
74 w.WriteHeader(statusCode)
75 w.Write(builder.FinishedBytes())
76}
77
78func respondNotImplemented(w http.ResponseWriter) {
79 respondWithError(w, http.StatusNotImplemented, "")
80}
81
Philipp Schraderb7e75932022-03-26 16:18:34 -070082func 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 -080083 success := true
84 defer func() {
85 if r := recover(); r != nil {
Philipp Schraderb7e75932022-03-26 16:18:34 -070086 respondWithError(w, http.StatusBadRequest, fmt.Sprintf("Failed to parse %s: %v", requestName, r))
Philipp Schradercdb5cfc2022-02-20 14:57:07 -080087 success = false
88 }
89 }()
Philipp Schraderb7e75932022-03-26 16:18:34 -070090 result := parser(buf, 0)
Philipp Schradercdb5cfc2022-02-20 14:57:07 -080091 return result, success
92}
93
Philipp Schraderfae8a7e2022-03-13 22:51:54 -070094// Parses the authorization information that the browser inserts into the
95// headers. The authorization follows this format:
96//
97// req.Headers["Authorization"] = []string{"Basic <base64 encoded username:password>"}
98func parseUsername(req *http.Request) string {
99 auth, ok := req.Header["Authorization"]
100 if !ok {
101 return "unknown"
102 }
103
104 parts := strings.Split(auth[0], " ")
105 if !(len(parts) == 2 && parts[0] == "Basic") {
106 return "unknown"
107 }
108
109 info, err := base64.StdEncoding.DecodeString(parts[1])
110 if err != nil {
111 log.Println("ERROR: Failed to parse Basic authentication.")
112 return "unknown"
113 }
114
115 loginParts := strings.Split(string(info), ":")
116 if len(loginParts) != 2 {
117 return "unknown"
118 }
119 return loginParts[0]
120}
121
Philipp Schradercdb5cfc2022-02-20 14:57:07 -0800122// Handles a SubmitDataScouting request.
Philipp Schrader8747f1b2022-02-23 23:56:22 -0800123type submitDataScoutingHandler struct {
124 db Database
125}
126
127func (handler submitDataScoutingHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
Philipp Schraderfae8a7e2022-03-13 22:51:54 -0700128 // Get the username of the person submitting the data.
129 username := parseUsername(req)
Philipp Schraderfae8a7e2022-03-13 22:51:54 -0700130
Philipp Schradercdb5cfc2022-02-20 14:57:07 -0800131 requestBytes, err := io.ReadAll(req.Body)
132 if err != nil {
133 respondWithError(w, http.StatusBadRequest, fmt.Sprint("Failed to read request bytes:", err))
134 return
135 }
136
Philipp Schraderb7e75932022-03-26 16:18:34 -0700137 request, success := parseRequest[SubmitDataScouting](w, requestBytes, "SubmitDataScouting", submit_data_scouting.GetRootAsSubmitDataScouting)
Philipp Schradercdb5cfc2022-02-20 14:57:07 -0800138 if !success {
139 return
140 }
141
Philipp Schraderd7b6eba2022-03-18 22:21:25 -0700142 log.Println("Got data scouting data for match", request.Match(), "team", request.Team(), "from", username)
143
Philipp Schrader30005e42022-03-06 13:53:58 -0800144 stats := db.Stats{
Philipp Schraderfee07e12022-03-17 22:19:47 -0700145 TeamNumber: request.Team(),
146 MatchNumber: request.Match(),
Philipp Schrader30b4a682022-04-16 14:36:17 -0700147 SetNumber: request.SetNumber(),
Philipp Schrader4535b7e2022-04-08 20:27:00 -0700148 CompLevel: string(request.CompLevel()),
Philipp Schraderfee07e12022-03-17 22:19:47 -0700149 StartingQuadrant: request.StartingQuadrant(),
150 AutoBallPickedUp: [5]bool{
151 request.AutoBall1(), request.AutoBall2(), request.AutoBall3(),
152 request.AutoBall4(), request.AutoBall5(),
153 },
Philipp Schraderfa45d742022-03-18 19:29:05 -0700154 ShotsMissedAuto: request.MissedShotsAuto(),
155 UpperGoalAuto: request.UpperGoalAuto(),
156 LowerGoalAuto: request.LowerGoalAuto(),
157 ShotsMissed: request.MissedShotsTele(),
158 UpperGoalShots: request.UpperGoalTele(),
159 LowerGoalShots: request.LowerGoalTele(),
160 PlayedDefense: request.DefenseRating(),
161 DefenseReceivedScore: request.DefenseReceivedRating(),
162 Climbing: int32(request.ClimbLevel()),
163 CollectedBy: username,
164 Comment: string(request.Comment()),
Philipp Schrader30005e42022-03-06 13:53:58 -0800165 }
Philipp Schradercdb5cfc2022-02-20 14:57:07 -0800166
Philipp Schraderfee07e12022-03-17 22:19:47 -0700167 // Do some error checking.
168 if stats.StartingQuadrant < 1 || stats.StartingQuadrant > 4 {
169 respondWithError(w, http.StatusBadRequest, fmt.Sprint(
170 "Invalid starting_quadrant field value of ", stats.StartingQuadrant))
171 return
172 }
173
Philipp Schrader30005e42022-03-06 13:53:58 -0800174 err = handler.db.AddToStats(stats)
175 if err != nil {
176 respondWithError(w, http.StatusInternalServerError, fmt.Sprint("Failed to submit datascouting data: ", err))
Philipp Schraderfee07e12022-03-17 22:19:47 -0700177 return
Philipp Schrader30005e42022-03-06 13:53:58 -0800178 }
179
180 builder := flatbuffers.NewBuilder(50 * 1024)
181 builder.Finish((&SubmitDataScoutingResponseT{}).Pack(builder))
182 w.Write(builder.FinishedBytes())
Philipp Schradercdb5cfc2022-02-20 14:57:07 -0800183}
184
Philipp Schradercbf5c6a2022-02-27 23:25:19 -0800185// Handles a RequestAllMaches request.
186type requestAllMatchesHandler struct {
187 db Database
188}
189
190func (handler requestAllMatchesHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
191 requestBytes, err := io.ReadAll(req.Body)
192 if err != nil {
193 respondWithError(w, http.StatusBadRequest, fmt.Sprint("Failed to read request bytes:", err))
194 return
195 }
196
Philipp Schraderb7e75932022-03-26 16:18:34 -0700197 _, success := parseRequest(w, requestBytes, "RequestAllMatches", request_all_matches.GetRootAsRequestAllMatches)
Philipp Schradercbf5c6a2022-02-27 23:25:19 -0800198 if !success {
199 return
200 }
201
202 matches, err := handler.db.ReturnMatches()
203 if err != nil {
Philipp Schraderfae8a7e2022-03-13 22:51:54 -0700204 respondWithError(w, http.StatusInternalServerError, fmt.Sprint("Failed to query database: ", err))
Philipp Schrader2e7eb0002022-03-02 22:52:39 -0800205 return
Philipp Schradercbf5c6a2022-02-27 23:25:19 -0800206 }
207
208 var response RequestAllMatchesResponseT
209 for _, match := range matches {
210 response.MatchList = append(response.MatchList, &request_all_matches_response.MatchT{
211 MatchNumber: match.MatchNumber,
Philipp Schrader30b4a682022-04-16 14:36:17 -0700212 SetNumber: match.SetNumber,
Philipp Schradercbf5c6a2022-02-27 23:25:19 -0800213 CompLevel: match.CompLevel,
214 R1: match.R1,
215 R2: match.R2,
216 R3: match.R3,
217 B1: match.B1,
218 B2: match.B2,
219 B3: match.B3,
220 })
221 }
222
223 builder := flatbuffers.NewBuilder(50 * 1024)
224 builder.Finish((&response).Pack(builder))
225 w.Write(builder.FinishedBytes())
226}
227
Philipp Schraderd1c4bef2022-02-28 22:51:30 -0800228// Handles a RequestMatchesForTeam request.
229type requestMatchesForTeamHandler struct {
230 db Database
231}
232
233func (handler requestMatchesForTeamHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
234 requestBytes, err := io.ReadAll(req.Body)
235 if err != nil {
236 respondWithError(w, http.StatusBadRequest, fmt.Sprint("Failed to read request bytes:", err))
237 return
238 }
239
Philipp Schraderb7e75932022-03-26 16:18:34 -0700240 request, success := parseRequest(w, requestBytes, "RequestMatchesForTeam", request_matches_for_team.GetRootAsRequestMatchesForTeam)
Philipp Schraderd1c4bef2022-02-28 22:51:30 -0800241 if !success {
242 return
243 }
244
245 matches, err := handler.db.QueryMatches(request.Team())
246 if err != nil {
247 respondWithError(w, http.StatusInternalServerError, fmt.Sprint("Faled to query database: ", err))
Philipp Schrader2e7eb0002022-03-02 22:52:39 -0800248 return
Philipp Schraderd1c4bef2022-02-28 22:51:30 -0800249 }
250
251 var response RequestAllMatchesResponseT
252 for _, match := range matches {
253 response.MatchList = append(response.MatchList, &request_all_matches_response.MatchT{
254 MatchNumber: match.MatchNumber,
Philipp Schrader30b4a682022-04-16 14:36:17 -0700255 SetNumber: match.SetNumber,
Philipp Schraderd1c4bef2022-02-28 22:51:30 -0800256 CompLevel: match.CompLevel,
257 R1: match.R1,
258 R2: match.R2,
259 R3: match.R3,
260 B1: match.B1,
261 B2: match.B2,
262 B3: match.B3,
263 })
264 }
265
266 builder := flatbuffers.NewBuilder(50 * 1024)
267 builder.Finish((&response).Pack(builder))
268 w.Write(builder.FinishedBytes())
269}
270
Philipp Schraderacf96232022-03-01 22:03:30 -0800271// Handles a RequestDataScouting request.
272type requestDataScoutingHandler struct {
273 db Database
274}
275
276func (handler requestDataScoutingHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
277 requestBytes, err := io.ReadAll(req.Body)
278 if err != nil {
279 respondWithError(w, http.StatusBadRequest, fmt.Sprint("Failed to read request bytes:", err))
280 return
281 }
282
Philipp Schraderb7e75932022-03-26 16:18:34 -0700283 _, success := parseRequest(w, requestBytes, "RequestDataScouting", request_data_scouting.GetRootAsRequestDataScouting)
Philipp Schraderacf96232022-03-01 22:03:30 -0800284 if !success {
285 return
286 }
287
288 stats, err := handler.db.ReturnStats()
289 if err != nil {
290 respondWithError(w, http.StatusInternalServerError, fmt.Sprint("Faled to query database: ", err))
Philipp Schrader2e7eb0002022-03-02 22:52:39 -0800291 return
Philipp Schraderacf96232022-03-01 22:03:30 -0800292 }
293
294 var response RequestDataScoutingResponseT
295 for _, stat := range stats {
296 response.StatsList = append(response.StatsList, &request_data_scouting_response.StatsT{
Philipp Schraderfa45d742022-03-18 19:29:05 -0700297 Team: stat.TeamNumber,
298 Match: stat.MatchNumber,
Philipp Schrader30b4a682022-04-16 14:36:17 -0700299 SetNumber: stat.SetNumber,
Philipp Schrader4535b7e2022-04-08 20:27:00 -0700300 CompLevel: stat.CompLevel,
Philipp Schraderfa45d742022-03-18 19:29:05 -0700301 StartingQuadrant: stat.StartingQuadrant,
302 AutoBall1: stat.AutoBallPickedUp[0],
303 AutoBall2: stat.AutoBallPickedUp[1],
304 AutoBall3: stat.AutoBallPickedUp[2],
305 AutoBall4: stat.AutoBallPickedUp[3],
306 AutoBall5: stat.AutoBallPickedUp[4],
307 MissedShotsAuto: stat.ShotsMissedAuto,
308 UpperGoalAuto: stat.UpperGoalAuto,
309 LowerGoalAuto: stat.LowerGoalAuto,
310 MissedShotsTele: stat.ShotsMissed,
311 UpperGoalTele: stat.UpperGoalShots,
312 LowerGoalTele: stat.LowerGoalShots,
313 DefenseRating: stat.PlayedDefense,
314 DefenseReceivedRating: stat.DefenseReceivedScore,
315 ClimbLevel: request_data_scouting_response.ClimbLevel(stat.Climbing),
316 CollectedBy: stat.CollectedBy,
317 Comment: stat.Comment,
Philipp Schraderacf96232022-03-01 22:03:30 -0800318 })
319 }
320
321 builder := flatbuffers.NewBuilder(50 * 1024)
322 builder.Finish((&response).Pack(builder))
323 w.Write(builder.FinishedBytes())
324}
325
Philipp Schraderd3fac192022-03-02 20:35:46 -0800326func parseTeamKey(teamKey string) (int, error) {
327 // TBA prefixes teams with "frc". Not sure why. Get rid of that.
328 teamKey = strings.TrimPrefix(teamKey, "frc")
329 return strconv.Atoi(teamKey)
330}
331
332// Parses the alliance data from the specified match and returns the three red
333// teams and the three blue teams.
334func parseTeamKeys(match *scraping.Match) ([3]int32, [3]int32, error) {
335 redKeys := match.Alliances.Red.TeamKeys
336 blueKeys := match.Alliances.Blue.TeamKeys
337
338 if len(redKeys) != 3 || len(blueKeys) != 3 {
339 return [3]int32{}, [3]int32{}, errors.New(fmt.Sprintf(
340 "Found %d red teams and %d blue teams.", len(redKeys), len(blueKeys)))
341 }
342
343 var red [3]int32
344 for i, key := range redKeys {
345 team, err := parseTeamKey(key)
346 if err != nil {
347 return [3]int32{}, [3]int32{}, errors.New(fmt.Sprintf(
348 "Failed to parse red %d team '%s' as integer: %v", i+1, key, err))
349 }
350 red[i] = int32(team)
351 }
352 var blue [3]int32
353 for i, key := range blueKeys {
354 team, err := parseTeamKey(key)
355 if err != nil {
356 return [3]int32{}, [3]int32{}, errors.New(fmt.Sprintf(
357 "Failed to parse blue %d team '%s' as integer: %v", i+1, key, err))
358 }
359 blue[i] = int32(team)
360 }
361 return red, blue, nil
362}
363
364type refreshMatchListHandler struct {
365 db Database
366 scrape ScrapeMatchList
367}
368
369func (handler refreshMatchListHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
370 requestBytes, err := io.ReadAll(req.Body)
371 if err != nil {
372 respondWithError(w, http.StatusBadRequest, fmt.Sprint("Failed to read request bytes:", err))
373 return
374 }
375
Philipp Schraderb7e75932022-03-26 16:18:34 -0700376 request, success := parseRequest(w, requestBytes, "RefreshMatchList", refresh_match_list.GetRootAsRefreshMatchList)
Philipp Schraderd3fac192022-03-02 20:35:46 -0800377 if !success {
378 return
379 }
380
381 matches, err := handler.scrape(request.Year(), string(request.EventCode()))
382 if err != nil {
383 respondWithError(w, http.StatusInternalServerError, fmt.Sprint("Faled to scrape match list: ", err))
384 return
385 }
386
387 for _, match := range matches {
388 // Make sure the data is valid.
389 red, blue, err := parseTeamKeys(&match)
390 if err != nil {
391 respondWithError(w, http.StatusInternalServerError, fmt.Sprintf(
392 "TheBlueAlliance data for match %d is malformed: %v", match.MatchNumber, err))
393 return
394 }
395 // Add the match to the database.
Philipp Schrader7365d322022-03-06 16:40:08 -0800396 err = handler.db.AddToMatch(db.Match{
Philipp Schraderd3fac192022-03-02 20:35:46 -0800397 MatchNumber: int32(match.MatchNumber),
Philipp Schrader30b4a682022-04-16 14:36:17 -0700398 SetNumber: int32(match.SetNumber),
Philipp Schrader45befdd2022-04-08 19:12:44 -0700399 CompLevel: match.CompLevel,
400 R1: red[0],
401 R2: red[1],
402 R3: red[2],
403 B1: blue[0],
404 B2: blue[1],
405 B3: blue[2],
Philipp Schraderd3fac192022-03-02 20:35:46 -0800406 })
Philipp Schrader7365d322022-03-06 16:40:08 -0800407 if err != nil {
408 respondWithError(w, http.StatusInternalServerError, fmt.Sprintf(
409 "Failed to add match %d to the database: %v", match.MatchNumber, err))
410 return
411 }
Philipp Schraderd3fac192022-03-02 20:35:46 -0800412 }
413
414 var response RefreshMatchListResponseT
415 builder := flatbuffers.NewBuilder(1024)
416 builder.Finish((&response).Pack(builder))
417 w.Write(builder.FinishedBytes())
418}
419
Alex Perry81f96ba2022-03-13 18:26:19 -0700420type submitNoteScoutingHandler struct {
421 db Database
422}
423
424func (handler submitNoteScoutingHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
425 requestBytes, err := io.ReadAll(req.Body)
426 if err != nil {
427 respondWithError(w, http.StatusBadRequest, fmt.Sprint("Failed to read request bytes:", err))
428 return
429 }
430
Philipp Schraderb7e75932022-03-26 16:18:34 -0700431 request, success := parseRequest(w, requestBytes, "SubmitNotes", submit_notes.GetRootAsSubmitNotes)
Alex Perry81f96ba2022-03-13 18:26:19 -0700432 if !success {
433 return
434 }
435
436 err = handler.db.AddNotes(db.NotesData{
437 TeamNumber: request.Team(),
438 Notes: []string{string(request.Notes())},
439 })
440 if err != nil {
441 respondWithError(w, http.StatusInternalServerError, fmt.Sprintf("Failed to insert notes: %v", err))
442 return
443 }
444
445 var response SubmitNotesResponseT
446 builder := flatbuffers.NewBuilder(10)
447 builder.Finish((&response).Pack(builder))
448 w.Write(builder.FinishedBytes())
449}
450
Alex Perry81f96ba2022-03-13 18:26:19 -0700451type requestNotesForTeamHandler struct {
452 db Database
453}
454
455func (handler requestNotesForTeamHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
456 requestBytes, err := io.ReadAll(req.Body)
457 if err != nil {
458 respondWithError(w, http.StatusBadRequest, fmt.Sprint("Failed to read request bytes:", err))
459 return
460 }
461
Philipp Schraderb7e75932022-03-26 16:18:34 -0700462 request, success := parseRequest(w, requestBytes, "RequestNotesForTeam", request_notes_for_team.GetRootAsRequestNotesForTeam)
Alex Perry81f96ba2022-03-13 18:26:19 -0700463 if !success {
464 return
465 }
466
467 notesData, err := handler.db.QueryNotes(request.Team())
468 if err != nil {
469 respondWithError(w, http.StatusInternalServerError, fmt.Sprintf("Failed to query notes: %v", err))
470 return
471 }
472
473 var response RequestNotesForTeamResponseT
474 for _, data := range notesData.Notes {
475 response.Notes = append(response.Notes, &request_notes_for_team_response.NoteT{data})
476 }
477
478 builder := flatbuffers.NewBuilder(1024)
479 builder.Finish((&response).Pack(builder))
480 w.Write(builder.FinishedBytes())
481}
482
Philipp Schraderd3fac192022-03-02 20:35:46 -0800483func HandleRequests(db Database, scrape ScrapeMatchList, scoutingServer server.ScoutingServer) {
Philipp Schradercdb5cfc2022-02-20 14:57:07 -0800484 scoutingServer.HandleFunc("/requests", unknown)
Philipp Schrader8747f1b2022-02-23 23:56:22 -0800485 scoutingServer.Handle("/requests/submit/data_scouting", submitDataScoutingHandler{db})
Philipp Schradercbf5c6a2022-02-27 23:25:19 -0800486 scoutingServer.Handle("/requests/request/all_matches", requestAllMatchesHandler{db})
Philipp Schraderd1c4bef2022-02-28 22:51:30 -0800487 scoutingServer.Handle("/requests/request/matches_for_team", requestMatchesForTeamHandler{db})
Philipp Schraderacf96232022-03-01 22:03:30 -0800488 scoutingServer.Handle("/requests/request/data_scouting", requestDataScoutingHandler{db})
Philipp Schraderd3fac192022-03-02 20:35:46 -0800489 scoutingServer.Handle("/requests/refresh_match_list", refreshMatchListHandler{db, scrape})
Alex Perry81f96ba2022-03-13 18:26:19 -0700490 scoutingServer.Handle("/requests/submit/submit_notes", submitNoteScoutingHandler{db})
491 scoutingServer.Handle("/requests/request/notes_for_team", requestNotesForTeamHandler{db})
Philipp Schradercdb5cfc2022-02-20 14:57:07 -0800492}