Changeset 7263
- Timestamp:
- 4 Dec 2011, 12:59:40 (13 years ago)
- Location:
- main/waeup.sirp/trunk/src/waeup/sirp
- Files:
-
- 2 added
- 8 edited
Legend:
- Unmodified
- Added
- Removed
-
main/waeup.sirp/trunk/src/waeup/sirp/applicants/batching.py
r7262 r7263 66 66 return 67 67 68 class Applicant Processor(BatchProcessor):68 class ApplicantImporter(BatchProcessor): 69 69 """A batch processor for IApplicant objects. 70 70 """ … … 118 118 def delEntry(self, row, site): 119 119 applicant = self.entryExists(row, site) 120 if applicant :120 if applicant is not None: 121 121 parent = self.getParent(row, site) 122 122 del parent[row['application_number']] -
main/waeup.sirp/trunk/src/waeup/sirp/applicants/browser.py
r7260 r7263 931 931 form_fields = grok.AutoFields(IApplicantEdit).omit( 932 932 'locked', 'course_admitted', 'student_id', 933 'screening_score', 'applicant_id' 933 'screening_score', 'applicant_id', 'reg_no' 934 934 ) 935 935 form_fields['date_of_birth'].custom_widget = FriendlyDateWidget('le-year') -
main/waeup.sirp/trunk/src/waeup/sirp/applicants/interfaces.py
r7262 r7263 22 22 23 23 from zope import schema 24 from zope.interface import Interface, Attribute 25 from zope.component import getUtilitiesFor 24 from zope.interface import Interface, Attribute, implements, directlyProvides 25 from zope.component import getUtilitiesFor, queryUtility 26 from zope.catalog.interfaces import ICatalog 27 from zope.schema.interfaces import ValidationError, ISource, IContextSourceBinder 26 28 from zc.sourcefactory.basic import BasicSourceFactory 29 from waeup.sirp.schema import TextLineChoice 27 30 from waeup.sirp.interfaces import ( 28 31 IWAeUPObject, year_range, validate_email, academic_sessions_vocab) … … 40 43 MAX_UPLOAD_SIZE = 1024 * 20 41 44 45 class RegNumInSource(ValidationError): 46 """Registration number exists already 47 """ 48 # The docstring of ValidationErrors is used as error description 49 # by zope.formlib. 50 pass 51 52 class RegNumberSource(object): 53 implements(ISource) 54 cat_name = 'applicants_catalog' 55 field_name = 'reg_no' 56 validation_error = RegNumInSource 57 def __init__(self, context): 58 self.context = context 59 return 60 61 def __contains__(self, value): 62 cat = queryUtility(ICatalog, self.cat_name) 63 if cat is None: 64 return True 65 kw = {self.field_name: (value, value)} 66 results = cat.searchResults(**kw) 67 for entry in results: 68 if entry.applicant_id != self.context.applicant_id: 69 # XXX: sources should simply return False. 70 # But then we get some stupid error message in forms 71 # when validation fails. 72 raise self.validation_error(value) 73 #return False 74 return True 75 76 def contextual_reg_num_source(context): 77 source = RegNumberSource(context) 78 return source 79 directlyProvides(contextual_reg_num_source, IContextSourceBinder) 80 42 81 class ApplicantContainerProviderSource(BasicSourceFactory): 43 82 """A source offering all available applicants container types. … … 259 298 readonly = False, 260 299 ) 261 reg_no = schema.TextLine(300 reg_no = TextLineChoice( 262 301 title = u'JAMB Registration Number', 263 readonly = True, 264 required = False, 302 readonly = False, 303 required = True, 304 default = None, 305 source = contextual_reg_num_source, 265 306 ) 266 307 access_code = schema.TextLine( -
main/waeup.sirp/trunk/src/waeup/sirp/applicants/tests/test_batching.py
r7193 r7263 23 23 import unittest 24 24 from zope.component.hooks import setSite, clearSite 25 from zope.component import createObject 25 26 from zope.interface.verify import verifyClass, verifyObject 26 27 27 28 from waeup.sirp.app import University 28 from waeup.sirp.applicants.batching import ApplicantsContainerImporter 29 from waeup.sirp.applicants.batching import ( 30 ApplicantsContainerImporter, ApplicantImporter) 29 31 from waeup.sirp.applicants.container import ApplicantsContainer 32 from waeup.sirp.applicants.applicant import Applicant 33 from waeup.sirp.university.faculty import Faculty 34 from waeup.sirp.university.department import Department 30 35 from waeup.sirp.testing import FunctionalLayer, FunctionalTestCase 31 36 from waeup.sirp.interfaces import IBatchProcessor … … 39 44 # The header fields of the above CSV snippet 40 45 APPS_CONTAINER_HEADER_FIELDS = APPS_CONTAINER_SAMPLE_DATA.split( 46 '\n')[0].split(',') 47 48 # The same for students 49 APPLICANT_SAMPLE_DATA = open( 50 os.path.join(os.path.dirname(__file__), 'sample_applicant_data.csv'), 51 'rb').read() 52 53 APPLICANT_HEADER_FIELDS = APPLICANT_SAMPLE_DATA.split( 54 '\n')[0].split(',') 55 56 APPLICANT_SAMPLE_DATA_UPDATE = open( 57 os.path.join(os.path.dirname(__file__), 'sample_applicant_data_update.csv'), 58 'rb').read() 59 60 APPLICANT_HEADER_FIELDS_UPDATE = APPLICANT_SAMPLE_DATA_UPDATE.split( 41 61 '\n')[0].split(',') 42 62 … … 119 139 shutil.rmtree(os.path.dirname(fin_file)) 120 140 121 def test_suite(): 122 suite = unittest.TestSuite() 123 for testcase in [ 124 ApplicantsContainerImporterTest, 125 ]: 126 suite.addTest(unittest.TestLoader().loadTestsFromTestCase( 127 testcase 128 ) 129 ) 130 return suite 141 class ApplicantImporterTest(FunctionalTestCase): 142 143 layer = FunctionalLayer 144 145 def setUp(self): 146 super(ApplicantImporterTest, self).setUp() 147 # Setup a sample site for each test 148 app = University() 149 self.dc_root = tempfile.mkdtemp() 150 app['datacenter'].setStoragePath(self.dc_root) 151 152 # Prepopulate the ZODB... 153 self.getRootFolder()['app'] = app 154 # we add the site immediately after creation to the 155 # ZODB. Catalogs and other local utilities are not setup 156 # before that step. 157 self.app = self.getRootFolder()['app'] 158 # Set site here. Some of the following setup code might need 159 # to access grok.getSite() and should get our new app then 160 setSite(app) 161 162 # Add an applicants container 163 self.container = ApplicantsContainer() 164 self.container.code = u'dp2011' 165 self.app['applicants']['dp2011'] = self.container 166 167 # Populate university 168 self.certificate = createObject('waeup.Certificate') 169 self.certificate.code = 'CERT1' 170 self.certificate.application_category = 'basic' 171 self.certificate.start_level = 100 172 self.certificate.end_level = 500 173 self.app['faculties']['fac1'] = Faculty() 174 self.app['faculties']['fac1']['dep1'] = Department() 175 self.app['faculties']['fac1']['dep1'].certificates.addCertificate( 176 self.certificate) 177 178 # Add applicant with subobjects 179 applicant = Applicant() 180 applicant.firstname = u'Anna' 181 applicant.firstname = u'Tester' 182 self.app['applicants']['dp2011'].addApplicant(applicant) 183 self.application_number = applicant.application_number 184 self.applicant = self.app['applicants']['dp2011'][ 185 self.application_number] 186 self.importer = ApplicantImporter() 187 self.workdir = tempfile.mkdtemp() 188 self.csv_file = os.path.join(self.workdir, 'sample_applicant_data.csv') 189 self.csv_file_update = os.path.join( 190 self.workdir, 'sample_applicant_data_update.csv') 191 open(self.csv_file, 'wb').write(APPLICANT_SAMPLE_DATA) 192 open(self.csv_file_update, 'wb').write(APPLICANT_SAMPLE_DATA_UPDATE) 193 194 def tearDown(self): 195 super(ApplicantImporterTest, self).tearDown() 196 shutil.rmtree(self.workdir) 197 shutil.rmtree(self.dc_root) 198 clearSite() 199 return 200 201 def test_interface(self): 202 # Make sure we fulfill the interface contracts. 203 assert verifyObject(IBatchProcessor, self.importer) is True 204 assert verifyClass( 205 IBatchProcessor, ApplicantImporter) is True 206 207 def test_entryExists(self): 208 assert self.importer.entryExists( 209 dict(container_code='dp2011', application_number='999'), 210 self.app) is None 211 212 def test_getEntry(self): 213 applicant = self.importer.getEntry( 214 dict(container_code='dp2011', 215 application_number=self.application_number), self.app) 216 self.assertEqual(applicant.applicant_id, self.applicant.applicant_id) 217 218 def test_addEntry(self): 219 new_applicant = Applicant() 220 self.importer.addEntry( 221 new_applicant, dict(container_code='dp2011'), self.app) 222 assert len(self.app['applicants']['dp2011'].keys()) == 2 223 224 def test_delEntry(self): 225 assert self.application_number in self.app['applicants']['dp2011'].keys() 226 self.importer.delEntry( 227 dict(container_code='dp2011', 228 application_number=self.application_number), self.app) 229 assert self.application_number not in self.app['applicants']['dp2011'].keys() 230 231 def test_import(self): 232 num, num_warns, fin_file, fail_file = self.importer.doImport( 233 self.csv_file, APPLICANT_HEADER_FIELDS) 234 self.assertEqual(num_warns,0) 235 assert len(self.app['applicants']['dp2011'].keys()) == 4 236 shutil.rmtree(os.path.dirname(fin_file)) 237 238 def test_import_update(self): 239 num, num_warns, fin_file, fail_file = self.importer.doImport( 240 self.csv_file, APPLICANT_HEADER_FIELDS) 241 shutil.rmtree(os.path.dirname(fin_file)) 242 num, num_warns, fin_file, fail_file = self.importer.doImport( 243 self.csv_file_update, APPLICANT_HEADER_FIELDS_UPDATE, 'update') 244 self.assertEqual(num_warns,0) 245 shutil.rmtree(os.path.dirname(fin_file)) 246 247 def test_import_remove(self): 248 num, num_warns, fin_file, fail_file = self.importer.doImport( 249 self.csv_file, APPLICANT_HEADER_FIELDS) 250 shutil.rmtree(os.path.dirname(fin_file)) 251 num, num_warns, fin_file, fail_file = self.importer.doImport( 252 self.csv_file_update, APPLICANT_HEADER_FIELDS_UPDATE, 'remove') 253 self.assertEqual(num_warns,0) 254 shutil.rmtree(os.path.dirname(fin_file)) 255 -
main/waeup.sirp/trunk/src/waeup/sirp/applicants/tests/test_browser.py
r7260 r7263 118 118 # Add an applicant 119 119 self.applicant = Applicant() 120 # reg_no is the only field which has to be preset here 121 # because managers are allowed to edit this required field 122 self.applicant.reg_no = u'1234' 120 123 app['applicants']['app2009'].addApplicant(self.applicant) 121 124 IUserAccount( -
main/waeup.sirp/trunk/src/waeup/sirp/schema/field.py
r7196 r7263 57 57 or u'bar'. 58 58 59 The main ad avantage of this modified TextLine field is to support59 The main advantage of this modified TextLine field is to support 60 60 contextual sources. That means you can define some 61 61 IContextSourceBinder component that looks up catalogs or something -
main/waeup.sirp/trunk/src/waeup/sirp/students/batching.py
r7261 r7263 130 130 def delEntry(self, row, site): 131 131 student = self.entryExists(row, site) 132 if student :132 if student is not None: 133 133 parent = self.getParent(row, site) 134 134 del parent[student.student_id] -
main/waeup.sirp/trunk/src/waeup/sirp/students/tests/test_batching.py
r7256 r7263 54 54 55 55 STUDENT_HEADER_FIELDS_UPDATE2 = STUDENT_SAMPLE_DATA_UPDATE2.split( 56 '\n')[0].split(',')57 58 STUDENT_SAMPLE_DATA = open(59 os.path.join(os.path.dirname(__file__), 'sample_student_data.csv'),60 'rb').read()61 62 STUDENT_HEADER_FIELDS = STUDENT_SAMPLE_DATA.split(63 56 '\n')[0].split(',') 64 57
Note: See TracChangeset for help on using the changeset viewer.