@@ -158,60 +158,97 @@ private function get_csv_data() {
158158 $ row_num = 1 ;
159159 }
160160
161+ $ graded_reg_codes = STUDENT_REGISTERED_CODES ;
162+ $ audit_reg_codes = is_null (STUDENT_AUDIT_CODES ) ? array () : STUDENT_AUDIT_CODES ;
163+ $ latedrop_reg_codes = is_null (STUDENT_LATEDROP_CODES ) ? array () : STUDENT_LATEDROP_CODES ;
164+ $ all_valid_reg_codes = array_merge ($ graded_reg_codes , $ audit_reg_codes , $ latedrop_reg_codes );
165+ $ unexpected_term_codes = array ();
166+
161167 // Read and assign csv rows into $this->data array
162168 $ row = fgetcsv ($ this ->fh , 0 , CSV_DELIM_CHAR );
163169 while (!feof ($ this ->fh )) {
164- //Trim whitespace from all fields in $row
170+ // Course is comprised of an alphabetic prefix and a numeric suffix.
171+ $ course = strtolower ($ row [COLUMN_COURSE_PREFIX ] . $ row [COLUMN_COURSE_NUMBER ]);
172+
173+ // Trim whitespace from all fields in $row.
165174 array_walk ($ row , function (&$ val , $ key ) { $ val = trim ($ val ); });
166175
167176 // Remove any leading zeroes from "integer" registration sections.
168177 if (ctype_digit ($ row [COLUMN_SECTION ])) $ row [COLUMN_SECTION ] = ltrim ($ row [COLUMN_SECTION ], "0 " );
169178
170- $ course = strtolower ($ row [COLUMN_COURSE_PREFIX ] . $ row [COLUMN_COURSE_NUMBER ]);
179+ switch (true ) {
180+ // Check that $row has an appropriate student registration.
181+ case array_search ($ row [COLUMN_REGISTRATION ], $ all_valid_reg_codes ) === false :
182+ // Skip row.
183+ break ;
184+
185+ // Check that $row is associated with the current term (if check is enabled)
186+ // Assume this check is OK, when EXPECTED_TERM_CODE is null (check disabled)
187+ case is_null (EXPECTED_TERM_CODE ) ? false : $ row [COLUMN_TERM_CODE ] !== EXPECTED_TERM_CODE :
188+ // Note the unexpected term code for logging, if not already noted.
189+ if (array_search ($ row [COLUMN_TERM_CODE ], $ unexpected_term_codes ) === false ) {
190+ $ unexpected_term_codes [] = $ row [COLUMN_TERM_CODE ];
191+ }
192+ break ;
193+
194+ // Check that $row is associated with the course list.
195+ case array_search ($ course , $ this ->course_list ) !== false :
196+ if (validate::validate_row ($ row , $ row_num )) {
197+ // Include $row
198+ $ this ->data [$ course ][] = $ row ;
171199
172- // Does $row have a valid registration code?
173- $ graded_codes = STUDENT_REGISTERED_CODES ;
174- $ audit_codes = is_null (STUDENT_AUDIT_CODES ) ? array () : STUDENT_AUDIT_CODES ;
175- $ latedrop_codes = is_null (STUDENT_LATEDROP_CODES ) ? array () : STUDENT_LATEDROP_CODES ;
176- $ all_valid_codes = array_merge ($ graded_codes , $ audit_codes , $ latedrop_codes );
177- if (array_search ($ row [COLUMN_REGISTRATION ], $ all_valid_codes ) !== false ) {
178- // Check that $row is associated with the course list
179- if (array_search ($ course , $ this ->course_list ) !== false ) {
200+ // $row with a blank email is included, but it is also logged.
201+ if ($ row [COLUMN_EMAIL ] === "" ) {
202+ $ this ->log_it ("Blank email found for user {$ row [COLUMN_USER_ID ]}, row {$ row_num }. " );
203+ }
204+ } else {
205+ // There is a problem with $row, so log the problem and skip.
206+ $ this ->invalid_courses [$ course ] = true ;
207+ $ this ->log_it (validate::$ error );
208+ }
209+ break ;
210+
211+ // Check that the $row is associated with a mapped course.
212+ case array_key_exists ($ course , $ this ->mapped_courses ):
213+ // Also verify that the section is mapped.
214+ $ section = $ row [COLUMN_SECTION ];
215+ if (array_key_exists ($ section , $ this ->mapped_courses [$ course ])) {
216+ $ m_course = $ this ->mapped_courses [$ course ][$ section ]['mapped_course ' ];
180217 if (validate::validate_row ($ row , $ row_num )) {
181- $ this ->data [$ course ][] = $ row ;
182- // Rows with blank emails are allowed, but they are being logged.
218+ // Include $row.
219+ $ row [COLUMN_SECTION ] = $ this ->mapped_courses [$ course ][$ section ]['mapped_section ' ];
220+ $ this ->data [$ m_course ][] = $ row ;
221+
222+ // $row with a blank email is allowed, but it is also logged.
183223 if ($ row [COLUMN_EMAIL ] === "" ) {
184224 $ this ->log_it ("Blank email found for user {$ row [COLUMN_USER_ID ]}, row {$ row_num }. " );
185225 }
186226 } else {
187- $ this ->invalid_courses [$ course ] = true ;
227+ // There is a problem with $row, so log the problem and skip.
228+ $ this ->invalid_courses [$ m_course ] = true ;
188229 $ this ->log_it (validate::$ error );
189230 }
190- // Instead, check that the $row is associated with mapped course
191- } else if (array_key_exists ($ course , $ this ->mapped_courses )) {
192- $ section = $ row [COLUMN_SECTION ];
193- // Also verify that the section is mapped.
194- if (array_key_exists ($ section , $ this ->mapped_courses [$ course ])) {
195- $ m_course = $ this ->mapped_courses [$ course ][$ section ]['mapped_course ' ];
196- if (validate::validate_row ($ row , $ row_num )) {
197- $ row [COLUMN_SECTION ] = $ this ->mapped_courses [$ course ][$ section ]['mapped_section ' ];
198- $ this ->data [$ m_course ][] = $ row ;
199- // Rows with blank emails are allowed, but they are being logged.
200- if ($ row [COLUMN_EMAIL ] === "" ) {
201- $ this ->log_it ("Blank email found for user {$ row [COLUMN_USER_ID ]}, row {$ row_num }. " );
202- }
203- } else {
204- $ this ->invalid_courses [$ m_course ] = true ;
205- $ this ->log_it (validate::$ error );
206- }
207- }
208231 }
209- }
232+ break ;
233+
234+ default :
235+ // Skip row by default.
236+ break ;
237+
238+ } // END switch (true)
210239
211240 $ row = fgetcsv ($ this ->fh , 0 , CSV_DELIM_CHAR );
212241 $ row_num ++;
213242 }
214243
244+ // Log any unexpected term codes.
245+ // This may provide a notice that the next term's data is available.
246+ if (!empty ($ unexpected_term_codes )) {
247+ $ msg = "Unexpected term codes in CSV: " ;
248+ $ msg .= implode (", " , $ unexpected_term_codes );
249+ $ this ->log_it ($ msg );
250+ }
251+
215252 /* ---------------------------------------------------------------------
216253 There may be "fake" or "practice" courses in Submitty that shouldn't be
217254 altered by the autofeed. These courses will have no enrollments in the
@@ -262,6 +299,16 @@ private function check_for_duplicate_user_ids() {
262299 return true ;
263300 }
264301
302+ /**
303+ * An excessive ratio of dropped users may indicate bad data in the CSV.
304+ *
305+ * The confidence ratio is defined in config.php as VALIDATE_DROP_RATIO.
306+ * Confidence value is a float between 0 and 1.0.
307+ *
308+ * @see validate::check_for_excessive_dropped_users() Found in ssaf_validate.php
309+ *
310+ * @return bool True when check is within confidence ratio. False otherwise.
311+ */
265312 private function check_for_excessive_dropped_users () {
266313 $ is_validated = true ;
267314 $ invalid_courses = array (); // intentional local array
@@ -280,10 +327,10 @@ private function check_for_excessive_dropped_users() {
280327 array_unshift ($ invalid_courses , array ('course ' => "COURSE " , 'diff ' => "DIFF " , 'ratio ' => "RATIO " )); // Header
281328 foreach ($ invalid_courses as $ invalid_course ) {
282329 $ msg .= " " .
283- str_pad ($ invalid_course ['course ' ], 18 , " " , STR_PAD_RIGHT ) .
284- str_pad ($ invalid_course ['diff ' ], 6 , " " , STR_PAD_LEFT ) .
285- str_pad ($ invalid_course ['ratio ' ], 8 , " " , STR_PAD_LEFT ) .
286- PHP_EOL ;
330+ str_pad ($ invalid_course ['course ' ], 18 , " " , STR_PAD_RIGHT ) .
331+ str_pad ($ invalid_course ['diff ' ], 6 , " " , STR_PAD_LEFT ) .
332+ str_pad ($ invalid_course ['ratio ' ], 8 , " " , STR_PAD_LEFT ) .
333+ PHP_EOL ;
287334 }
288335 $ msg .= " No upsert performed on any/all courses in Submitty due to suspicious data sheet. " ;
289336
0 commit comments