Scouting: Add handler for actions in db.go
Signed-off-by: Sabina Leaver <100027607@mvla.net>
Change-Id: I234a4a838c236dcea209aa1fbceefb0b6566dc08
diff --git a/scouting/webserver/requests/debug/BUILD b/scouting/webserver/requests/debug/BUILD
index f3f4a72..d9bb030 100644
--- a/scouting/webserver/requests/debug/BUILD
+++ b/scouting/webserver/requests/debug/BUILD
@@ -14,6 +14,7 @@
"//scouting/webserver/requests/messages:request_all_notes_response_go_fbs",
"//scouting/webserver/requests/messages:request_notes_for_team_response_go_fbs",
"//scouting/webserver/requests/messages:request_shift_schedule_response_go_fbs",
+ "//scouting/webserver/requests/messages:submit_actions_response_go_fbs",
"//scouting/webserver/requests/messages:submit_driver_ranking_response_go_fbs",
"//scouting/webserver/requests/messages:submit_notes_response_go_fbs",
"//scouting/webserver/requests/messages:submit_shift_schedule_response_go_fbs",
diff --git a/scouting/webserver/requests/debug/debug.go b/scouting/webserver/requests/debug/debug.go
index eb3a1ca..acb9dd4 100644
--- a/scouting/webserver/requests/debug/debug.go
+++ b/scouting/webserver/requests/debug/debug.go
@@ -16,6 +16,7 @@
"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_all_notes_response"
"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_notes_for_team_response"
"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_shift_schedule_response"
+ "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_actions_response"
"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_driver_ranking_response"
"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_notes_response"
"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_shift_schedule_response"
@@ -157,3 +158,9 @@
server+"/requests/submit/submit_driver_ranking", requestBytes,
submit_driver_ranking_response.GetRootAsSubmitDriverRankingResponse)
}
+
+func SubmitActions(server string, requestBytes []byte) (*submit_actions_response.SubmitActionsResponseT, error) {
+ return sendMessage[submit_actions_response.SubmitActionsResponseT](
+ server+"/requests/submit/submit_actions", requestBytes,
+ submit_actions_response.GetRootAsSubmitActionsResponse)
+}
diff --git a/scouting/webserver/requests/messages/submit_actions.fbs b/scouting/webserver/requests/messages/submit_actions.fbs
index 8c79097..d8aa98d 100644
--- a/scouting/webserver/requests/messages/submit_actions.fbs
+++ b/scouting/webserver/requests/messages/submit_actions.fbs
@@ -62,5 +62,6 @@
set_number:int (id: 2);
comp_level:string (id: 3);
actions_list:[Action] (id:4);
+ //TODO: delete this field
collected_by:string (id: 5);
}
diff --git a/scouting/webserver/requests/requests.go b/scouting/webserver/requests/requests.go
index 9305274..8646a30 100644
--- a/scouting/webserver/requests/requests.go
+++ b/scouting/webserver/requests/requests.go
@@ -56,6 +56,7 @@
type SubmitDriverRanking = submit_driver_ranking.SubmitDriverRanking
type SubmitDriverRankingResponseT = submit_driver_ranking_response.SubmitDriverRankingResponseT
type SubmitActions = submit_actions.SubmitActions
+type Action = submit_actions.Action
type SubmitActionsResponseT = submit_actions_response.SubmitActionsResponseT
// The interface we expect the database abstraction to conform to.
@@ -74,6 +75,7 @@
QueryNotes(int32) ([]string, error)
AddNotes(db.NotesData) error
AddDriverRanking(db.DriverRankingData) error
+ AddAction(db.Action) error
}
// Handles unknown requests. Just returns a 404.
@@ -785,6 +787,62 @@
w.Write(builder.FinishedBytes())
}
+type submitActionsHandler struct {
+ db Database
+}
+
+func (handler submitActionsHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
+ // Get the username of the person submitting the data.
+ username := parseUsername(req)
+
+ requestBytes, err := io.ReadAll(req.Body)
+ if err != nil {
+ respondWithError(w, http.StatusBadRequest, fmt.Sprint("Failed to read request bytes:", err))
+ return
+ }
+
+ request, success := parseRequest(w, requestBytes, "SubmitActions", submit_actions.GetRootAsSubmitActions)
+ if !success {
+ return
+ }
+
+ log.Println("Got actions for match", request.MatchNumber(), "team", request.TeamNumber(), "from", username)
+
+ for i := 0; i < request.ActionsListLength(); i++ {
+
+ var action Action
+ request.ActionsList(&action, i)
+
+ dbAction := db.Action{
+ TeamNumber: string(request.TeamNumber()),
+ MatchNumber: request.MatchNumber(),
+ SetNumber: request.SetNumber(),
+ CompLevel: string(request.CompLevel()),
+ //TODO: Serialize CompletedAction
+ CompletedAction: []byte{},
+ Timestamp: action.Timestamp(),
+ CollectedBy: username,
+ }
+
+ // Do some error checking.
+ if action.Timestamp() < 0 {
+ respondWithError(w, http.StatusBadRequest, fmt.Sprint(
+ "Invalid timestamp field value of ", action.Timestamp()))
+ return
+ }
+
+ err = handler.db.AddAction(dbAction)
+ if err != nil {
+ respondWithError(w, http.StatusInternalServerError, fmt.Sprint("Failed to add action to database: ", err))
+ return
+ }
+ }
+
+ builder := flatbuffers.NewBuilder(50 * 1024)
+ builder.Finish((&SubmitActionsResponseT{}).Pack(builder))
+ w.Write(builder.FinishedBytes())
+}
+
func HandleRequests(db Database, scoutingServer server.ScoutingServer) {
scoutingServer.HandleFunc("/requests", unknown)
scoutingServer.Handle("/requests/request/all_matches", requestAllMatchesHandler{db})
@@ -796,4 +854,5 @@
scoutingServer.Handle("/requests/submit/shift_schedule", submitShiftScheduleHandler{db})
scoutingServer.Handle("/requests/request/shift_schedule", requestShiftScheduleHandler{db})
scoutingServer.Handle("/requests/submit/submit_driver_ranking", SubmitDriverRankingHandler{db})
+ scoutingServer.Handle("/requests/submit/submit_actions", submitActionsHandler{db})
}
diff --git a/scouting/webserver/requests/requests_test.go b/scouting/webserver/requests/requests_test.go
index dab3174..ac644ea 100644
--- a/scouting/webserver/requests/requests_test.go
+++ b/scouting/webserver/requests/requests_test.go
@@ -752,6 +752,109 @@
}
}
+func packAction(action *submit_actions.ActionT) []byte {
+ builder := flatbuffers.NewBuilder(50 * 1024)
+ builder.Finish((action).Pack(builder))
+ return (builder.FinishedBytes())
+}
+
+func TestAddingActions(t *testing.T) {
+ database := MockDatabase{}
+ scoutingServer := server.NewScoutingServer()
+ HandleRequests(&database, scoutingServer)
+ scoutingServer.Start(8080)
+ defer scoutingServer.Stop()
+
+ builder := flatbuffers.NewBuilder(1024)
+ builder.Finish((&submit_actions.SubmitActionsT{
+ TeamNumber: "1234",
+ MatchNumber: 4,
+ SetNumber: 1,
+ CompLevel: "qual",
+ ActionsList: []*submit_actions.ActionT{
+ {
+ ActionTaken: &submit_actions.ActionTypeT{
+ Type: submit_actions.ActionTypePickupObjectAction,
+ Value: &submit_actions.PickupObjectActionT{
+ ObjectType: submit_actions.ObjectTypekCube,
+ Auto: true,
+ },
+ },
+ Timestamp: 2400,
+ },
+ {
+ ActionTaken: &submit_actions.ActionTypeT{
+ Type: submit_actions.ActionTypePlaceObjectAction,
+ Value: &submit_actions.PlaceObjectActionT{
+ ObjectType: submit_actions.ObjectTypekCube,
+ ScoreLevel: submit_actions.ScoreLevelkLow,
+ Auto: false,
+ },
+ },
+ Timestamp: 1009,
+ },
+ },
+ }).Pack(builder))
+
+ _, err := debug.SubmitActions("http://localhost:8080", builder.FinishedBytes())
+ if err != nil {
+ t.Fatal("Failed to submit actions: ", err)
+ }
+
+ // Make sure that the data made it into the database.
+ // TODO: Add this back when we figure out how to add the serialized action into the database.
+
+ /* expectedActionsT := []*submit_actions.ActionT{
+ {
+ ActionTaken: &submit_actions.ActionTypeT{
+ Type: submit_actions.ActionTypePickupObjectAction,
+ Value: &submit_actions.PickupObjectActionT{
+ ObjectType: submit_actions.ObjectTypekCube,
+ Auto: true,
+ },
+ },
+ Timestamp: 2400,
+ },
+ {
+ ActionTaken: &submit_actions.ActionTypeT{
+ Type: submit_actions.ActionTypePlaceObjectAction,
+ Value: &submit_actions.PlaceObjectActionT{
+ ObjectType: submit_actions.ObjectTypekCube,
+ ScoreLevel: submit_actions.ScoreLevelkLow,
+ Auto: false,
+ },
+ },
+ Timestamp: 1009,
+ },
+ } */
+
+ expectedActions := []db.Action{
+ {
+ TeamNumber: "1234",
+ MatchNumber: 4,
+ SetNumber: 1,
+ CompLevel: "qual",
+ CollectedBy: "debug_cli",
+ CompletedAction: []byte{},
+ Timestamp: 2400,
+ },
+ {
+ TeamNumber: "1234",
+ MatchNumber: 4,
+ SetNumber: 1,
+ CompLevel: "qual",
+ CollectedBy: "debug_cli",
+ CompletedAction: []byte{},
+ Timestamp: 1009,
+ },
+ }
+
+ if !reflect.DeepEqual(expectedActions, database.actions) {
+ t.Fatal("Expected ", expectedActions, ", but got:", database.actions)
+ }
+
+}
+
// A mocked database we can use for testing. Add functionality to this as
// needed for your tests.
@@ -761,6 +864,7 @@
shiftSchedule []db.Shift
driver_ranking []db.DriverRankingData
stats2023 []db.Stats2023
+ actions []db.Action
}
func (database *MockDatabase) AddToMatch(match db.TeamMatch) error {
@@ -830,3 +934,12 @@
func (database *MockDatabase) ReturnAllDriverRankings() ([]db.DriverRankingData, error) {
return database.driver_ranking, nil
}
+
+func (database *MockDatabase) AddAction(action db.Action) error {
+ database.actions = append(database.actions, action)
+ return nil
+}
+
+func (database *MockDatabase) ReturnActions() ([]db.Action, error) {
+ return database.actions, nil
+}