Changeset 16012 for main


Ignore:
Timestamp:
24 Feb 2020, 21:26:35 (5 years ago)
Author:
Henrik Bettermann
Message:

Implement BatchProcessor.checkCreateRequirements and
BatchProcessor.checkUpdateRequirements methods mainly
to protect course result lists of graduated student.

Location:
main/waeup.kofa/trunk
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • main/waeup.kofa/trunk/CHANGES.txt

    r16007 r16012  
    441.6.1.dev0 (unreleased)
    55=======================
     6
     7* Implement `BatchProcessor.checkCreateRequirements` and
     8  `BatchProcessor.checkUpdateRequirements` methods mainly
     9  to protect course result lists of graduated student.
    610
    711* Do not allow course validation if no score has been entered.
  • main/waeup.kofa/trunk/src/waeup/kofa/students/batching.py

    r16000 r16012  
    621621        return
    622622
     623    def checkCreateRequirements(self, parent, row, site):
     624        """
     625        """
     626        if parent.student.studycourse_locked:
     627            return 'Studycourse is locked.'
     628        return None
     629
    623630    def checkUpdateRequirements(self, obj, row, site):
    624631        """
     
    626633        if obj.student.studycourse_locked:
    627634            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.'
    628642        return None
    629643
     
    736750        return
    737751
     752    def checkCreateRequirements(self, parent, row, site):
     753        """
     754        """
     755        if parent.student.studycourse_locked:
     756            return 'Studycourse is locked.'
     757        return None
     758
    738759    def checkUpdateRequirements(self, obj, row, site):
    739760        """
     
    744765            'unlock_score',None):
    745766            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.'
    746774        return None
    747775
  • main/waeup.kofa/trunk/src/waeup/kofa/students/tests/test_batching.py

    r16000 r16012  
    496496        num, num_warns, fin_file, fail_file = self.processor.doImport(
    497497            self.csv_file, STUDENT_HEADER_FIELDS)
    498         shutil.rmtree(os.path.dirname(fin_file))
    499498        self.assertRaises(
    500499            FatalCSVError, self.processor.doImport, self.csv_file_update4,
    501500            STUDENT_HEADER_FIELDS_UPDATE4, 'update')
     501        shutil.rmtree(os.path.dirname(fin_file))
    502502
    503503    def test_import_remove(self):
     
    891891            dict(reg_number='1', level='100'), self.app) is False
    892892        self.assertEqual(num_warns,3)
    893 
    894893        shutil.rmtree(os.path.dirname(fin_file))
    895894
     
    10091008        num, num_warns, fin_file, fail_file = self.processor.doImport(
    10101009            self.csv_file, COURSETICKET_HEADER_FIELDS,'create')
    1011         shutil.rmtree(os.path.dirname(fin_file))
    10121010        num, num_warns, fin_file, fail_file = self.processor.doImport(
    10131011            self.csv_file, COURSETICKET_HEADER_FIELDS,'update')
     
    10651063            '1,COURSE1,<IGNORE>,300,2008,<IGNORE>,6,<IGNORE>,<IGNORE>,level object: does not exist\r\n'
    10661064            '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            )
    10671120        shutil.rmtree(os.path.dirname(fin_file))
    10681121
     
    13741427            '... INFO - system - X666666 - Returned...',
    13751428            logcontent)
    1376 
    13771429        shutil.rmtree(os.path.dirname(fin_file))
    13781430
  • main/waeup.kofa/trunk/src/waeup/kofa/utils/batching.py

    r15065 r16012  
    196196        raise NotImplementedError('method not implemented')
    197197
     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
    198209    def checkUpdateRequirements(self, obj, row, site):
    199210        """Checks requirements the object must fulfill when being updated.
    200211
    201212        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.
    202224
    203225        Returns error messages as strings in case of requirement
     
    329351           record is stored in the pending data file.
    330352
     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
    331360           Now `doImport` tries to add the new object with the data
    332361           from the conversion dictionary. In some cases this
     
    359388           a ``no such entry`` warning message is raised and a record is
    360389           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.
    361397
    362398           Finally, `doImport` removes the existing object.
     
    425461                        "This object already exists.")
    426462                    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
    427470                obj = self.callFactory()
    428471                # Override all values in row, also
     
    453496                        failed_writer, string_row,
    454497                        "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)
    455505                    continue
    456506                self.delEntry(row, site)
Note: See TracChangeset for help on using the changeset viewer.