scouting: Add "defense received" and "comments" to the database

This patch makes it so the webserver saves the "defense received" and
"comment" fields to the database.

Signed-off-by: Philipp Schrader <philipp.schrader@gmail.com>
Change-Id: I3a76518095f7b38360b5c43ae3a117215244c3da
diff --git a/scouting/db/db.go b/scouting/db/db.go
index 4b40dbc..85395e1 100644
--- a/scouting/db/db.go
+++ b/scouting/db/db.go
@@ -25,8 +25,9 @@
 	StartingQuadrant        int32
 	AutoBallPickedUp        [5]bool
 	// TODO(phil): Re-order auto and teleop fields so auto comes first.
-	ShotsMissed, UpperGoalShots, LowerGoalShots                  int32
-	ShotsMissedAuto, UpperGoalAuto, LowerGoalAuto, PlayedDefense int32
+	ShotsMissed, UpperGoalShots, LowerGoalShots   int32
+	ShotsMissedAuto, UpperGoalAuto, LowerGoalAuto int32
+	PlayedDefense, DefenseReceivedScore           int32
 	// Climbing level:
 	// 0 -> "NoAttempt"
 	// 1 -> "Failed"
@@ -36,6 +37,8 @@
 	// 5 -> "High"
 	// 6 -> "Transversal"
 	Climbing int32
+	// Some non-numerical data that the scout felt worth noting.
+	Comment string
 	// The username of the person who collected these statistics.
 	// "unknown" if submitted without logging in.
 	// Empty if the stats have not yet been collected.
@@ -105,7 +108,9 @@
 		"UpperGoalAuto INTEGER, " +
 		"LowerGoalAuto INTEGER, " +
 		"PlayedDefense INTEGER, " +
+		"DefenseReceivedScore INTEGER, " +
 		"Climbing INTEGER, " +
+		"Comment VARCHAR, " +
 		"CollectedBy VARCHAR)")
 	if err != nil {
 		database.Close()
@@ -175,7 +180,8 @@
 		"AutoBall4PickedUp, AutoBall5PickedUp, " +
 		"ShotsMissed, UpperGoalShots, LowerGoalShots, " +
 		"ShotsMissedAuto, UpperGoalAuto, LowerGoalAuto, " +
-		"PlayedDefense, Climbing, CollectedBy) " +
+		"PlayedDefense, DefenseReceivedScore, Climbing, " +
+		"Comment, CollectedBy) " +
 		"VALUES (" +
 		"$1, $2, " +
 		"$3, " +
@@ -183,7 +189,8 @@
 		"$7, $8, " +
 		"$9, $10, $11, " +
 		"$12, $13, $14, " +
-		"$15, $16, $17) " +
+		"$15, $16, $17, " +
+		"$18, $19) " +
 		"RETURNING id")
 	if err != nil {
 		return errors.New(fmt.Sprint("Failed to prepare insertion into stats database: ", err))
@@ -199,7 +206,8 @@
 			false, false,
 			0, 0, 0,
 			0, 0, 0,
-			0, 0, "")
+			0, 0, 0,
+			"", "")
 		err = row.Scan(&rowIds[i])
 		if err != nil {
 			return errors.New(fmt.Sprint("Failed to insert stats: ", err))
@@ -236,8 +244,9 @@
 		"AutoBall4PickedUp = $7, AutoBall5PickedUp = $8, " +
 		"ShotsMissed = $9, UpperGoalShots = $10, LowerGoalShots = $11, " +
 		"ShotsMissedAuto = $12, UpperGoalAuto = $13, LowerGoalAuto = $14, " +
-		"PlayedDefense = $15, Climbing = $16, CollectedBy = $17 " +
-		"WHERE MatchNumber = $18 AND TeamNumber = $19")
+		"PlayedDefense = $15, DefenseReceivedScore = $16, Climbing = $17, " +
+		"Comment = $18, CollectedBy = $19 " +
+		"WHERE MatchNumber = $20 AND TeamNumber = $21")
 	if err != nil {
 		return errors.New(fmt.Sprint("Failed to prepare stats update statement: ", err))
 	}
@@ -250,7 +259,8 @@
 		s.AutoBallPickedUp[3], s.AutoBallPickedUp[4],
 		s.ShotsMissed, s.UpperGoalShots, s.LowerGoalShots,
 		s.ShotsMissedAuto, s.UpperGoalAuto, s.LowerGoalAuto,
-		s.PlayedDefense, s.Climbing, s.CollectedBy,
+		s.PlayedDefense, s.DefenseReceivedScore, s.Climbing,
+		s.Comment, s.CollectedBy,
 		s.MatchNumber, s.TeamNumber)
 	if err != nil {
 		return errors.New(fmt.Sprint("Failed to update stats database: ", err))
@@ -308,7 +318,8 @@
 			&team.AutoBallPickedUp[3], &team.AutoBallPickedUp[4],
 			&team.ShotsMissed, &team.UpperGoalShots, &team.LowerGoalShots,
 			&team.ShotsMissedAuto, &team.UpperGoalAuto, &team.LowerGoalAuto,
-			&team.PlayedDefense, &team.Climbing, &team.CollectedBy)
+			&team.PlayedDefense, &team.DefenseReceivedScore, &team.Climbing,
+			&team.Comment, &team.CollectedBy)
 		if err != nil {
 			return nil, errors.New(fmt.Sprint("Failed to scan from stats: ", err))
 		}
@@ -359,7 +370,8 @@
 			&team.AutoBallPickedUp[3], &team.AutoBallPickedUp[4],
 			&team.ShotsMissed, &team.UpperGoalShots, &team.LowerGoalShots,
 			&team.ShotsMissedAuto, &team.UpperGoalAuto, &team.LowerGoalAuto,
-			&team.PlayedDefense, &team.Climbing, &team.CollectedBy)
+			&team.PlayedDefense, &team.DefenseReceivedScore, &team.Climbing,
+			&team.Comment, &team.CollectedBy)
 		if err != nil {
 			return nil, errors.New(fmt.Sprint("Failed to scan from stats: ", err))
 		}
diff --git a/scouting/db/db_test.go b/scouting/db/db_test.go
index c5bea5e..02e8d50 100644
--- a/scouting/db/db_test.go
+++ b/scouting/db/db_test.go
@@ -93,8 +93,8 @@
 			AutoBallPickedUp: [5]bool{false, false, false, true, false},
 			ShotsMissed:      9, UpperGoalShots: 5, LowerGoalShots: 4,
 			ShotsMissedAuto: 3, UpperGoalAuto: 2, LowerGoalAuto: 1,
-			PlayedDefense: 2, Climbing: 3,
-			CollectedBy: "josh",
+			PlayedDefense: 2, DefenseReceivedScore: 0, Climbing: 3,
+			Comment: "this is a comment", CollectedBy: "josh",
 		},
 		Stats{
 			TeamNumber: 1001, MatchNumber: 7,
@@ -102,8 +102,8 @@
 			AutoBallPickedUp: [5]bool{true, false, true, true, false},
 			ShotsMissed:      6, UpperGoalShots: 9, LowerGoalShots: 9,
 			ShotsMissedAuto: 0, UpperGoalAuto: 0, LowerGoalAuto: 0,
-			PlayedDefense: 0, Climbing: 0,
-			CollectedBy: "rupert",
+			PlayedDefense: 0, DefenseReceivedScore: 1, Climbing: 0,
+			Comment: "another comment", CollectedBy: "rupert",
 		},
 		Stats{
 			TeamNumber: 777, MatchNumber: 7,
@@ -111,8 +111,8 @@
 			AutoBallPickedUp: [5]bool{false, true, true, true, false},
 			ShotsMissed:      5, UpperGoalShots: 7, LowerGoalShots: 12,
 			ShotsMissedAuto: 0, UpperGoalAuto: 4, LowerGoalAuto: 0,
-			PlayedDefense: 0, Climbing: 0,
-			CollectedBy: "felix",
+			PlayedDefense: 0, DefenseReceivedScore: 3, Climbing: 0,
+			Comment: "and another", CollectedBy: "felix",
 		},
 		Stats{
 			TeamNumber: 1000, MatchNumber: 7,
@@ -120,8 +120,8 @@
 			AutoBallPickedUp: [5]bool{false, false, false, false, false},
 			ShotsMissed:      12, UpperGoalShots: 6, LowerGoalShots: 10,
 			ShotsMissedAuto: 0, UpperGoalAuto: 7, LowerGoalAuto: 0,
-			PlayedDefense: 0, Climbing: 0,
-			CollectedBy: "thea",
+			PlayedDefense: 0, DefenseReceivedScore: 1, Climbing: 0,
+			Comment: "and another one", CollectedBy: "thea",
 		},
 		Stats{
 			TeamNumber: 4321, MatchNumber: 7,
@@ -129,8 +129,8 @@
 			AutoBallPickedUp: [5]bool{true, false, false, false, false},
 			ShotsMissed:      14, UpperGoalShots: 12, LowerGoalShots: 3,
 			ShotsMissedAuto: 0, UpperGoalAuto: 7, LowerGoalAuto: 0,
-			PlayedDefense: 0, Climbing: 0,
-			CollectedBy: "amy",
+			PlayedDefense: 0, DefenseReceivedScore: 0, Climbing: 0,
+			Comment: "more comment", CollectedBy: "amy",
 		},
 		Stats{
 			TeamNumber: 1234, MatchNumber: 7,
@@ -138,8 +138,8 @@
 			AutoBallPickedUp: [5]bool{false, false, false, false, true},
 			ShotsMissed:      3, UpperGoalShots: 4, LowerGoalShots: 0,
 			ShotsMissedAuto: 0, UpperGoalAuto: 9, LowerGoalAuto: 0,
-			PlayedDefense: 0, Climbing: 0,
-			CollectedBy: "beth",
+			PlayedDefense: 0, DefenseReceivedScore: 5, Climbing: 0,
+			Comment: "final comment", CollectedBy: "beth",
 		},
 	}
 
@@ -211,14 +211,14 @@
 			AutoBallPickedUp: [5]bool{false, false, false, false, false},
 			ShotsMissed:      2, UpperGoalShots: 2, LowerGoalShots: 2,
 			ShotsMissedAuto: 2, UpperGoalAuto: 2, LowerGoalAuto: 2,
-			PlayedDefense: 2, Climbing: 2},
+			PlayedDefense: 2, DefenseReceivedScore: 1, Climbing: 2},
 		Stats{
 			TeamNumber: 1234, MatchNumber: 94,
 			StartingQuadrant: 2,
 			AutoBallPickedUp: [5]bool{false, false, false, false, true},
 			ShotsMissed:      4, UpperGoalShots: 4, LowerGoalShots: 4,
 			ShotsMissedAuto: 4, UpperGoalAuto: 4, LowerGoalAuto: 4,
-			PlayedDefense: 7, Climbing: 2,
+			PlayedDefense: 7, DefenseReceivedScore: 1, Climbing: 2,
 		},
 		Stats{
 			TeamNumber: 1233, MatchNumber: 94,
@@ -226,7 +226,7 @@
 			AutoBallPickedUp: [5]bool{false, false, false, false, false},
 			ShotsMissed:      3, UpperGoalShots: 3, LowerGoalShots: 3,
 			ShotsMissedAuto: 3, UpperGoalAuto: 3, LowerGoalAuto: 3,
-			PlayedDefense: 3, Climbing: 3,
+			PlayedDefense: 3, DefenseReceivedScore: 0, Climbing: 3,
 		},
 		Stats{
 			TeamNumber: 1232, MatchNumber: 94,
@@ -234,7 +234,7 @@
 			AutoBallPickedUp: [5]bool{true, false, false, false, true},
 			ShotsMissed:      5, UpperGoalShots: 5, LowerGoalShots: 5,
 			ShotsMissedAuto: 5, UpperGoalAuto: 5, LowerGoalAuto: 5,
-			PlayedDefense: 7, Climbing: 1,
+			PlayedDefense: 7, DefenseReceivedScore: 2, Climbing: 1,
 		},
 		Stats{
 			TeamNumber: 1231, MatchNumber: 94,
@@ -242,7 +242,7 @@
 			AutoBallPickedUp: [5]bool{false, false, true, false, false},
 			ShotsMissed:      6, UpperGoalShots: 6, LowerGoalShots: 6,
 			ShotsMissedAuto: 6, UpperGoalAuto: 6, LowerGoalAuto: 6,
-			PlayedDefense: 7, Climbing: 1,
+			PlayedDefense: 7, DefenseReceivedScore: 3, Climbing: 1,
 		},
 		Stats{
 			TeamNumber: 1239, MatchNumber: 94,
@@ -250,7 +250,7 @@
 			AutoBallPickedUp: [5]bool{false, true, true, false, false},
 			ShotsMissed:      7, UpperGoalShots: 7, LowerGoalShots: 7,
 			ShotsMissedAuto: 7, UpperGoalAuto: 7, LowerGoalAuto: 3,
-			PlayedDefense: 7, Climbing: 1,
+			PlayedDefense: 7, DefenseReceivedScore: 5, Climbing: 1,
 		},
 	}
 
@@ -271,7 +271,7 @@
 			AutoBallPickedUp: [5]bool{false, false, false, false, false},
 			ShotsMissed:      2, UpperGoalShots: 2, LowerGoalShots: 2,
 			ShotsMissedAuto: 2, UpperGoalAuto: 2, LowerGoalAuto: 2,
-			PlayedDefense: 2, Climbing: 2,
+			PlayedDefense: 2, DefenseReceivedScore: 1, Climbing: 2,
 		},
 	}
 
@@ -339,14 +339,14 @@
 			AutoBallPickedUp: [5]bool{false, false, false, false, false},
 			ShotsMissed:      2, UpperGoalShots: 2, LowerGoalShots: 2,
 			ShotsMissedAuto: 2, UpperGoalAuto: 2, LowerGoalAuto: 2,
-			PlayedDefense: 2, Climbing: 2},
+			PlayedDefense: 2, DefenseReceivedScore: 3, Climbing: 2},
 		Stats{
 			TeamNumber: 1236, MatchNumber: 94,
 			StartingQuadrant: 2,
 			AutoBallPickedUp: [5]bool{false, false, false, false, true},
 			ShotsMissed:      4, UpperGoalShots: 4, LowerGoalShots: 4,
 			ShotsMissedAuto: 4, UpperGoalAuto: 4, LowerGoalAuto: 4,
-			PlayedDefense: 7, Climbing: 2,
+			PlayedDefense: 7, DefenseReceivedScore: 1, Climbing: 2,
 		},
 		Stats{
 			TeamNumber: 1237, MatchNumber: 94,
@@ -354,7 +354,7 @@
 			AutoBallPickedUp: [5]bool{false, false, false, false, false},
 			ShotsMissed:      3, UpperGoalShots: 3, LowerGoalShots: 3,
 			ShotsMissedAuto: 3, UpperGoalAuto: 3, LowerGoalAuto: 3,
-			PlayedDefense: 3, Climbing: 3,
+			PlayedDefense: 3, DefenseReceivedScore: 0, Climbing: 3,
 		},
 		Stats{
 			TeamNumber: 1238, MatchNumber: 94,
@@ -362,7 +362,7 @@
 			AutoBallPickedUp: [5]bool{true, false, false, false, true},
 			ShotsMissed:      5, UpperGoalShots: 5, LowerGoalShots: 5,
 			ShotsMissedAuto: 5, UpperGoalAuto: 5, LowerGoalAuto: 5,
-			PlayedDefense: 7, Climbing: 1,
+			PlayedDefense: 7, DefenseReceivedScore: 4, Climbing: 1,
 		},
 		Stats{
 			TeamNumber: 1239, MatchNumber: 94,
@@ -370,7 +370,7 @@
 			AutoBallPickedUp: [5]bool{false, false, true, false, false},
 			ShotsMissed:      6, UpperGoalShots: 6, LowerGoalShots: 6,
 			ShotsMissedAuto: 6, UpperGoalAuto: 6, LowerGoalAuto: 6,
-			PlayedDefense: 7, Climbing: 1,
+			PlayedDefense: 7, DefenseReceivedScore: 4, Climbing: 1,
 		},
 		Stats{
 			TeamNumber: 1233, MatchNumber: 94,
@@ -378,7 +378,7 @@
 			AutoBallPickedUp: [5]bool{false, true, true, false, false},
 			ShotsMissed:      7, UpperGoalShots: 7, LowerGoalShots: 7,
 			ShotsMissedAuto: 7, UpperGoalAuto: 7, LowerGoalAuto: 3,
-			PlayedDefense: 7, Climbing: 1,
+			PlayedDefense: 7, DefenseReceivedScore: 1, Climbing: 1,
 		},
 	}
 
diff --git a/scouting/scouting_test.ts b/scouting/scouting_test.ts
index 84824ff..6fab5fc 100644
--- a/scouting/scouting_test.ts
+++ b/scouting/scouting_test.ts
@@ -65,6 +65,18 @@
       protractor.Key.CONTROL, 'a', protractor.Key.NULL, value);
 }
 
+// Moves the nth slider left or right. A positive "adjustBy" value moves the
+// slider to the right. A negative value moves the slider to the left.
+//
+//   negative/left <--- 0 ---> positive/right
+async function adjustNthSliderBy(n: number, adjustBy: number) {
+  const slider =  element.all(by.css('input[type=range]')).get(n);
+  const key = adjustBy > 0 ? protractor.Key.ARROW_RIGHT : protractor.Key.ARROW_LEFT;
+  for (let i = 0; i < Math.abs(adjustBy); i++) {
+    await slider.sendKeys(key);
+  }
+}
+
 describe('The scouting web page', () => {
   beforeAll(async () => {
     await browser.get(browser.baseUrl);
@@ -128,9 +140,12 @@
 
     expect(await getHeadingText()).toEqual('Climb');
     await element(by.id('high')).click();
+    await setTextboxByIdTo("comment", "A very useful comment here.");
     await element(by.buttonText('Next')).click();
 
     expect(await getHeadingText()).toEqual('Other');
+    await adjustNthSliderBy(0, 3);
+    await adjustNthSliderBy(1, 1);
     await element(by.id('no_show')).click();
     await element(by.id('mechanically_broke')).click();
     await element(by.buttonText('Next')).click();
@@ -155,10 +170,11 @@
 
     // Validate Climb.
     await expectReviewFieldToBe('Level', 'High');
+    await expectReviewFieldToBe('Comments', 'A very useful comment here.');
 
     // Validate Other.
-    await expectReviewFieldToBe('Defense Played On Rating', '0');
-    await expectReviewFieldToBe('Defense Played Rating', '0');
+    await expectReviewFieldToBe('Defense Played On Rating', '3');
+    await expectReviewFieldToBe('Defense Played Rating', '1');
     await expectReviewFieldToBe('No show', 'true');
     await expectReviewFieldToBe('Never moved', 'false');
     await expectReviewFieldToBe('Battery died', 'false');
diff --git a/scouting/webserver/requests/debug/cli/cli_test.py b/scouting/webserver/requests/debug/cli/cli_test.py
index 718b2ce..5b0c749 100644
--- a/scouting/webserver/requests/debug/cli/cli_test.py
+++ b/scouting/webserver/requests/debug/cli/cli_test.py
@@ -75,7 +75,9 @@
             "upper_goal_tele": 14,
             "lower_goal_tele": 15,
             "defense_rating": 3,
+            "defense_received_rating": 4,
             "climb_level": "Medium",
+            "comment": "A very inspiring and useful comment",
         })
         exit_code, _, stderr = run_debug_cli(["-submitDataScouting", json_path])
         self.assertEqual(exit_code, 0, stderr)
@@ -104,7 +106,9 @@
             AutoBall4: (bool) false,
             AutoBall5: (bool) true,
             StartingQuadrant: (int32) 3,
-            ClimbLevel: (request_data_scouting_response.ClimbLevel) Medium
+            ClimbLevel: (request_data_scouting_response.ClimbLevel) Medium,
+            DefenseReceivedRating: (int32) 4,
+            Comment: (string) (len=35) "A very inspiring and useful comment"
             }"""), stdout)
 
     def test_request_all_matches(self):
diff --git a/scouting/webserver/requests/messages/request_data_scouting_response.fbs b/scouting/webserver/requests/messages/request_data_scouting_response.fbs
index d85dfbb..3987d7e 100644
--- a/scouting/webserver/requests/messages/request_data_scouting_response.fbs
+++ b/scouting/webserver/requests/messages/request_data_scouting_response.fbs
@@ -24,6 +24,7 @@
     upper_goal_tele:int (id:6);
     lower_goal_tele:int (id:7);
     defense_rating:int (id:8);
+    defense_received_rating:int (id:18);
 
     climbing:int (id:9, deprecated);
     climb_level:ClimbLevel (id:17);
@@ -38,6 +39,8 @@
     // The quadrant that the robot starts in for autonomous mode.
     // Valid values are 1 through 4.
     starting_quadrant: int (id:16);
+
+    comment:string (id:19);
 }
 
 table RequestDataScoutingResponse {
diff --git a/scouting/webserver/requests/requests.go b/scouting/webserver/requests/requests.go
index 118fafb..2554941 100644
--- a/scouting/webserver/requests/requests.go
+++ b/scouting/webserver/requests/requests.go
@@ -149,15 +149,17 @@
 			request.AutoBall1(), request.AutoBall2(), request.AutoBall3(),
 			request.AutoBall4(), request.AutoBall5(),
 		},
-		ShotsMissedAuto: request.MissedShotsAuto(),
-		UpperGoalAuto:   request.UpperGoalAuto(),
-		LowerGoalAuto:   request.LowerGoalAuto(),
-		ShotsMissed:     request.MissedShotsTele(),
-		UpperGoalShots:  request.UpperGoalTele(),
-		LowerGoalShots:  request.LowerGoalTele(),
-		PlayedDefense:   request.DefenseRating(),
-		Climbing:        int32(request.ClimbLevel()),
-		CollectedBy:     username,
+		ShotsMissedAuto:      request.MissedShotsAuto(),
+		UpperGoalAuto:        request.UpperGoalAuto(),
+		LowerGoalAuto:        request.LowerGoalAuto(),
+		ShotsMissed:          request.MissedShotsTele(),
+		UpperGoalShots:       request.UpperGoalTele(),
+		LowerGoalShots:       request.LowerGoalTele(),
+		PlayedDefense:        request.DefenseRating(),
+		DefenseReceivedScore: request.DefenseReceivedRating(),
+		Climbing:             int32(request.ClimbLevel()),
+		CollectedBy:          username,
+		Comment:              string(request.Comment()),
 	}
 
 	// Do some error checking.
@@ -329,23 +331,25 @@
 	var response RequestDataScoutingResponseT
 	for _, stat := range stats {
 		response.StatsList = append(response.StatsList, &request_data_scouting_response.StatsT{
-			Team:             stat.TeamNumber,
-			Match:            stat.MatchNumber,
-			StartingQuadrant: stat.StartingQuadrant,
-			AutoBall1:        stat.AutoBallPickedUp[0],
-			AutoBall2:        stat.AutoBallPickedUp[1],
-			AutoBall3:        stat.AutoBallPickedUp[2],
-			AutoBall4:        stat.AutoBallPickedUp[3],
-			AutoBall5:        stat.AutoBallPickedUp[4],
-			MissedShotsAuto:  stat.ShotsMissedAuto,
-			UpperGoalAuto:    stat.UpperGoalAuto,
-			LowerGoalAuto:    stat.LowerGoalAuto,
-			MissedShotsTele:  stat.ShotsMissed,
-			UpperGoalTele:    stat.UpperGoalShots,
-			LowerGoalTele:    stat.LowerGoalShots,
-			DefenseRating:    stat.PlayedDefense,
-			ClimbLevel:       request_data_scouting_response.ClimbLevel(stat.Climbing),
-			CollectedBy:      stat.CollectedBy,
+			Team:                  stat.TeamNumber,
+			Match:                 stat.MatchNumber,
+			StartingQuadrant:      stat.StartingQuadrant,
+			AutoBall1:             stat.AutoBallPickedUp[0],
+			AutoBall2:             stat.AutoBallPickedUp[1],
+			AutoBall3:             stat.AutoBallPickedUp[2],
+			AutoBall4:             stat.AutoBallPickedUp[3],
+			AutoBall5:             stat.AutoBallPickedUp[4],
+			MissedShotsAuto:       stat.ShotsMissedAuto,
+			UpperGoalAuto:         stat.UpperGoalAuto,
+			LowerGoalAuto:         stat.LowerGoalAuto,
+			MissedShotsTele:       stat.ShotsMissed,
+			UpperGoalTele:         stat.UpperGoalShots,
+			LowerGoalTele:         stat.LowerGoalShots,
+			DefenseRating:         stat.PlayedDefense,
+			DefenseReceivedRating: stat.DefenseReceivedScore,
+			ClimbLevel:            request_data_scouting_response.ClimbLevel(stat.Climbing),
+			CollectedBy:           stat.CollectedBy,
+			Comment:               stat.Comment,
 		})
 	}
 
diff --git a/scouting/webserver/requests/requests_test.go b/scouting/webserver/requests/requests_test.go
index 8165c7d..b864cf3 100644
--- a/scouting/webserver/requests/requests_test.go
+++ b/scouting/webserver/requests/requests_test.go
@@ -82,22 +82,24 @@
 
 	builder := flatbuffers.NewBuilder(1024)
 	builder.Finish((&submit_data_scouting.SubmitDataScoutingT{
-		Team:             971,
-		Match:            1,
-		StartingQuadrant: 2,
-		AutoBall1:        true,
-		AutoBall2:        false,
-		AutoBall3:        false,
-		AutoBall4:        false,
-		AutoBall5:        false,
-		MissedShotsAuto:  9971,
-		UpperGoalAuto:    9971,
-		LowerGoalAuto:    9971,
-		MissedShotsTele:  9971,
-		UpperGoalTele:    9971,
-		LowerGoalTele:    9971,
-		DefenseRating:    9971,
-		ClimbLevel:       submit_data_scouting.ClimbLevelLow,
+		Team:                  971,
+		Match:                 1,
+		StartingQuadrant:      2,
+		AutoBall1:             true,
+		AutoBall2:             false,
+		AutoBall3:             false,
+		AutoBall4:             false,
+		AutoBall5:             false,
+		MissedShotsAuto:       9971,
+		UpperGoalAuto:         9971,
+		LowerGoalAuto:         9971,
+		MissedShotsTele:       9971,
+		UpperGoalTele:         9971,
+		LowerGoalTele:         9971,
+		DefenseRating:         9971,
+		DefenseReceivedRating: 4,
+		ClimbLevel:            submit_data_scouting.ClimbLevelLow,
+		Comment:               "this is a comment",
 	}).Pack(builder))
 
 	response, err := debug.SubmitDataScouting("http://localhost:8080", builder.FinishedBytes())
@@ -231,8 +233,8 @@
 				AutoBallPickedUp: [5]bool{true, false, false, false, true},
 				ShotsMissed:      1, UpperGoalShots: 2, LowerGoalShots: 3,
 				ShotsMissedAuto: 4, UpperGoalAuto: 5, LowerGoalAuto: 6,
-				PlayedDefense: 7, Climbing: 2,
-				CollectedBy: "john",
+				PlayedDefense: 7, DefenseReceivedScore: 3, Climbing: 2,
+				Comment: "a lovely comment", CollectedBy: "john",
 			},
 			{
 				TeamNumber: 972, MatchNumber: 1,
@@ -240,8 +242,8 @@
 				AutoBallPickedUp: [5]bool{false, false, true, false, false},
 				ShotsMissed:      2, UpperGoalShots: 3, LowerGoalShots: 4,
 				ShotsMissedAuto: 5, UpperGoalAuto: 6, LowerGoalAuto: 7,
-				PlayedDefense: 8, Climbing: 4,
-				CollectedBy: "andrea",
+				PlayedDefense: 8, DefenseReceivedScore: 1, Climbing: 4,
+				Comment: "another lovely comment", CollectedBy: "andrea",
 			},
 		},
 	}
@@ -264,23 +266,27 @@
 				Team: 971, Match: 1,
 				MissedShotsAuto: 4, UpperGoalAuto: 5, LowerGoalAuto: 6,
 				MissedShotsTele: 1, UpperGoalTele: 2, LowerGoalTele: 3,
-				DefenseRating: 7,
-				CollectedBy:   "john",
-				AutoBall1:     true, AutoBall2: false, AutoBall3: false,
+				DefenseRating:         7,
+				DefenseReceivedRating: 3,
+				CollectedBy:           "john",
+				AutoBall1:             true, AutoBall2: false, AutoBall3: false,
 				AutoBall4: false, AutoBall5: true,
 				StartingQuadrant: 1,
 				ClimbLevel:       request_data_scouting_response.ClimbLevelFailedWithPlentyOfTime,
+				Comment:          "a lovely comment",
 			},
 			{
 				Team: 972, Match: 1,
 				MissedShotsAuto: 5, UpperGoalAuto: 6, LowerGoalAuto: 7,
 				MissedShotsTele: 2, UpperGoalTele: 3, LowerGoalTele: 4,
-				DefenseRating: 8,
-				CollectedBy:   "andrea",
-				AutoBall1:     false, AutoBall2: false, AutoBall3: true,
+				DefenseRating:         8,
+				DefenseReceivedRating: 1,
+				CollectedBy:           "andrea",
+				AutoBall1:             false, AutoBall2: false, AutoBall3: true,
 				AutoBall4: false, AutoBall5: false,
 				StartingQuadrant: 2,
 				ClimbLevel:       request_data_scouting_response.ClimbLevelMedium,
+				Comment:          "another lovely comment",
 			},
 		},
 	}
diff --git a/scouting/www/entry/entry.ng.html b/scouting/www/entry/entry.ng.html
index bc49bc6..722da67 100644
--- a/scouting/www/entry/entry.ng.html
+++ b/scouting/www/entry/entry.ng.html
@@ -86,7 +86,7 @@
         </form>
         <div class="row">
             <h4>Comments</h4>
-            <textarea [(ngModel)]="comment"></textarea>
+            <textarea [(ngModel)]="comment" id="comment"></textarea>
         </div>
         <div class="buttons">
           <button class="btn btn-primary" (click)="prevSection()">Back</button>
@@ -178,6 +178,7 @@
         <h4>Climb</h4>
         <ul>
             <li>Level: {{level | levelToString}}</li>
+            <li>Comments: {{comment}}</li>
         </ul>
 
         <h4>Other</h4>