- Timestamp:
- 24 Feb 2020, 21:26:35 (5 years ago)
- Location:
- main/waeup.kofa/trunk
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
main/waeup.kofa/trunk/CHANGES.txt
r16007 r16012 4 4 1.6.1.dev0 (unreleased) 5 5 ======================= 6 7 * Implement `BatchProcessor.checkCreateRequirements` and 8 `BatchProcessor.checkUpdateRequirements` methods mainly 9 to protect course result lists of graduated student. 6 10 7 11 * Do not allow course validation if no score has been entered. -
main/waeup.kofa/trunk/src/waeup/kofa/students/batching.py
r16000 r16012 621 621 return 622 622 623 def checkCreateRequirements(self, parent, row, site): 624 """ 625 """ 626 if parent.student.studycourse_locked: 627 return 'Studycourse is locked.' 628 return None 629 623 630 def checkUpdateRequirements(self, obj, row, site): 624 631 """ … … 626 633 if obj.student.studycourse_locked: 627 634 return 'Studylevel is locked.' 635 return None 636 637 def checkRemoveRequirements(self, obj, row, site): 638 """ 639 """ 640 if obj.student.studycourse_locked: 641 return 'Studycourse is locked.' 628 642 return None 629 643 … … 736 750 return 737 751 752 def checkCreateRequirements(self, parent, row, site): 753 """ 754 """ 755 if parent.student.studycourse_locked: 756 return 'Studycourse is locked.' 757 return None 758 738 759 def checkUpdateRequirements(self, obj, row, site): 739 760 """ … … 744 765 'unlock_score',None): 745 766 return 'Score attribute is locked.' 767 return None 768 769 def checkRemoveRequirements(self, obj, row, site): 770 """ 771 """ 772 if obj.student.studycourse_locked: 773 return 'Studycourse is locked.' 746 774 return None 747 775 -
main/waeup.kofa/trunk/src/waeup/kofa/students/tests/test_batching.py
r16000 r16012 496 496 num, num_warns, fin_file, fail_file = self.processor.doImport( 497 497 self.csv_file, STUDENT_HEADER_FIELDS) 498 shutil.rmtree(os.path.dirname(fin_file))499 498 self.assertRaises( 500 499 FatalCSVError, self.processor.doImport, self.csv_file_update4, 501 500 STUDENT_HEADER_FIELDS_UPDATE4, 'update') 501 shutil.rmtree(os.path.dirname(fin_file)) 502 502 503 503 def test_import_remove(self): … … 891 891 dict(reg_number='1', level='100'), self.app) is False 892 892 self.assertEqual(num_warns,3) 893 894 893 shutil.rmtree(os.path.dirname(fin_file)) 895 894 … … 1009 1008 num, num_warns, fin_file, fail_file = self.processor.doImport( 1010 1009 self.csv_file, COURSETICKET_HEADER_FIELDS,'create') 1011 shutil.rmtree(os.path.dirname(fin_file))1012 1010 num, num_warns, fin_file, fail_file = self.processor.doImport( 1013 1011 self.csv_file, COURSETICKET_HEADER_FIELDS,'update') … … 1065 1063 '1,COURSE1,<IGNORE>,300,2008,<IGNORE>,6,<IGNORE>,<IGNORE>,level object: does not exist\r\n' 1066 1064 '1,COURSE1,<IGNORE>,300,2008X,<IGNORE>,6,<IGNORE>,<IGNORE>,level_session: Invalid value\r\n') 1065 shutil.rmtree(os.path.dirname(fin_file)) 1066 1067 def test_import_create_locked(self): 1068 # In state 'transcript validated' course tickets can't be created 1069 student = self.app['students']['X666666'] 1070 IWorkflowState(student).setState('transcript validated') 1071 num, num_warns, fin_file, fail_file = self.processor.doImport( 1072 self.csv_file, COURSETICKET_HEADER_FIELDS,'create') 1073 fail_file = open(fail_file).read() 1074 self.assertEqual(num_warns,7) 1075 self.assertEqual(fail_file, 1076 'reg_number,code,mandatory,level,level_session,ticket_session,score,unlock_score,matric_number,--ERRORS--\r\n' 1077 '1,COURSE1,True,100,<IGNORE>,<IGNORE>,1,<IGNORE>,<IGNORE>,Studycourse is locked.\r\n' 1078 '1,COURSE1,True,200,2008,<IGNORE>,1,<IGNORE>,<IGNORE>,Studycourse is locked.\r\n' 1079 '1,COURSE1,<IGNORE>,nonsense,<IGNORE>,<IGNORE>,5,<IGNORE>,<IGNORE>,Not all parents do exist yet.\r\n' 1080 '1,NONSENSE,<IGNORE>,100,<IGNORE>,<IGNORE>,5,<IGNORE>,<IGNORE>,code: non-existent\r\n' 1081 '1,COURSE1,<IGNORE>,200,2004,<IGNORE>,6,<IGNORE>,<IGNORE>,level_session: does not match 2008\r\n' 1082 '1,COURSE1,<IGNORE>,300,2008,<IGNORE>,6,<IGNORE>,<IGNORE>,level object: does not exist\r\n' 1083 '1,COURSE1,<IGNORE>,300,2008X,<IGNORE>,6,<IGNORE>,<IGNORE>,level_session: Invalid value\r\n') 1084 self.assertFalse(self.processor.entryExists( 1085 dict(reg_number='1', level='100', code='COURSE1'), 1086 self.app)) 1087 shutil.rmtree(os.path.dirname(fin_file)) 1088 1089 def test_import_remove_locked(self): 1090 # We perform the same import twice, 1091 # the second time in remove mode. 1092 num, num_warns, fin_file, fail_file = self.processor.doImport( 1093 self.csv_file, COURSETICKET_HEADER_FIELDS,'create') 1094 shutil.rmtree(os.path.dirname(fin_file)) 1095 assert self.processor.entryExists( 1096 dict(reg_number='1', level='100', code='COURSE1'), self.app) is True 1097 # In state 'transcript validated' course tickets can't be removed 1098 student = self.app['students']['X666666'] 1099 IWorkflowState(student).setState('transcript validated') 1100 num, num_warns, fin_file, fail_file = self.processor.doImport( 1101 self.csv_file, COURSETICKET_HEADER_FIELDS,'remove') 1102 self.assertEqual(num_warns,7) 1103 assert self.processor.entryExists( 1104 dict(reg_number='1', level='100', code='COURSE1'), self.app) is True 1105 logcontent = open(self.logfile).read() 1106 self.assertFalse( 1107 'INFO - system - X666666 - Course ticket in 100 removed: COURSE1' 1108 in logcontent) 1109 fail_file = open(fail_file).read() 1110 self.assertEqual(fail_file, 1111 'reg_number,code,matric_number,level,--ERRORS--\r\n' 1112 '1,COURSE1,<IGNORE>,100,Studycourse is locked.\r\n' 1113 '1,COURSE1,<IGNORE>,200,Studycourse is locked.\r\n' 1114 '1,COURSE1,<IGNORE>,nonsense,Cannot remove: no such entry\r\n' 1115 '1,NONSENSE,<IGNORE>,100,Cannot remove: no such entry\r\n' 1116 '1,COURSE1,<IGNORE>,200,Studycourse is locked.\r\n' 1117 '1,COURSE1,<IGNORE>,300,Cannot remove: no such entry\r\n' 1118 '1,COURSE1,<IGNORE>,300,Cannot remove: no such entry\r\n' 1119 ) 1067 1120 shutil.rmtree(os.path.dirname(fin_file)) 1068 1121 … … 1374 1427 '... INFO - system - X666666 - Returned...', 1375 1428 logcontent) 1376 1377 1429 shutil.rmtree(os.path.dirname(fin_file)) 1378 1430 -
main/waeup.kofa/trunk/src/waeup/kofa/utils/batching.py
r15065 r16012 196 196 raise NotImplementedError('method not implemented') 197 197 198 def checkCreateRequirements(self, parent, row, site): 199 """Checks requirements the parent object must fulfill when 200 a new subobject is being created. 201 202 This method is not used in case of updating or removing objects. 203 204 Returns error messages as strings in case of requirement 205 problems. 206 """ 207 return None 208 198 209 def checkUpdateRequirements(self, obj, row, site): 199 210 """Checks requirements the object must fulfill when being updated. 200 211 201 212 This method is not used in case of deleting or adding objects. 213 214 Returns error messages as strings in case of requirement 215 problems. 216 """ 217 return None 218 219 220 def checkRemoveRequirements(self, obj, row, site): 221 """Checks requirements the object must fulfill when being removed. 222 223 This method is not used in case of updating or adding objects. 202 224 203 225 Returns error messages as strings in case of requirement … … 329 351 record is stored in the pending data file. 330 352 353 The `BatchProcessor.checkCreateRequirements` method checks additional 354 requirements the parent object must fulfill before a new sububject 355 is being added. These requirements are not imposed by the data 356 type but the context of the object. For example, the course results 357 of graduated students must not changed by import, neither by 358 creating nor updating or removing course tickets. 359 331 360 Now `doImport` tries to add the new object with the data 332 361 from the conversion dictionary. In some cases this … … 359 388 a ``no such entry`` warning message is raised and a record is 360 389 stored in the pending data file. 390 391 The `BatchProcessor.checkRemoveRequirements` method checks additional 392 requirements the object must fulfill before being removed. 393 These requirements are not imposed by the data type but the context 394 of the object. For example, the course results of graduated students 395 must not changed by import, neither by creating nor updating or 396 removing course tickets. 361 397 362 398 Finally, `doImport` removes the existing object. … … 425 461 "This object already exists.") 426 462 continue 463 parent = self.getParent(row, site) 464 create_errors = self.checkCreateRequirements(parent, row, site) 465 if create_errors is not None: 466 num_warns += 1 467 self.writeFailedRow( 468 failed_writer, string_row, create_errors) 469 continue 427 470 obj = self.callFactory() 428 471 # Override all values in row, also … … 453 496 failed_writer, string_row, 454 497 "Cannot remove: no such entry") 498 continue 499 obj = self.getEntry(row, site) 500 remove_errors = self.checkRemoveRequirements(obj, row, site) 501 if remove_errors is not None: 502 num_warns += 1 503 self.writeFailedRow( 504 failed_writer, string_row, remove_errors) 455 505 continue 456 506 self.delEntry(row, site)
Note: See TracChangeset for help on using the changeset viewer.