Changeset 11947 for main/waeup.kofa/branches/henrik-regista
- Timestamp:
- 13 Nov 2014, 13:21:59 (10 years ago)
- Location:
- main/waeup.kofa/branches/henrik-regista/src/waeup/kofa
- Files:
-
- 21 deleted
- 33 edited
Legend:
- Unmodified
- Added
- Removed
-
main/waeup.kofa/branches/henrik-regista/src/waeup/kofa/app.py
r11477 r11947 51 51 """Setup some hard-wired components. 52 52 53 Create local datacenter, containers for users , studentsand53 Create local datacenter, containers for users and 54 54 the like. 55 55 """ 56 from waeup.kofa.students.container import StudentsContainer57 from waeup.kofa.hostels.container import HostelsContainer58 56 59 57 self['users'] = UsersContainer() 60 58 self['datacenter'] = DataCenter() 61 self['students'] = StudentsContainer()62 59 self['configuration'] = ConfigurationContainer() 63 self['hostels'] = HostelsContainer()64 60 self['mandates'] = MandatesContainer() 65 61 self._createPlugins() -
main/waeup.kofa/branches/henrik-regista/src/waeup/kofa/app.txt
r7819 r11947 58 58 u'Sample University' 59 59 60 >>> myuniversity['faculties']61 <waeup.kofa.university.facultiescontainer.FacultiesContainer object at 0x...>62 63 >>> myuniversity['students']64 <waeup.kofa.students.container.StudentsContainer object at 0x...>65 66 60 >>> myuniversity['users'] 67 61 <waeup.kofa.userscontainer.UsersContainer object at 0x...> … … 73 67 <waeup.kofa.configuration.ConfigurationContainer object at 0x...> 74 68 75 We can export universities. For this we lookup an appropriate exporter76 first::77 78 >>> from waeup.kofa.interfaces import IKofaExporter79 >>> exporter = IKofaExporter(myuniversity)80 >>> exporter81 <waeup.kofa.utils.importexport.Exporter object at 0x...>82 83 Now we can trigger the export::84 85 >>> exporter.export()86 <cStringIO.StringO object at 0x...>87 88 We can also get an XML representation as file. If we do not provide a89 filepath, we will get an instance of `cStringIO.StringIO`, i.e. a90 memory file::91 92 >>> from waeup.kofa.interfaces import IKofaXMLExporter93 >>> exporter = IKofaXMLExporter(myuniversity)94 >>> f = exporter.export()95 >>> f96 <cStringIO.StringO object at 0x...>97 98 >>> print f.read()99 <?xml version="1.0" encoding="utf-8" ?>100 <pickle>101 <initialized_object id="...">102 ...103 </pickle>104 69 105 70 Kofa plugins … … 116 81 >>> from zope.component import getAdapters, getUtilitiesFor 117 82 >>> sorted(list(getUtilitiesFor(IKofaPluggable))) 118 [(u' accesscodes', <waeup.kofa.accesscodes...AccessCodePlugin ...)]83 [(u'mandates', <waeup.kofa.mandates.container.MandatesPlugin ...)] 119 84 120 85 -
main/waeup.kofa/branches/henrik-regista/src/waeup/kofa/authentication.py
r10055 r11947 388 388 def handle_account_added(account, event): 389 389 """When an account is added, the local owner role and the global 390 AcademicsOfficer role must be set.390 ProductsOfficer role must be set. 391 391 """ 392 392 # We set the local Owner role … … 394 394 role_manager_account.assignRoleToPrincipal( 395 395 'waeup.local.Owner', account.name) 396 # We set the global AcademicsOfficer role396 # We set the global ProductsOfficer role 397 397 site = grok.getSite() 398 398 role_manager_site = IPrincipalRoleManager(site) 399 399 role_manager_site.assignRoleToPrincipal( 400 'waeup. AcademicsOfficer', account.name)400 'waeup.ProductsOfficer', account.name) 401 401 # Finally we have to notify the user account that the local role 402 402 # of the same object has changed -
main/waeup.kofa/branches/henrik-regista/src/waeup/kofa/authentication.txt
r9308 r11947 51 51 {'waeup.local.Owner': [<waeup.kofa.authentication.Account object at 0x...>]} 52 52 53 User automatically get the global AcademicsOfficer role:53 User automatically get the global ProductsOfficer role: 54 54 55 55 >>> alice.getSiteRolesForPrincipal() 56 ['waeup.ManageDataCenter', 'waeup. AcademicsOfficer']56 ['waeup.ManageDataCenter', 'waeup.ProductsOfficer'] 57 57 58 58 We can tell an account, that Alice got some role for another object: … … 88 88 stored objects are removed. Furthermore this subscriber reads the 89 89 internal local roles table. 90 91 We create a faculty and grant Bob a local role:92 93 >>> from zope.securitypolicy.interfaces import IPrincipalRoleManager94 >>> from waeup.kofa.university.faculty import Faculty95 >>> faculty = Faculty()96 >>> root['app']['bobs_fac'] = faculty97 >>> role_manager = IPrincipalRoleManager(faculty)98 >>> role_manager.assignRoleToPrincipal(99 ... 'waeup.PortalManager', 'bob')100 101 We notify the machinery about that fact:102 103 >>> notify(LocalRoleSetEvent(faculty, 'waeup.PortalManager', 'bob',104 ... granted=True))105 >>> bob = root['app']['users']['bob']106 >>> bob.getLocalRoles()107 {'waeup.PortalManager': [<waeup.kofa...Faculty object at 0x...>]}108 109 When we delete the faculty from ZODB, also Bobs roles are modified:110 111 >>> del root['app']['bobs_fac']112 >>> bob.getLocalRoles()113 {'waeup.local.Owner': [<waeup.kofa.authentication.Account object at 0x...>]}114 115 If one notifies the machinery of a local role removal for an object116 that cannot have local roles, this will cause no trouble:117 118 >>> mycontext = None #object()119 >>> notify(LocalRoleSetEvent(120 ... mycontext, 'waeup.PortalManager', 'bob', granted=False121 ... )) is None122 True123 124 When an account get deleted, also the local roles of the owner get125 removed. Let's setup a local role for `alice`:126 127 >>> faculty = Faculty()128 >>> root['app']['alice_fac'] = faculty129 >>> role_manager = IPrincipalRoleManager(faculty)130 >>> role_manager.assignRoleToPrincipal(131 ... 'waeup.PortalManager', 'alice')132 >>> notify(LocalRoleSetEvent(faculty, 'waeup.PortalManager', 'alice',133 ... granted=True))134 135 The local role is set now:136 137 >>> from zope.securitypolicy.interfaces import IPrincipalRoleMap138 >>> IPrincipalRoleMap(faculty).getPrincipalsAndRoles()139 [('waeup.PortalManager', 'alice', PermissionSetting: Allow)]140 141 But when we delete Alices account from ZODB:142 143 >>> del root['app']['users']['alice']144 >>> IPrincipalRoleMap(faculty).getPrincipalsAndRoles()145 []146 147 the local role has gone and also the site roles have been removed:148 149 >>> prm = IPrincipalRoleManager(root['app'])150 >>> [x[0] for x in prm.getRolesForPrincipal('alice')151 ... if x[0].startswith('waeup.')]152 []153 90 154 91 -
main/waeup.kofa/branches/henrik-regista/src/waeup/kofa/browser/batchprocessing.txt
r11699 r11947 58 58 59 59 60 Batch processing faculties61 ==========================62 63 Go to datacenter page:64 65 >>> browser.open('http://localhost/app/datacenter')66 67 Prepare a CSV file for faculties (extended ascii values are accepted):68 69 >>> open('faculties.csv', 'wb').write(70 ... """code,title,title_prefix71 ... FAC1,Faculty 1,faculty72 ... FAC2,Faculty 2,institute73 ... FAC3,Fäcülty 3,school74 ... """)75 76 Upload the file:77 78 >>> import cStringIO79 >>> browser.getLink('Upload data').click()80 >>> filecontents = cStringIO.StringIO(81 ... open('faculties.csv', 'rb').read())82 >>> filewidget = browser.getControl(name='uploadfile:file')83 >>> filewidget.add_file(filecontents, 'text/plain', 'faculties.csv')84 >>> browser.getControl(name='SUBMIT').click()85 86 Step 1: start batch processing:87 88 >>> browser.getLink('Process data').click()89 >>> button = lookup_submit_value(90 ... 'select', 'faculties_zope.mgr.csv', browser)91 >>> button.click()92 93 Step 2: select a processor and mode:94 95 >>> importerselect = browser.getControl(name='importer')96 >>> importerselect.displayOptions97 ['AccessCodeBatch Processor', 'AccessCode Processor',98 'Applicant Processor', 'ApplicantsContainer Processor',99 'CertificateCourse Processor', 'Certificate Processor',100 'Course Processor',101 'CourseTicket Processor',102 'Department Processor', 'Faculty Processor',103 'Hostel Processor',104 'StudentOnlinePayment Processor', 'Student Processor',105 'StudentStudyCourse Processor (update only)',106 'StudentStudyLevel Processor',107 'User Processor',108 'Verdict Processor (special processor, update only)']109 110 >>> importerselect.getControl('Faculty Processor').selected = True111 112 >>> modeselect = browser.getControl(name='mode')113 >>> modeselect.options114 ['create', 'update', 'remove']115 116 >>> modeselect.getControl(value='create').selected = True117 >>> browser.getControl('Proceed to step 3').click()118 119 Step 3: Fix headerlines120 121 We get informed that there are no problems with the current header:122 123 >>> print browser.contents124 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"125 ...126 Header fields OK127 ...128 129 The submit button is enabled:130 131 >>> browser.getControl('Perform import').disabled132 False133 134 >>> browser.getControl('Perform import').click()135 136 Step 4: See import results137 138 The import was successful:139 140 >>> print browser.contents141 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"142 ...Successfully processed 3 rows...143 ...Batch processing finished...144 ...File:...faculties_zope.mgr.csv...145 146 We can grep the entries generated in logfile:147 148 >>> browser.open('http://localhost/app/datacenter/logs')149 >>> browser.getControl('Show', index=0).click()150 >>> print browser.contents151 <!DOCTYPE ...152 ...<h1 class="kofa-content-label">Logfile datacenter.log</h1>...153 154 >>> browser.getControl(name='query').value = "zope.mgr"155 >>> browser.getControl('Search').click()156 >>> 'zope.mgr - processed' in browser.contents157 True158 159 160 Batch processing departments161 ============================162 163 >>> browser.open('http://localhost/app/datacenter')164 165 Prepare a CSV file for departments:166 167 >>> open('departments.csv', 'wb').write(168 ... """code,faculty_code,title,title_prefix169 ... DEP1,FAC1,Department 1,department170 ... DEP2,FAC2,Department 2,centre171 ... """)172 173 Upload the file:174 175 >>> import cStringIO176 >>> browser.getLink('Upload data').click()177 >>> filecontents = cStringIO.StringIO(178 ... open('departments.csv', 'rb').read())179 >>> filewidget = browser.getControl(name='uploadfile:file')180 >>> filewidget.add_file(filecontents, 'text/plain', 'departments.csv')181 >>> browser.getControl(name='SUBMIT').click()182 183 Step 1: start batch processing:184 185 >>> browser.getLink('Process data').click()186 >>> button = lookup_submit_value(187 ... 'select', 'departments_zope.mgr.csv', browser)188 >>> button.click()189 190 Step 2: select a processor and mode:191 192 >>> importerselect = browser.getControl(name='importer')193 >>> importerselect.getControl('Department Processor').selected = True194 >>> modeselect = browser.getControl(name='mode')195 >>> modeselect.getControl(value='create').selected = True196 >>> browser.getControl('Proceed to step 3').click()197 198 Step 3: Fix headerlines199 200 We get informed that there are no problems with the current header:201 202 >>> print browser.contents203 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"204 ...205 Header fields OK206 ...207 208 The submit button is enabled:209 210 >>> browser.getControl('Perform import').disabled211 False212 213 >>> browser.getControl('Perform import').click()214 215 Step 4: See import results216 217 The import was successful:218 219 >>> print browser.contents220 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"221 ...Successfully processed 2 rows...222 ...Batch processing finished...223 ...File:...departments_zope.mgr.csv...224 225 Batch processing courses226 ========================227 228 >>> browser.open('http://localhost/app/datacenter')229 230 Prepare a CSV file for courses:231 232 >>> open('courses.csv', 'wb').write(233 ... """code,faculty_code,department_code,title,level,passmark,credits,semester234 ... CRS1,FAC1,DEP1,Course 1,100,40,2,1235 ... CRS2,FAC1,DEP1,Course 2,100,40,2,2236 ... """)237 238 Upload the file:239 240 >>> import cStringIO241 >>> browser.getLink('Upload data').click()242 >>> filecontents = cStringIO.StringIO(243 ... open('courses.csv', 'rb').read())244 >>> filewidget = browser.getControl(name='uploadfile:file')245 >>> filewidget.add_file(filecontents, 'text/plain', 'courses.csv')246 >>> browser.getControl(name='SUBMIT').click()247 248 Step 1: start batch processing:249 250 >>> browser.getLink('Process data').click()251 >>> button = lookup_submit_value(252 ... 'select', 'courses_zope.mgr.csv', browser)253 >>> button.click()254 255 Step 2: select a processor and mode:256 257 >>> importerselect = browser.getControl(name='importer')258 >>> importerselect.getControl('Course Processor', index=1).selected = True259 >>> modeselect = browser.getControl(name='mode')260 >>> modeselect.getControl(value='create').selected = True261 >>> browser.getControl('Proceed to step 3').click()262 263 Step 3: Fix headerlines264 265 We get informed that there are no problems with the current header:266 267 >>> print browser.contents268 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"269 ...270 Header fields OK271 ...272 273 The submit button is enabled:274 275 >>> browser.getControl('Perform import').disabled276 False277 278 >>> browser.getControl('Perform import').click()279 280 Step 4: See import results281 282 The import was successful:283 284 >>> print browser.contents285 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"286 ...Successfully processed 2 rows...287 ...Batch processing finished...288 ...File:...courses_zope.mgr.csv...289 290 Batch processing certificates291 =============================292 293 >>> browser.open('http://localhost/app/datacenter')294 295 Prepare a CSV file for certificates:296 297 >>> open('certificates.csv', 'wb').write(298 ... """code,faculty_code,department_code,title,study_mode,start_level,end_level,application_category299 ... CERT1,FAC1,DEP1,Certificate 1,pg_ft,999,999,basic300 ... CERT2,FAC1,DEP1,Certificate 2,ug_ft,200,300,cest301 ... """)302 303 Upload the file:304 305 >>> import cStringIO306 >>> browser.getLink('Upload data').click()307 >>> filecontents = cStringIO.StringIO(308 ... open('certificates.csv', 'rb').read())309 >>> filewidget = browser.getControl(name='uploadfile:file')310 >>> filewidget.add_file(filecontents, 'text/plain', 'certificates.csv')311 >>> browser.getControl(name='SUBMIT').click()312 313 Step 1: start batch processing:314 315 >>> browser.getLink('Process data').click()316 >>> button = lookup_submit_value(317 ... 'select', 'certificates_zope.mgr.csv', browser)318 >>> button.click()319 320 321 Step 2: select a processor and mode:322 323 >>> importerselect = browser.getControl(name='importer')324 >>> importerselect.getControl('Certificate Processor').selected = True325 >>> modeselect = browser.getControl(name='mode')326 >>> modeselect.getControl(value='create').selected = True327 >>> browser.getControl('Proceed to step 3').click()328 329 Step 3: Fix headerlines330 331 We get informed that there are no problems with the current header:332 333 >>> print browser.contents334 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"335 ...336 Header fields OK337 ...338 339 The submit button is enabled:340 341 >>> browser.getControl('Perform import').disabled342 False343 344 >>> browser.getControl('Perform import').click()345 346 Step 4: See import results347 348 The import was successful:349 350 >>> print browser.contents351 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"352 ...Successfully processed 2 rows...353 ...Batch processing finished...354 ...File:...certificates_zope.mgr.csv...355 356 Batch processing certificate courses357 ====================================358 359 >>> browser.open('http://localhost/app/datacenter')360 361 Prepare a CSV file for certificate courses:362 363 >>> open('mycertcourses.csv', 'wb').write(364 ... """course,faculty_code,department_code,certificate_code,level,mandatory365 ... CRS1,FAC1,DEP1,CERT1,100,True366 ... CRS2,FAC1,DEP1,CERT1,100,True367 ... """)368 369 Upload the file:370 371 >>> import cStringIO372 >>> browser.getLink('Upload data').click()373 >>> filecontents = cStringIO.StringIO(374 ... open('mycertcourses.csv', 'rb').read())375 >>> filewidget = browser.getControl(name='uploadfile:file')376 >>> filewidget.add_file(filecontents, 'text/plain', 'mycertcourses.csv')377 >>> browser.getControl(name='SUBMIT').click()378 379 Step 1: start batch processing:380 381 >>> browser.getLink('Process data').click()382 >>> button = lookup_submit_value(383 ... 'select', 'mycertcourses_zope.mgr.csv', browser)384 >>> button.click()385 386 Step 2: select a processor and mode:387 388 >>> importerselect = browser.getControl(name='importer')389 >>> importerselect.getControl('CertificateCourse Processor').selected = True390 >>> modeselect = browser.getControl(name='mode')391 >>> modeselect.getControl(value='create').selected = True392 >>> browser.getControl('Proceed to step 3').click()393 394 Step 3: Fix headerlines395 396 We get informed that there are no problems with the current header:397 398 >>> print browser.contents399 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"400 ...401 Header fields OK402 ...403 404 The submit button is enabled:405 406 >>> browser.getControl('Perform import').disabled407 False408 409 >>> browser.getControl('Perform import').click()410 411 Step 4: See import results412 413 The import was successful:414 415 >>> print browser.contents416 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"417 ...Successfully processed 2 rows...418 ...Batch processing finished...419 ...File:...mycertcourses_zope.mgr.csv...420 421 60 Batch processing users 422 61 ====================== … … 488 127 >>> henrik = getRootFolder()['app']['users']['henrik'] 489 128 >>> henrik.roles 490 ['waeup.P ortalManager', 'waeup.AcademicsOfficer', 'waeup.ImportManager']129 ['waeup.ProductsOfficer', 'waeup.PortalManager', 'waeup.ImportManager'] 491 130 492 131 Pending files … … 502 141 >>> browser.open('http://localhost/app/datacenter') 503 142 504 Prepare a CSV file for faculties:505 506 >>> open('new faculties.csv', 'wb').write(507 ... """ code,title,title_prefix508 ... FAC1,Faculty 1,faculty509 ... FAC4,Faculty 4,school143 Prepare a CSV file for users: 144 145 >>> open('newusers.csv', 'wb').write( 146 ... """name,title,public_name,email,phone,roles 147 ... isouaba,Issoufou Abba Moussa,Chief Developer,isouaba@abc.de,+49-234-567,[] 148 ... henrik,Henrik Bettermann,Admin,henrik@abc.de,+49-234-567,"['waeup.PortalManager', 'waeup.ImportManager']" 510 149 ... """) 511 150 … … 515 154 >>> browser.getLink('Upload data').click() 516 155 >>> filecontents = cStringIO.StringIO( 517 ... open('new faculties.csv', 'rb').read())156 ... open('newusers.csv', 'rb').read()) 518 157 >>> filewidget = browser.getControl(name='uploadfile:file') 519 >>> filewidget.add_file(filecontents, 'text/plain', 'new faculties.csv')158 >>> filewidget.add_file(filecontents, 'text/plain', 'newusers.csv') 520 159 >>> browser.getControl(name='SUBMIT').click() 521 160 … … 531 170 >>> browser.getLink('Process data').click() 532 171 >>> button = lookup_submit_value( 533 ... 'select', 'new faculties_zope.mgr.csv', browser)172 ... 'select', 'newusers_zope.mgr.csv', browser) 534 173 >>> button.click() 535 174 … … 537 176 538 177 >>> importerselect = browser.getControl(name='importer') 539 >>> importerselect.getControl(' FacultyProcessor').selected = True178 >>> importerselect.getControl('User Processor').selected = True 540 179 >>> modeselect = browser.getControl(name='mode') 541 180 >>> modeselect.getControl(value='create').selected = True … … 561 200 ``finished`` dirs: 562 201 563 >>> pending_file = dc_path + '/new faculties_zope.mgr.create.pending.csv'202 >>> pending_file = dc_path + '/newusers_zope.mgr.create.pending.csv' 564 203 >>> print open(pending_file).read() 565 title_prefix,code,title,--ERRORS--566 faculty,FAC1,Faculty 1,This object already exists. Skipping.567 568 >>> finished_file = dc_path + '/finished/new faculties_zope.mgr.create.finished.csv'204 name,roles,title,public_name,phone,email,--ERRORS-- 205 henrik,"['waeup.PortalManager', 'waeup.ImportManager']",Henrik Bettermann,Admin,+49-234-567,henrik@abc.de,This object already exists. Skipping. 206 207 >>> finished_file = dc_path + '/finished/newusers_zope.mgr.create.finished.csv' 569 208 >>> print open(finished_file).read() 570 title_prefix,code,title571 school,FAC4,Faculty 4209 name,roles,title,public_name,phone,email 210 isouaba,[],Issoufou Abba Moussa,Chief Developer,+49-234-567,isouaba@abc.de 572 211 573 212 The finished-file contains the dataset we could import, while the … … 583 222 import this way: 584 223 585 >>> open(dc_path + '/new faculties_zope.mgr.create.pending.csv', 'wb').write(586 ... """ title_prefix,--IGNORE--,code,title587 ... faculty,FAC5,Faculty 5224 >>> open(dc_path + '/newusers_zope.mgr.create.pending.csv', 'wb').write( 225 ... """name,title,public_name,email,phone,roles 226 ... gbenga,Jason Bamidele,Chief Developer,gbenga@abc.de,+49-234-567,[] 588 227 ... """) 589 228 … … 593 232 >>> browser.getLink('Process data').click() 594 233 >>> button = lookup_submit_value( 595 ... 'select', 'new faculties_zope.mgr.create.pending.csv', browser)234 ... 'select', 'newusers_zope.mgr.create.pending.csv', browser) 596 235 >>> button.click() 597 236 … … 599 238 600 239 >>> importerselect = browser.getControl(name='importer') 601 >>> importerselect.getControl(' FacultyProcessor').selected = True240 >>> importerselect.getControl('User Processor').selected = True 602 241 >>> modeselect = browser.getControl(name='mode') 603 242 >>> modeselect.getControl(value='create').selected = True … … 626 265 627 266 >>> sorted(os.listdir(dc_path + '/finished')) 628 ['certificates_zope.mgr.create.finished.csv', ..., 629 'users_zope.mgr.create.finished.csv', 'users_zope.mgr.csv'] 267 ['newusers_zope.mgr.create.finished.csv', 'newusers_zope.mgr.csv', 'users_zope.mgr.create.finished.csv', 'users_zope.mgr.csv'] 630 268 631 269 Processed (finished) Files … … 633 271 634 272 >>> browser.open('http://localhost/app/datacenter/processed') 635 >>> 'download?filename=finished/ certificates_zope.mgr.create.finished.csv' in browser.contents273 >>> 'download?filename=finished/users_zope.mgr.create.finished.csv' in browser.contents 636 274 True 637 275 -
main/waeup.kofa/branches/henrik-regista/src/waeup/kofa/browser/breadcrumbs.py
r10655 r11947 28 28 from waeup.kofa.browser.interfaces import ( 29 29 IBreadcrumb, IBreadcrumbIgnorable, IBreadcrumbContainer, IKofaObject, 30 IUniversity, IFacultiesContainer, IUsersContainer, IDataCenter, IFaculty, 31 IDepartment, ICourse, ICertificate, ICoursesContainer, ICertificateCourse, 32 ICertificatesContainer 30 IUniversity, IUsersContainer, IDataCenter, 33 31 ) 34 32 from waeup.kofa.reports import IReportsContainer … … 114 112 return (self.context, 'administration') 115 113 116 class FacultiesContainerBreadcrumb(Breadcrumb):117 """A breadcrumb for faculty containers.118 """119 grok.context(IFacultiesContainer)120 title = _(u'Academics')121 122 114 class AdministrationBreadcrumb(Breadcrumb): 123 115 """A breadcrumb for administration areas of University instances. … … 174 166 title = _(u'Student Data Exports') 175 167 target = None 176 177 class FacultyBreadcrumb(Breadcrumb):178 """A breadcrumb for faculties.179 """180 grok.context(IFaculty)181 182 @property183 def title(self):184 return self.context.longtitle185 186 class DepartmentBreadcrumb(FacultyBreadcrumb):187 """A breadcrumb for departments.188 """189 grok.context(IDepartment)190 191 class CourseBreadcrumb(FacultyBreadcrumb):192 """A breadcrumb for courses.193 """194 grok.context(ICourse)195 196 class CertificateBreadcrumb(FacultyBreadcrumb):197 """A breadcrumb for certificates.198 """199 grok.context(ICertificate)200 201 class CoursesContainerBreadcrumb(Breadcrumb):202 """ We don't want course container breadcrumbs.203 """204 grok.context(ICoursesContainer)205 grok.implements(IBreadcrumbIgnorable)206 207 class CertificatesContainerBreadcrumb(Breadcrumb):208 """ We don't want course container breadcrumbs.209 """210 grok.context(ICertificatesContainer)211 grok.implements(IBreadcrumbIgnorable)212 213 class CertificateCourseBreadcrumb(Breadcrumb):214 """ We don't want course container breadcrumbs.215 """216 grok.context(ICertificateCourse)217 @property218 def title(self):219 return self.context.longtitle220 168 221 169 def getBreadcrumb(obj, viewname=None): -
main/waeup.kofa/branches/henrik-regista/src/waeup/kofa/browser/browser.txt
r11794 r11947 148 148 149 149 >>> browser.open('http://localhost/myuniversity//@@change_language?lang=en') 150 151 We can export a university as XML::152 153 >>> browser.open('http://localhost/myuniversity/export.xml')154 >>> print browser.contents155 <?xml version="1.0" encoding="utf-8" ?>156 <pickle>157 ...158 </pickle>159 160 >>> print browser.headers161 Status: 200 Ok162 Content-Length: ...163 Content-Type: text/xml; charset=UTF-8164 X-Powered-By: Zope (www.zope.org), Python (www.python.org)165 150 166 151 … … 204 189 >>> print root['myuniversity']['users']['bob'].roles 205 190 [] 206 >>> root['myuniversity']['users']['bob'].roles = ['waeup. ApplicationsOfficer']191 >>> root['myuniversity']['users']['bob'].roles = ['waeup.UsersManager'] 207 192 >>> print root['myuniversity']['users']['bob'].roles 208 ['waeup. ApplicationsOfficer']193 ['waeup.UsersManager'] 209 194 >>> browser.open('http://localhost/myuniversity/users') 210 195 >>> print browser.contents 211 196 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"... 212 ...<td nowrap> Applications Officer (view only)<br /></td>197 ...<td nowrap>Users Manager <br /></td> 213 198 ... 214 199 … … 263 248 264 249 265 266 Faculties267 =========268 269 Faculties are stored in a special container of `IUniversity`270 instances. The container is called ``faculties`` and provides an271 add-form to add new faculties::272 273 >>> browser.open('http://localhost/myuniversity/faculties/manage')274 >>> browser.getControl('Add faculty').click()275 >>> print browser.contents276 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"...277 ...*...278 ...<span>Name of faculty</span>:279 ...280 >>> browser.getControl('Cancel').click()281 >>> browser.open('http://localhost/myuniversity/faculties/add')282 283 We fill in a new name for our new faculty::284 285 >>> ctrl = browser.getControl(name='form.title')286 >>> ctrl.value = 'TestFac'287 288 Furthermore we add a prefix and a code (kind of abbreviation):289 290 >>> browser.getControl(name='form.code').value = 'TF'291 292 Finally we click on 'Add Faculty' to add the new thing::293 294 >>> browser.getControl('Add faculty').click()295 296 We can view a faculty by browsing a URL like this::297 298 >>> browser.open('http://localhost/myuniversity/faculties/TF')299 300 Afterwards, the faculty should be visible:301 302 >>> browser.open('http://localhost/myuniversity/faculties')303 >>> print browser.contents304 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"305 ...<h1 class="kofa-content-label">Academic Section</h1>306 ...<td> <a href="http://localhost/myuniversity/faculties/TF"> <span>TF</span></a></td>307 ...308 309 We can 'visit' each faculty by clicking on the appropriate link:310 311 >>> browser.getLink('TF').click()312 >>> print browser.contents313 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"...314 ...Faculty of TestFac (TF)...315 ...316 317 If we add the same faculty twice, an error message will occur:318 319 >>> browser.open('http://localhost/myuniversity/faculties/add')320 >>> ctrl = browser.getControl(name='form.title')321 >>> ctrl.value = 'TestFac'322 >>> browser.getControl(name='form.code').value = 'TF'323 >>> browser.getControl('Add faculty').click()324 >>> 'The faculty code chosen already exists.' in browser.contents325 True326 327 Modifying faculties328 -------------------329 330 A faculty can directly be reached by its code:331 332 >>> browser.open('http://localhost/myuniversity/faculties/TF')333 334 We can change the settings for a faculty by clicking on the335 provided 'Manage faculty' button:336 337 >>> browser.getLink('Manage faculty').click()338 339 Let's set a new title and save the form:340 341 >>> browser.getControl(name='form.title').value = "My renamed faculty"342 >>> browser.getControl(name='form.actions.save').click()343 344 Our faculty was indeed renamed to ``My renamed faculty``:345 346 >>> browser.open('http://localhost/myuniversity/faculties')347 >>> print browser.contents348 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"...349 ...<h1 class="kofa-content-label">Academic Section</h1>350 ...<td> <a href="http://localhost/myuniversity/faculties/TF"> <span>TF</span></a></td>351 ...<td>Faculty of My renamed faculty (TF)</td>352 ...353 354 We can grant local roles:355 356 >>> root['myuniversity']['users'].addUser('bob', 'secret',title='Bob',357 ... description='A sample user')358 >>> browser.open('http://localhost/myuniversity/faculties/TF/manage')359 >>> browser.getControl(name="user").value = ['bob']360 >>> browser.getControl(361 ... name="local_role").value = ['waeup.local.DepartmentManager']362 >>> browser.getControl("Add local role").click()363 >>> print browser.contents364 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"...365 ...<td>bob</td>366 ...367 368 On the portal user page the new local role is displayed:369 370 >>> browser.getLink("Portal Users").click()371 >>> print browser.contents372 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"...373 ...<td>Department Manager:...374 ...375 376 The local role can be removed again:377 378 >>> browser.open('http://localhost/myuniversity/faculties/TF/manage')379 >>> ctrl = browser.getControl(name='role_id')380 >>> browser.getControl("Remove selected local roles").click()381 >>> print browser.contents382 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"...383 ...No local role selected...384 ...385 386 >>> browser.open('http://localhost/myuniversity/faculties/TF/manage')387 >>> ctrl = browser.getControl(name='role_id')388 >>> ctrl.getControl(value='bob|waeup.local.DepartmentManager').selected = True389 >>> browser.getControl("Remove selected local roles").click()390 >>> print browser.contents391 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"...392 ...Local role successfully removed...393 ...394 395 Deleting faculties396 ------------------397 398 >>> browser.open('http://localhost/myuniversity/faculties/manage')399 >>> browser.getControl('Cancel').click()400 >>> print browser.url401 http://localhost/myuniversity/faculties402 >>> browser.getLink('Manage academic section').click()403 >>> browser.getControl('Add faculty').click()404 >>> ctrl = browser.getControl(name='form.title')405 >>> ctrl.value = 'Second Faculty'406 >>> browser.getControl(name='form.code').value = 'TF2'407 >>> browser.getControl('Add faculty').click()408 >>> browser.open('http://localhost/myuniversity/faculties/manage')409 >>> browser.getControl("Remove selected", index=0).click()410 >>> 'No item selected' in browser.contents411 True412 >>> browser.open('http://localhost/myuniversity/faculties/manage')413 >>> ctrl = browser.getControl(name='val_id')414 >>> ctrl.getControl(value='TF2').selected = True415 >>> browser.getControl("Remove selected", index=0).click()416 >>> print browser.contents417 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"...418 ...Successfully removed:...419 ...420 421 Departments422 ===========423 424 Adding departments425 ------------------426 427 Departments are stored in :class:`IFaculty` instances with their code428 as key. Faculties therefore are also department containers. Faculties429 provides an add-form to add new departments:430 431 >>> browser.open('http://localhost/myuniversity/faculties/TF/add')432 >>> print browser.contents433 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"...434 ...*</span>435 ...<span>Name of department</span>:436 ...437 >>> browser.getControl('Cancel').click()438 >>> browser.open('http://localhost/myuniversity/faculties/TF/add')439 440 We fill in a new name for our new department:441 442 >>> ctrl = browser.getControl(name='form.title')443 >>> ctrl.value = 'TestDept'444 445 Furthermore we add a code (kind of abbreviation):446 447 >>> browser.getControl(name='form.code').value = 'TD'448 449 Finally we click on 'Add Department' to add the new thing::450 451 >>> browser.getControl('Add department').click()452 453 If we try to register a department under the same code twice we will454 get an error:455 456 >>> browser.open('http://localhost/myuniversity/faculties/TF/add')457 >>> ctrl = browser.getControl(name='form.title')458 >>> ctrl.value = 'Another TestDept with same code'459 >>> browser.getControl(name='form.code').value = 'TD'460 >>> browser.getControl('Add department').click()461 >>> print browser.contents462 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"...463 ...The code chosen already exists in this faculty...464 ...465 466 We can view a department by browsing a URL like this::467 468 >>> browser.open('http://localhost/myuniversity/faculties/TF/TD')469 470 Afterwards, the department should be visible::471 472 >>> browser.open('http://localhost/myuniversity/faculties/TF')473 >>> print browser.contents474 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"...475 ...<h1 class="kofa-content-label">Departments</h1>476 ...<td> <a href="http://localhost/myuniversity/faculties/TF/TD"> <span>TD</span></a></td>477 ...<td>Department of TestDept (TD)</td>478 ...479 480 481 Modifying departments482 ---------------------483 484 We can change the settings for a department by clicking on the485 provided 'Edit department' button:486 487 >>> browser.open('http://localhost/myuniversity/faculties/TF/TD')488 >>> browser.getLink('Manage department').click()489 490 Let's set a new title and save the form:491 492 >>> browser.getControl(name='form.title').value = "My test dept"493 >>> browser.getControl(name='form.actions.save').click()494 495 Clicking 'Save' we will stay on the settings form. So we can change496 the department again.497 498 >>> browser.getControl(name='form.title').value = "My renamed dept"499 >>> ctrl = browser.getControl("Save")500 >>> ctrl.click()501 502 503 Our department was indeed renamed to ``My renamed dept``:504 505 >>> browser.open('http://localhost/myuniversity/faculties/TF')506 >>> print browser.contents507 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"508 ...<h1 class="kofa-content-label">Departments</h1>509 ...<td> <a href="http://localhost/myuniversity/faculties/TF/TD"> <span>TD</span></a></td>510 ...<td>Department of My renamed dept (TD)</td>511 ...512 513 We can grant local roles:514 515 >>> browser.open('http://localhost/myuniversity/faculties/TF/TD/manage')516 >>> browser.getControl(name="user").value = ['bob']517 >>> browser.getControl(518 ... name="local_role").value = ['waeup.local.DepartmentManager']519 >>> browser.getControl("Add local role").click()520 >>> print browser.contents521 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"...522 ...<td>bob</td>523 ...524 525 The local role can be removed again:526 527 >>> browser.open('http://localhost/myuniversity/faculties/TF/TD/manage')528 >>> ctrl = browser.getControl(name='role_id')529 >>> browser.getControl("Remove selected local roles").click()530 >>> print browser.contents531 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"...532 ...No local role selected...533 ...534 535 >>> browser.open('http://localhost/myuniversity/faculties/TF/TD/manage')536 >>> ctrl = browser.getControl(name='role_id')537 >>> ctrl.getControl(538 ... value='bob|waeup.local.DepartmentManager').selected = True539 >>> browser.getControl("Remove selected local roles").click()540 >>> print browser.contents541 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"...542 ...Local role successfully removed...543 ...544 545 Deleting departments546 --------------------547 548 >>> browser.open('http://localhost/myuniversity/faculties/TF/manage')549 >>> browser.getControl('Cancel', index=0).click()550 >>> print browser.url551 http://localhost/myuniversity/faculties/TF552 >>> browser.getLink('Manage faculty').click()553 >>> browser.getControl('Add department').click()554 >>> ctrl = browser.getControl(name='form.title')555 >>> ctrl.value = 'Second Department'556 >>> browser.getControl(name='form.code').value = 'TD2'557 >>> browser.getControl('Add department').click()558 >>> browser.open('http://localhost/myuniversity/faculties/TF/manage')559 >>> browser.getControl("Remove selected", index=0).click()560 >>> 'No item selected' in browser.contents561 True562 >>> browser.open('http://localhost/myuniversity/faculties/TF/manage')563 >>> ctrl = browser.getControl(name='val_id')564 >>> ctrl.getControl(value='TD2').selected = True565 >>> browser.getControl("Remove selected", index=0).click()566 >>> print browser.contents567 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"...568 ...Successfully removed:...569 ...570 571 572 Courses573 =======574 575 Once we have a department, we can add courses.576 577 Adding courses578 --------------579 580 Courses are stored in :class:`ICoursesContainer` instances with their581 code as key. CoursesContainers are normally availabe as `course`582 attribute of :class:`waeup.kofa.university.department.Department`583 instances.584 585 To ease the life of users we do not require to browse the586 coursescontainers (which have a rather flat user interface), but587 provide adding of courses in department views.588 589 Each department provides a ``Add course`` action button near top.590 591 Departments provide an add-form to add new courses:592 593 >>> dept_url = 'http://localhost/myuniversity/faculties/TF/TD'594 >>> browser.open(dept_url + '/manage')595 >>> browser.getControl('Add course').click()596 >>> print browser.contents597 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"...598 ...*</span>599 ...<span>Title of course</span>:600 ...601 602 We fill in a name for our new course:603 604 >>> ctrl = browser.getControl(name='form.title')605 >>> ctrl.value = 'My Course 1'606 607 Furthermore we add a code (kind of abbreviation):608 609 >>> browser.getControl(name='form.code').value = 'COURSE1'610 611 This course will take place in the the first semester, so we set the612 `semester` value to 1:613 614 >>> ctrl = browser.getControl(name='form.semester')615 >>> ctrl.options616 ['1', '2', '3', '9']617 618 >>> ctrl.displayOptions619 ['1st Semester', '2nd Semester', 'Combined', 'N/A']620 621 >>> ctrl.value = ['1']622 623 Finally, we create the course:624 625 >>> browser.getControl('Add course').click()626 627 If we try to register a course under the same code twice we will628 get an error:629 630 >>> browser.open(dept_url + '/addcourse')631 >>> ctrl = browser.getControl(name='form.title')632 >>> ctrl.value = 'Another course with same code'633 >>> browser.getControl(name='form.code').value = 'COURSE1'634 >>> browser.getControl('Add course').click()635 >>> print browser.contents636 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"...637 ...A course with same code already exists:...638 ...639 640 Our course will be linked under the code on the department page:641 642 >>> browser.open(dept_url)643 >>> browser.getLink('COURSE1').click()644 >>> browser.url645 'http://localhost/myuniversity/faculties/TF/TD/courses/COURSE1'646 647 Before we really add a course we can cancel the action and will be648 redirected to the department page:649 650 >>> browser.open(dept_url + '/addcourse')651 >>> browser.getControl('Cancel').click()652 >>> browser.url653 'http://localhost/myuniversity/faculties/TF/TD'654 655 656 Modifying courses657 -----------------658 659 We can change the settings for a course by clicking on the provided660 'Edit settings' link:661 662 >>> browser.open(dept_url + '/courses/COURSE1')663 >>> browser.getLink('Edit course').click()664 665 When modifying a course, we cannot change the code any more:666 667 >>> browser.getControl(name='form.code')668 Traceback (most recent call last):669 ...670 LookupError: name 'form.code'671 672 Let's set a new title and save the form:673 674 >>> browser.getControl(name='form.title').value = "My test course"675 >>> browser.getControl(name='form.actions.save').click()676 677 Clicking 'Save' we will stay on the settings form. So we can change678 the course again. If we click ``Cancel`` nothing will be679 changed:680 681 >>> browser.getControl(name='form.title').value = "Blah"682 >>> browser.getControl('Cancel').click()683 684 Our course was not renamed to ``Blah``:685 686 >>> browser.open('http://localhost/myuniversity/faculties/TF/TD')687 >>> print browser.contents688 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"...689 ...<td>My test course</td>...690 ...691 692 Searching courses693 -----------------694 695 >>> browser.open('http://localhost/myuniversity/faculties/search')696 >>> browser.getControl(name='query').value = "My test course"697 >>> browser.getControl('Search').click()698 >>> print browser.contents699 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"...700 ...faculties/TF/TD/courses/COURSE1">COURSE1</a>701 ...702 703 >>> browser.open('http://localhost/myuniversity/faculties/search')704 >>> browser.getControl(name='query').value = "COURSE1"705 >>> browser.getControl('Search').click()706 >>> print browser.contents707 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"...708 ...faculties/TF/TD/courses/COURSE1">COURSE1</a>709 ...710 711 >>> browser.getControl(name='query').value = "Nonsense"712 >>> browser.getControl('Search').click()713 >>> 'Search Results' in browser.contents714 False715 >>> '<div class="alert alert-warning">No object found.</div>' in browser.contents716 True717 718 >>> browser.getControl(name='query').value = ""719 >>> browser.getControl('Search').click()720 >>> 'Empty search string' in browser.contents721 True722 723 We can grant local roles:724 725 >>> browser.open('http://localhost/myuniversity/faculties/TF/TD/courses/COURSE1/manage')726 >>> browser.getControl(name="user").value = ['bob']727 >>> browser.getControl(728 ... name="local_role").value = ['waeup.local.Lecturer']729 >>> browser.getControl("Add local role").click()730 >>> print browser.contents731 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"...732 ...<td>bob</td>733 ...734 735 On the portal user page the new local role is displayed:736 737 >>> browser.getLink("Portal Users").click()738 >>> print browser.contents739 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"...740 ...<td>Lecturer:...741 ...742 743 The local role can be removed again:744 745 >>> browser.open('http://localhost/myuniversity/faculties/TF/TD/courses/COURSE1/manage')746 >>> ctrl = browser.getControl(name='role_id')747 >>> browser.getControl("Remove selected local roles").click()748 >>> print browser.contents749 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"...750 ...No local role selected...751 ...752 753 >>> browser.open('http://localhost/myuniversity/faculties/TF/TD/courses/COURSE1/manage')754 >>> ctrl = browser.getControl(name='role_id')755 >>> ctrl.getControl(value='bob|waeup.local.Lecturer').selected = True756 >>> browser.getControl("Remove selected local roles").click()757 >>> print browser.contents758 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"...759 ...Local role successfully removed...760 ...761 762 Deleting courses763 ----------------764 765 We can delete courses by browsing the manage page of the containing766 department and checking the appropriate select box and clicking the767 ´´Remove selected´´ button.768 769 >>> browser.open(770 ... 'http://localhost/myuniversity/faculties/TF/TD/@@manage#tab-2')771 >>> 'My test course' in browser.contents772 True773 774 >>> browser.getControl('Cancel', index=0).click()775 >>> browser.getLink('Manage department').click()776 >>> browser.getControl('Remove selected courses').click()777 >>> 'No item selected' in browser.contents778 True779 780 >>> browser.getControl(781 ... name='val_id').getControl(value='COURSE1').selected = True782 >>> browser.getControl('Remove selected courses').click()783 784 >>> browser.open('http://localhost/myuniversity/faculties/TF/TD')785 >>> 'My renamed course' in browser.contents786 False787 788 789 Deleting departments with courses790 ---------------------------------791 792 >>> browser.open('http://localhost/myuniversity/faculties/TF/manage')793 >>> browser.getControl('Cancel', index=0).click()794 >>> browser.getLink('Manage faculty').click()795 >>> browser.getControl('Add department').click()796 >>> ctrl = browser.getControl(name='form.title')797 >>> ctrl.value = 'Third Department'798 >>> browser.getControl(name='form.code').value = 'TD3'799 >>> browser.getControl('Add department').click()800 >>> browser.open('http://localhost/myuniversity/faculties/TF/TD3/manage')801 >>> browser.getControl('Add course').click()802 >>> ctrl = browser.getControl(name='form.title')803 >>> ctrl.value = 'My Course 5'804 >>> browser.getControl(name='form.code').value = 'COURSE5'805 >>> browser.getControl('Add course').click()806 >>> browser.open('http://localhost/myuniversity/faculties/TF/manage')807 >>> ctrl = browser.getControl(name='val_id')808 >>> ctrl.getControl(value='TD3').selected = True809 >>> browser.getControl("Remove selected", index=0).click()810 >>> print browser.contents811 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"...812 ...Successfully removed:...813 ...814 815 Certificates816 ============817 818 Once we have a department, we can add also certificats.819 820 Adding certificates821 -------------------822 823 Certificates are stored in :class:`ICertificatesContainer` instances824 with their code as key. CertificatesContainers are normally availabe as825 `certificates` attribute of826 :class:`waeup.kofa.university.department.Department` instances.827 828 To ease the life of users we do not require to browse the829 certificatescontainers (which have in fact no user interface), but830 provide adding of certificates in department views.831 832 Each department provides a ``Add certificate`` action button near top.833 834 Departments provide an add-form to add new certificates:835 836 >>> dept_url = 'http://localhost/myuniversity/faculties/TF/TD'837 >>> browser.open(dept_url + '/manage')838 >>> browser.getControl('Add certificate').click()839 >>> print browser.contents840 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"...841 ...*</span>842 ...<span>Title</span>:843 ...844 845 We fill in a name for our new cert:846 847 >>> ctrl = browser.getControl(name='form.title')848 >>> ctrl.value = 'My Certificate 1'849 850 Furthermore we add a code (kind of abbreviation):851 852 >>> browser.getControl(name='form.code').value = 'CERT1'853 854 Set the remaining required fields:855 856 >>> browser.getControl(name='form.study_mode').value = ['ug_ft']857 >>> browser.getControl(name='form.start_level').value = ['100']858 >>> browser.getControl(name='form.end_level').value = ['400']859 >>> browser.getControl(name='form.application_category').value = ['basic']860 861 Finally, we create the certificate:862 863 >>> browser.getControl('Add certificate').click()864 865 If we try to register a certificate under the same code twice we will866 get an error:867 868 >>> browser.open(dept_url + '/addcertificate')869 >>> ctrl = browser.getControl(name='form.title')870 >>> ctrl.value = 'Another cert with same code'871 >>> browser.getControl(name='form.code').value = 'CERT1'872 >>> browser.getControl(name='form.study_mode').value = ['ug_ft']873 >>> browser.getControl(name='form.start_level').value = ['100']874 >>> browser.getControl(name='form.end_level').value = ['400']875 >>> browser.getControl(name='form.application_category').value = ['basic']876 877 >>> browser.getControl('Add certificate').click()878 >>> print browser.contents879 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"...880 ...A certificate with same code already exists:...881 ...882 883 Our certificate will be linked under the code on the department page:884 885 >>> browser.open(dept_url)886 >>> browser.getLink('CERT1').click()887 >>> browser.url888 'http://localhost/myuniversity/faculties/TF/TD/certificates/CERT1'889 890 Before we really add a certificate we can cancel the action and will be891 redirected to the department page:892 893 >>> browser.open(dept_url + '/addcertificate')894 >>> browser.getControl('Cancel').click()895 >>> browser.url896 'http://localhost/myuniversity/faculties/TF/TD'897 898 899 Modifying certificates900 ----------------------901 902 We can change the settings for a cert by clicking on the provided903 'Edit certificate' link:904 905 >>> browser.open(dept_url + '/certificates/CERT1')906 >>> browser.getLink('Manage certificate').click()907 908 When modifying a certificate, we cannot change the code any more:909 910 >>> browser.getControl(name='form.code')911 Traceback (most recent call last):912 ...913 LookupError: name 'form.code'914 915 Let's set a new title and save the form:916 917 >>> browser.getControl(name='form.title').value = "My test cert"918 >>> browser.getControl(name='form.actions.save').click()919 920 Clicking 'Save' we will stay on the settings form. So we can change921 the cert again.922 923 >>> browser.getControl(name='form.title').value = "My renamed cert"924 >>> ctrl = browser.getControl("Save",index=0)925 >>> ctrl.click()926 927 If we go to the settings page and click ``Cancel`` nothing will be928 changed:929 930 >>> browser.getControl(name='form.title').value = "Blah"931 >>> browser.getControl('Cancel',index=0).click()932 933 Our certificate was indeed renamed to ``My renamed cert`` and not to934 ``Blah``:935 936 >>> browser.open('http://localhost/myuniversity/faculties/TF/TD')937 >>> print browser.contents938 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"...939 ...<td>My renamed cert</td>...940 ...941 942 Searching certificates943 ----------------------944 945 >>> browser.open('http://localhost/myuniversity/faculties/search')946 >>> browser.getControl(name='query').value = "My renamed cert"947 >>> browser.getControl('Search').click()948 >>> print browser.contents949 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"...950 ...faculties/TF/TD/certificates/CERT1">CERT1</a>951 ...952 953 >>> browser.open('http://localhost/myuniversity/faculties/search')954 >>> browser.getControl(name='query').value = "CERT1"955 >>> browser.getControl('Search').click()956 >>> print browser.contents957 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"...958 ...faculties/TF/TD/certificates/CERT1">CERT1</a>959 ...960 961 Deleting certificates962 ---------------------963 964 We can delete certificates by browsing the manage page of the965 containing department and checking the appropriate select box and966 clicking the ´´Remove selected´´ button.967 968 >>> browser.open(969 ... 'http://localhost/myuniversity/faculties/TF/TD/@@manage#tab-3')970 >>> 'My renamed cert' in browser.contents971 True972 973 >>> browser.getControl('Remove selected certificates').click()974 >>> 'No item selected' in browser.contents975 True976 977 >>> browser.getControl(name='val_id').getControl(978 ... value='CERT1').selected = True979 >>> browser.getControl('Remove selected certificates').click()980 >>> 'My renamed cert' in browser.contents981 False982 983 984 CertificateCourses985 ==================986 987 Once we have a certificate, we can add also certificate courses. These988 are referrers of courses with some extra data.989 990 Before we can work with certificate courses, we need some certificates991 and courses to be available.992 993 >>> browser.open(dept_url + '/addcourse')994 >>> ctrl = browser.getControl(name='form.title')995 >>> ctrl.value = 'Another course with same code'996 >>> browser.getControl(name='form.code').value = 'COURSE1'997 >>> browser.getControl(name='form.title').value = 'Course 1'998 >>> browser.getControl('Add course').click()999 1000 >>> browser.open(dept_url + '/addcourse')1001 >>> ctrl = browser.getControl(name='form.title')1002 >>> ctrl.value = 'Another course with same code'1003 >>> browser.getControl(name='form.code').value = 'COURSE2'1004 >>> browser.getControl(name='form.title').value = 'Course 2'1005 >>> browser.getControl('Add course').click()1006 1007 >>> browser.open(dept_url + '/addcertificate')1008 >>> ctrl = browser.getControl(name='form.title')1009 >>> ctrl.value = 'Another cert with same code'1010 >>> browser.getControl(name='form.code').value = 'CERT1'1011 >>> browser.getControl(name='form.title').value = 'Certificate 1'1012 >>> browser.getControl(name='form.study_mode').value = ['ug_ft']1013 >>> browser.getControl(name='form.start_level').value = ['100']1014 >>> browser.getControl(name='form.end_level').value = ['400']1015 >>> browser.getControl(name='form.application_category').value = ['basic']1016 >>> browser.getControl('Add certificate').click()1017 1018 >>> browser.open(dept_url + '/addcertificate')1019 >>> ctrl = browser.getControl(name='form.title')1020 >>> ctrl.value = 'Another cert with same code'1021 >>> browser.getControl(name='form.code').value = 'CERT2'1022 >>> browser.getControl(name='form.title').value = 'Certificate 2'1023 >>> browser.getControl(name='form.study_mode').value = ['ug_ft']1024 >>> browser.getControl(name='form.start_level').value = ['100']1025 >>> browser.getControl(name='form.end_level').value = ['400']1026 >>> browser.getControl(name='form.application_category').value = ['basic']1027 >>> browser.getControl('Add certificate').click()1028 1029 1030 Adding certificatecourses1031 -------------------------1032 1033 Certcourses are stored in :class:`ICertificate` instances1034 with their code as key.1035 1036 Each certificate provides a ``Add certificate course`` action button near top.1037 1038 Certificates provide an add-form to add new certcourses:1039 1040 >>> cert_url = dept_url + '/certificates/CERT1'1041 >>> browser.open(cert_url + '/manage')1042 >>> browser.getControl('Add certificate course').click()1043 >>> print browser.contents1044 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"...1045 ...*</span>1046 ...<span>Level</span>:1047 ...1048 1049 In the add-form we will get a list of available courses to select1050 from. This list will contain all courses stored in the site, not only1051 the ones from local department:1052 1053 >>> ctrl = browser.getControl(name='form.course')1054 >>> ctrl.displayOptions1055 ['--', 'COURSE1 - Course 1', 'COURSE2 - Course 2']1056 1057 We select the first course and create our certificatecourse:1058 1059 >>> ctrl.getControl('COURSE1').selected = True1060 >>> browser.getControl(name='form.level').value = ['100']1061 >>> browser.getControl('Add certificate course').click()1062 1063 Our certificatecourse will be linked on the parent certificate page:1064 1065 >>> browser.open(cert_url)1066 >>> browser.getLink('COURSE1_100').click()1067 >>> browser.url1068 'http://localhost/my...sity/faculties/TF/TD/certificates/CERT1/COURSE1_100'1069 1070 We can't add the same certificatecourse twice:1071 1072 >>> cert_url = dept_url + '/certificates/CERT1'1073 >>> browser.open(cert_url + '/manage')1074 >>> browser.getControl('Add certificate course').click()1075 >>> ctrl = browser.getControl(name='form.course')1076 >>> ctrl.getControl('COURSE1').selected = True1077 >>> browser.getControl(name='form.level').value = ['100']1078 >>> browser.getControl('Add certificate course').click()1079 >>> 'The chosen certificate course is already' in browser.contents1080 True1081 1082 When we started to add a new certificatecourse, we can also cancel the1083 process before submitting. This will bring us back to the certificate1084 page:1085 1086 >>> browser.open(cert_url + '/addcertificatecourse')1087 >>> browser.getControl('Cancel').click()1088 >>> browser.url1089 'http://localhost/myuniversity/faculties/TF/TD/certificates/CERT1'1090 1091 1092 Modifying certificatecourses1093 ----------------------------1094 1095 We can change the settings for a certcourse by clicking on the1096 provided 'Edit certificate course' link:1097 1098 >>> browser.open(cert_url + '/COURSE1_100')1099 >>> browser.getLink('Edit certificate course').click()1100 1101 If we just click 'Save and return' nothing will change:1102 1103 >>> browser.getControl("Save and return").click()1104 >>> browser.getLink('COURSE1_100').click()1105 >>> browser.url1106 'http://localhost/myun.../TF/TD/certificates/CERT1/COURSE1_100'1107 1108 Let's set a new level (it was 100 before) and save the form. This will1109 bring us to the certificate index page afterwards:1110 1111 >>> browser.open(cert_url + '/COURSE1_100/manage')1112 >>> browser.getControl(name='form.level').value = ['200']1113 >>> browser.getControl("Save and return").click()1114 1115 As we changed the level, also the URL will change:1116 1117 >>> browser.getLink('COURSE1_200').click()1118 >>> browser.url1119 'http://localhost/myun.../TF/TD/certificates/CERT1/COURSE1_200'1120 1121 If we go to the settings page and click ``Cancel`` nothing will be1122 changed:1123 1124 >>> browser.getLink('Edit certificate course').click()1125 >>> browser.getControl(name='form.level').value = ['400']1126 >>> browser.getControl('Cancel').click()1127 1128 Our certcourse provides a new level of 200 and not 400:1129 1130 >>> browser.open(cert_url + '/COURSE1_200')1131 >>> print browser.contents1132 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"1133 ...<td>Level:</td>1134 ...<td>200 (Year 2)</td>1135 ...1136 1137 Searching certificatecourses1138 ----------------------------1139 1140 >>> browser.open('http://localhost/myuniversity/faculties/search')1141 >>> browser.getControl(name='query').value = "COURSE1"1142 >>> browser.getControl('Search').click()1143 >>> print browser.contents1144 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"...1145 ...faculties/TF/TD/certificates/CERT1/COURSE1_200">COURSE1</a>1146 ...1147 1148 >>> browser.getControl(name='query').value = "*"1149 >>> browser.getControl('Search').click()1150 >>> 'Search string not allowed' in browser.contents1151 True1152 1153 Deleting certificatecourses1154 ---------------------------1155 1156 We can delete certcourses by browsing the containing certificate manage page:1157 1158 >>> browser.open(cert_url + '/manage#tab-2')1159 >>> 'COURSE1_200</a>' in browser.contents1160 True1161 >>> browser.getControl('Remove selected certificate courses').click()1162 >>> 'No item selected' in browser.contents1163 True1164 >>> browser.getControl(name='val_id').getControl(1165 ... value='COURSE1_200').selected = True1166 >>> browser.getControl('Remove selected certificate courses').click()1167 >>> 'Successfully removed: COURSE1_200' in browser.contents1168 True1169 1170 >>> 'COURSE1_200</a>' in browser.contents1171 False1172 1173 1174 1175 250 Data Center 1176 251 =========== … … 1276 351 ['deleted', 'finished', 'logs', 'myfaculties_zope.mgr.csv', 'unfinished'] 1277 352 1278 We create and upload also a CSV file containing departments:1279 1280 >>> open('departments.csv', 'wb').write(1281 ... """code,title,title_prefix,faculty_code1282 ... LIT,Literature,department,FA1283 ... SOC,Sociology,department,FA1284 ... PHY,Physics,department,FS1285 ... INF,Informatics,department,FS1286 ... MAT,Math,department,FS1287 ... """)1288 1289 >>> browser.open('http://localhost/myuniversity/datacenter/upload')1290 >>> browser.getControl(name='uploadfile:file').add_file(1291 ... cStringIO.StringIO(open('departments.csv', 'rb').read()),1292 ... 'text/plain', 'mydepartments.csv')1293 >>> browser.getControl(name='SUBMIT').click()1294 1295 We create and upload also a CSV file containing courses:1296 1297 >>> open('courses.csv', 'wb').write(1298 ... """code,level,title,passmark,credits,semester,faculty,department1299 ... LI1,,Introduction to Literature I,40,2,1,FA,LIT1300 ... LI2,,Introduction to Literature II,40,2,2,FA,LIT1301 ... AN1,000,Analysis I,40,2,1,FS,MAT1302 ... AN2,000,Analysis II,40,2,2,FS,MAT1303 ... """)1304 1305 >>> browser.open('http://localhost/myuniversity/datacenter/upload')1306 >>> browser.getControl(name='uploadfile:file').add_file(1307 ... cStringIO.StringIO(open('courses.csv', 'rb').read()),1308 ... 'text/plain', 'mycourses.csv')1309 >>> browser.getControl(name='SUBMIT').click()1310 1311 We create and upload also a CSV file containing certificates:1312 1313 >>> open('certificates.csv', 'wb').write(1314 ... """code,title,faculty_code,department_code,study_mode,end_level,m_prefix,start_level,application_category1315 ... LBA,BACHELOR OF LITERATURE,FA,LIT,UG,ug_ft,500,LIT,100,basic1316 ... LMA,MASTER OF LITERATURE,FA,LIT,UG,ug_pt,500,LIT,100,cest1317 ... DME,DIPLOMA OF MATH,FS,MAT,DP,dp_ft,200,DME,100,cest1318 ... """)1319 1320 >>> browser.open('http://localhost/myuniversity/datacenter/upload')1321 >>> browser.getControl(name='uploadfile:file').add_file(1322 ... cStringIO.StringIO(open('certificates.csv', 'rb').read()),1323 ... 'text/plain', 'mycertificates.csv')1324 >>> browser.getControl(name='SUBMIT').click()1325 1326 We create and upload also a CSV file containing certificate courses:1327 1328 >>> open('certcourses.csv', 'wb').write(1329 ... """code,faculty_code,department_code,certificate_code,level,mandatory1330 ... LI1,FA,LIT,LBA,100,True1331 ... LI2,FA,LIT,LBA,200,True1332 ... """)1333 1334 >>> browser.open('http://localhost/myuniversity/datacenter/upload')1335 >>> browser.getControl(name='uploadfile:file').add_file(1336 ... cStringIO.StringIO(open('certcourses.csv', 'rb').read()),1337 ... 'text/plain', 'mycertcourses.csv')1338 >>> browser.getControl(name='SUBMIT').click()1339 353 1340 354 -
main/waeup.kofa/branches/henrik-regista/src/waeup/kofa/browser/interfaces.py
r11254 r11947 23 23 IKofaObject, IUniversity, IUsersContainer, IDataCenter, validate_email) 24 24 from waeup.kofa.interfaces import MessageFactory as _ 25 from waeup.kofa.university.interfaces import (26 IFacultiesContainer, IFaculty, IDepartment,27 ICoursesContainer, ICourse, ICertificatesContainer,28 ICertificate, ICertificateCourse)29 25 30 26 class IBreadcrumb(Interface): … … 177 173 title = _(u'Unique Identifier'), 178 174 description = _( 179 u'User Name, Student or Applicant Id, Matriculationor '175 u'User Name, Customer Id, or ' 180 176 u'Registration Number'), 181 177 required = True, … … 188 184 constraint=validate_email, 189 185 ) 190 191 class IStudentNavigationBase(IKofaObject):192 """Objects that provide student navigation (whatever it is) should193 implement this interface.194 """195 student = Attribute('''Some student object that has a '''196 ''' `display_fullname` attribute.''')197 198 class IApplicantBase(IKofaObject):199 """Some Applicant.200 """201 display_fullname = Attribute('''Fullname.''') -
main/waeup.kofa/branches/henrik-regista/src/waeup/kofa/browser/layout.py
r11437 r11947 35 35 from waeup.kofa.interfaces import MessageFactory as _ 36 36 from waeup.kofa.utils.helpers import to_timezone 37 from waeup.kofa.browser.interfaces import (38 IStudentNavigationBase, IApplicantBase)39 37 from waeup.kofa.authentication import get_principal_role_manager 40 38 … … 254 252 return userid 255 253 256 def is Student(self):254 def isCustomer(self): 257 255 usertype = getattr(self.request.principal, 'user_type', None) 258 256 if not usertype: 259 257 return False 260 return self.request.principal.user_type == 'student' 261 262 def isApplicant(self): 263 usertype = getattr(self.request.principal, 'user_type', None) 264 if not usertype: 265 return False 266 return self.request.principal.user_type == 'applicant' 267 268 def getStudentName(self): 269 """Return the student name. 270 """ 271 if IStudentNavigationBase.providedBy(self.context): 272 return self.context.student.display_fullname 273 return 258 return self.request.principal.user_type == 'customer' 274 259 275 260 def formatDatetime(self,datetimeobj): … … 301 286 302 287 def render(self): 303 if self.is Student() or self.isApplicant() or not self.isAuthenticated():288 if self.isCustomer() or not self.isAuthenticated(): 304 289 return self.studenttemp.render(self) 305 290 return self.stafftemp.render(self) -
main/waeup.kofa/branches/henrik-regista/src/waeup/kofa/browser/pages.py
r11889 r11947 46 46 KofaDisplayFormPage, NullValidator) 47 47 from waeup.kofa.browser.interfaces import ( 48 IUniversity, IFacultiesContainer, IFaculty, 49 IDepartment, ICourse, ICertificate, 50 ICertificateCourse, 51 ICaptchaManager, IChangePassword) 48 IUniversity, ICaptchaManager, IChangePassword) 52 49 from waeup.kofa.browser.layout import jsaction, action, UtilityView 53 50 from waeup.kofa.interfaces import MessageFactory as _ … … 58 55 ISessionConfiguration, ISessionConfigurationAdd, IJobManager, 59 56 IPasswordValidator, IContactForm, IKofaUtils, ICSVExporter, 60 a cademic_sessions_vocab)57 application_sessions_vocab) 61 58 from waeup.kofa.permissions import ( 62 59 get_users_with_local_roles, get_all_roles, get_all_users, 63 60 get_users_with_role) 64 61 65 from waeup.kofa.university.catalog import search66 from waeup.kofa.university.vocabularies import course_levels67 62 from waeup.kofa.authentication import LocalRoleSetEvent 68 63 from waeup.kofa.widgets.htmlwidget import HTMLDisplayWidget … … 70 65 from waeup.kofa.mandates.mandate import PasswordMandate 71 66 from waeup.kofa.datacenter import DataCenterFile 72 73 from waeup.kofa.students.export import EXPORTER_NAMES as STUDENT_EXPORTERS74 from waeup.kofa.students.catalog import StudentQueryResultItem75 67 76 68 FORBIDDEN_CHARACTERS = (160,) … … 270 262 login_button = label 271 263 272 def _comment(self, student):273 return getattr(student, 'suspended_comment', None)274 275 264 def update(self, SUBMIT=None, camefrom=None): 276 265 self.camefrom = camefrom … … 278 267 if self.request.principal.id != 'zope.anybody': 279 268 self.flash(_('You logged in.')) 280 if self.request.principal.user_type == ' student':281 student = grok.getSite()[' students'][269 if self.request.principal.user_type == 'customer': 270 student = grok.getSite()['customerss'][ 282 271 self.request.principal.id] 283 rel_link = '/ students/%s' % self.request.principal.id272 rel_link = '/customers/%s' % self.request.principal.id 284 273 if student.personal_data_expired: 285 rel_link = '/ students/%s/edit_personal' % (274 rel_link = '/customerss/%s/edit_personal' % ( 286 275 self.request.principal.id) 287 276 self.flash( 288 277 _('Your personal data record is outdated. Please update.'), 289 278 type='warning') 290 self.redirect(self.application_url() + rel_link)291 return292 elif self.request.principal.user_type == 'applicant':293 container, application_number = self.request.principal.id.split('_')294 rel_link = '/applicants/%s/%s' % (295 container, application_number)296 279 self.redirect(self.application_url() + rel_link) 297 280 return … … 301 284 self.redirect(self.camefrom) 302 285 return 303 # Display appropriate flash message if credentials are correct304 # but student has been deactivated or a temporary password305 # has been set.306 login = self.request.form['form.login']307 if len(login) == 8 and login in grok.getSite()['students']:308 student = grok.getSite()['students'][login]309 password = self.request.form['form.password']310 passwordmanager = getUtility(IPasswordManager, 'SSHA')311 if student.password is not None and \312 passwordmanager.checkPassword(student.password, password):313 # The student entered valid credentials.314 # First we check if a temporary password has been set.315 delta = timedelta(minutes=10)316 now = datetime.utcnow()317 temp_password_dict = getattr(student, 'temp_password', None)318 if temp_password_dict is not None and \319 now < temp_password_dict.get('timestamp', now) + delta:320 self.flash(321 _('Your account has been temporarily deactivated.'),322 type='warning')323 return324 # Now we know that the student is suspended.325 comment = self._comment(student)326 if comment:327 self.flash(comment, type='warning')328 else:329 self.flash(_('Your account has been deactivated.'),330 type='warning')331 return332 286 self.flash(_('You entered invalid credentials.'), type='danger') 333 287 return … … 734 688 735 689 # 736 # Search pages...737 #738 739 class SearchPage(KofaPage):740 """General search page for the academics section.741 """742 grok.context(IFacultiesContainer)743 grok.name('search')744 grok.template('searchpage')745 grok.require('waeup.viewAcademics')746 label = _(u"Search Academic Section")747 pnav = 1748 search_button = _(u'Search')749 750 def update(self, *args, **kw):751 form = self.request.form752 self.hitlist = []753 self.query = ''754 if not 'query' in form:755 return756 query = form['query']757 self.query = query758 self.hitlist = search(query=self.query, view=self)759 if not self.hitlist:760 self.flash(_('No object found.'), type="warning")761 return762 763 #764 690 # Configuration pages... 765 691 # … … 856 782 self.context.__parent__.logger.info( 857 783 '%s - added: %s' % ( 858 ob_class, sessionconfiguration.a cademic_session))784 ob_class, sessionconfiguration.application_session)) 859 785 except KeyError: 860 786 self.flash(_('The session chosen already exists.'), type='danger') … … 1518 1444 self.filename = logname 1519 1445 self.query = query 1520 if search is None ornot query:1446 if not query: 1521 1447 return 1522 1448 try: … … 1582 1508 utils = getUtilitiesFor(ICSVExporter) 1583 1509 title_name_tuples = [ 1584 (util.title, name) for name, util in utils 1585 if not name in STUDENT_EXPORTERS] 1586 # The exporter for access codes requires a special permission. 1587 if not checkPermission('waeup.manageACBatches', self.context): 1588 title_name_tuples.remove((u'AccessCodes', u'accesscodes')) 1510 (util.title, name) for name, util in utils] 1589 1511 return sorted(title_name_tuples) 1590 1512 … … 1643 1565 return result 1644 1566 1645 class ExportXMLPage(grok.View):1646 """Deliver an XML representation of the context.1647 """1648 grok.name('export.xml')1649 grok.require('waeup.managePortal')1650 1651 def render(self):1652 exporter = IKofaXMLExporter(self.context)1653 xml = exporter.export().read()1654 self.response.setHeader(1655 'Content-Type', 'text/xml; charset=UTF-8')1656 return xml1657 1658 class ImportXMLPage(KofaPage):1659 """Replace the context object by an object created from an XML1660 representation.1661 1662 XXX: This does not work for ISite objects, i.e. for instance1663 for complete University objects.1664 """1665 grok.name('importxml')1666 grok.require('waeup.managePortal')1667 1668 def update(self, xmlfile=None, CANCEL=None, SUBMIT=None):1669 if CANCEL is not None:1670 self.redirect(self.url(self.context))1671 return1672 if not xmlfile:1673 return1674 importer = IKofaXMLImporter(self.context)1675 obj = importer.doImport(xmlfile)1676 if type(obj) != type(self.context):1677 return1678 parent = self.context.__parent__1679 name = self.context.__name__1680 self.context = obj1681 if hasattr(parent, name):1682 setattr(parent, name, obj)1683 else:1684 del parent[name]1685 parent[name] = obj1686 pass1687 return1688 1689 1690 #1691 # FacultiesContainer pages...1692 #1693 1694 class FacultiesContainerPage(KofaPage):1695 """ Index page for faculty containers.1696 """1697 grok.context(IFacultiesContainer)1698 grok.require('waeup.viewAcademics')1699 grok.name('index')1700 label = _('Academic Section')1701 pnav = 11702 grok.template('facultypage')1703 1704 class FacultiesContainerManageFormPage(KofaEditFormPage):1705 """Manage the basic properties of a `Faculty` instance.1706 """1707 grok.context(IFacultiesContainer)1708 grok.name('manage')1709 grok.require('waeup.manageAcademics')1710 grok.template('facultiescontainermanagepage')1711 pnav = 11712 taboneactions = [_('Add faculty'), _('Remove selected'),_('Cancel')]1713 subunits = _('Faculties')1714 1715 @property1716 def label(self):1717 return _('Manage academic section')1718 1719 @jsaction(_('Remove selected'))1720 def delFaculties(self, **data):1721 if not checkPermission('waeup.managePortal', self.context):1722 self.flash(_('You are not allowed to remove entire faculties.'),1723 type='warning')1724 return1725 delSubobjects(self, redirect='@@manage', tab='1')1726 return1727 1728 @action(_('Add faculty'), validator=NullValidator)1729 def addFaculty(self, **data):1730 self.redirect(self.url(self.context, '@@add'))1731 return1732 1733 @action(_('Cancel'), validator=NullValidator)1734 def cancel(self, **data):1735 self.redirect(self.url(self.context))1736 return1737 1738 1739 class FacultyAddFormPage(KofaAddFormPage):1740 """ Page form to add a new faculty to a faculty container.1741 """1742 grok.context(IFacultiesContainer)1743 grok.require('waeup.manageAcademics')1744 grok.name('add')1745 label = _('Add faculty')1746 form_fields = grok.AutoFields(IFaculty)1747 pnav = 11748 1749 @action(_('Add faculty'), style='primary')1750 def addFaculty(self, **data):1751 faculty = createObject(u'waeup.Faculty')1752 self.applyData(faculty, **data)1753 try:1754 self.context.addFaculty(faculty)1755 except KeyError:1756 self.flash(_('The faculty code chosen already exists.'),1757 type='danger')1758 return1759 ob_class = self.__implemented__.__name__.replace('waeup.kofa.','')1760 self.context.__parent__.logger.info(1761 '%s - added: %s' % (ob_class, faculty.code))1762 self.redirect(self.url(self.context, u'@@manage')+'#tab1')1763 return1764 1765 @action(_('Cancel'), validator=NullValidator)1766 def cancel(self, **data):1767 self.redirect(self.url(self.context))1768 1769 #1770 # Faculty pages1771 #1772 class FacultyPage(KofaPage):1773 """Index page of faculties.1774 """1775 grok.context(IFaculty)1776 grok.require('waeup.viewAcademics')1777 grok.name('index')1778 pnav = 11779 1780 @property1781 def label(self):1782 return _('Departments')1783 1784 class FacultyManageFormPage(KofaEditFormPage,1785 LocalRoleAssignmentUtilityView):1786 """Manage the basic properties of a `Faculty` instance.1787 """1788 grok.context(IFaculty)1789 grok.name('manage')1790 grok.require('waeup.manageAcademics')1791 grok.template('facultymanagepage')1792 pnav = 11793 subunits = _('Departments')1794 taboneactions = [_('Save'),_('Cancel')]1795 tabtwoactions = [_('Add department'), _('Remove selected'),_('Cancel')]1796 tabthreeactions1 = [_('Remove selected local roles')]1797 tabthreeactions2 = [_('Add local role')]1798 1799 form_fields = grok.AutoFields(IFaculty).omit('code')1800 1801 @property1802 def label(self):1803 return _('Manage faculty')1804 1805 @jsaction(_('Remove selected'))1806 def delDepartments(self, **data):1807 if not checkPermission('waeup.managePortal', self.context):1808 self.flash(_('You are not allowed to remove entire departments.'),1809 type='danger')1810 return1811 delSubobjects(self, redirect='@@manage', tab='2')1812 return1813 1814 @action(_('Save'), style='primary')1815 def save(self, **data):1816 return msave(self, **data)1817 1818 @action(_('Cancel'), validator=NullValidator)1819 def cancel(self, **data):1820 self.redirect(self.url(self.context))1821 return1822 1823 @action(_('Add department'), validator=NullValidator)1824 def addSubunit(self, **data):1825 self.redirect(self.url(self.context, '@@add'))1826 return1827 1828 @action(_('Add local role'), validator=NullValidator)1829 def addLocalRole(self, **data):1830 return add_local_role(self,3,**data)1831 1832 @action(_('Remove selected local roles'))1833 def delLocalRoles(self, **data):1834 return del_local_roles(self,3,**data)1835 1836 class FindStudentsPage(KofaPage):1837 """Search students in faculty.1838 """1839 grok.context(IFaculty)1840 grok.name('find_students')1841 grok.require('waeup.showStudents')1842 grok.template('findstudentspage')1843 search_button = _('Find student(s)')1844 pnav = 11845 1846 @property1847 def label(self):1848 return _('Find students in ') + ('%s' % self.context.longtitle)1849 1850 def _find_students(self,query=None, searchtype=None, view=None):1851 hitlist = []1852 if searchtype in ('fullname',):1853 results = Query().searchResults(1854 Text(('students_catalog', searchtype), query) &1855 Eq(('students_catalog', 'faccode'), self.context.code)1856 )1857 else:1858 results = Query().searchResults(1859 Eq(('students_catalog', searchtype), query) &1860 Eq(('students_catalog', 'faccode'), self.context.code)1861 )1862 for result in results:1863 hitlist.append(StudentQueryResultItem(result, view=view))1864 return hitlist1865 1866 def update(self, *args, **kw):1867 form = self.request.form1868 self.hitlist = []1869 if 'searchterm' in form and form['searchterm']:1870 self.searchterm = form['searchterm']1871 self.searchtype = form['searchtype']1872 elif 'old_searchterm' in form:1873 self.searchterm = form['old_searchterm']1874 self.searchtype = form['old_searchtype']1875 else:1876 if 'search' in form:1877 self.flash(_('Empty search string'), type='warning')1878 return1879 self.hitlist = self._find_students(query=self.searchterm,1880 searchtype=self.searchtype, view=self)1881 if not self.hitlist:1882 self.flash(_('No student found.'), type='warning')1883 return1884 1885 class DepartmentAddFormPage(KofaAddFormPage):1886 """Add a department to a faculty.1887 """1888 grok.context(IFaculty)1889 grok.name('add')1890 grok.require('waeup.manageAcademics')1891 label = _('Add department')1892 form_fields = grok.AutoFields(IDepartment)1893 pnav = 11894 1895 @action(_('Add department'), style='primary')1896 def addDepartment(self, **data):1897 department = createObject(u'waeup.Department')1898 self.applyData(department, **data)1899 try:1900 self.context.addDepartment(department)1901 except KeyError:1902 self.flash(_('The code chosen already exists in this faculty.'),1903 type='danger')1904 return1905 self.status = self.flash(1906 _("Department ${a} added.", mapping = {'a':data['code']}))1907 ob_class = self.__implemented__.__name__.replace('waeup.kofa.','')1908 self.context.__parent__.__parent__.logger.info(1909 '%s - added: %s' % (ob_class, data['code']))1910 self.redirect(self.url(self.context, u'@@manage')+'#tab2')1911 return1912 1913 @action(_('Cancel'), validator=NullValidator)1914 def cancel(self, **data):1915 self.redirect(self.url(self.context))1916 return1917 1918 #1919 # Department pages1920 #1921 class DepartmentPage(KofaPage):1922 """Department index page.1923 """1924 grok.context(IDepartment)1925 grok.require('waeup.viewAcademics')1926 grok.name('index')1927 pnav = 11928 label = _('Courses and Certificates')1929 1930 def update(self):1931 super(DepartmentPage, self).update()1932 return1933 1934 def getCourses(self):1935 """Get a list of all stored courses.1936 """1937 for key, val in self.context.courses.items():1938 url = self.url(val)1939 yield(dict(url=url, name=key, container=val))1940 1941 def getCertificates(self):1942 """Get a list of all stored certificates.1943 """1944 for key, val in self.context.certificates.items():1945 url = self.url(val)1946 yield(dict(url=url, name=key, container=val))1947 1948 class DepartmentManageFormPage(KofaEditFormPage,1949 LocalRoleAssignmentUtilityView):1950 """Manage the basic properties of a `Department` instance.1951 """1952 grok.context(IDepartment)1953 grok.name('manage')1954 grok.require('waeup.manageAcademics')1955 pnav = 11956 grok.template('departmentmanagepage')1957 taboneactions = [_('Save'),_('Cancel')]1958 tabtwoactions = [_('Add course'), _('Remove selected courses'),_('Cancel')]1959 tabthreeactions = [_('Add certificate'), _('Remove selected certificates'),1960 _('Cancel')]1961 tabfouractions1 = [_('Remove selected local roles')]1962 tabfouractions2 = [_('Add local role')]1963 1964 form_fields = grok.AutoFields(IDepartment).omit('code')1965 1966 @property1967 def label(self):1968 return _('Manage department')1969 1970 def getCourses(self):1971 """Get a list of all stored courses.1972 """1973 for key, val in self.context.courses.items():1974 url = self.url(val)1975 yield(dict(url=url, name=key, container=val))1976 1977 def getCertificates(self):1978 """Get a list of all stored certificates.1979 """1980 for key, val in self.context.certificates.items():1981 url = self.url(val)1982 yield(dict(url=url, name=key, container=val))1983 1984 @action(_('Save'), style='primary')1985 def save(self, **data):1986 return msave(self, **data)1987 1988 @jsaction(_('Remove selected courses'))1989 def delCourses(self, **data):1990 delSubobjects(1991 self, redirect='@@manage', tab='2', subcontainer='courses')1992 return1993 1994 @jsaction(_('Remove selected certificates'))1995 def delCertificates(self, **data):1996 if not checkPermission('waeup.managePortal', self.context):1997 self.flash(_('You are not allowed to remove certificates.'),1998 type='warning')1999 return2000 delSubobjects(2001 self, redirect='@@manage', tab='3', subcontainer='certificates')2002 return2003 2004 @action(_('Add course'), validator=NullValidator)2005 def addCourse(self, **data):2006 self.redirect(self.url(self.context, 'addcourse'))2007 return2008 2009 @action(_('Add certificate'), validator=NullValidator)2010 def addCertificate(self, **data):2011 self.redirect(self.url(self.context, 'addcertificate'))2012 return2013 2014 @action(_('Cancel'), validator=NullValidator)2015 def cancel(self, **data):2016 self.redirect(self.url(self.context))2017 return2018 2019 @action(_('Add local role'), validator=NullValidator)2020 def addLocalRole(self, **data):2021 return add_local_role(self,4,**data)2022 2023 @action(_('Remove selected local roles'))2024 def delLocalRoles(self, **data):2025 return del_local_roles(self,4,**data)2026 2027 class CourseAddFormPage(KofaAddFormPage):2028 """Add-form to add course to a department.2029 """2030 grok.context(IDepartment)2031 grok.name('addcourse')2032 grok.require('waeup.manageAcademics')2033 label = _(u'Add course')2034 form_fields = grok.AutoFields(ICourse)2035 pnav = 12036 2037 @action(_('Add course'))2038 def addCourse(self, **data):2039 course = createObject(u'waeup.Course')2040 self.applyData(course, **data)2041 try:2042 self.context.courses.addCourse(course)2043 except DuplicationError, error:2044 # signals duplication error2045 entries = error.entries2046 for entry in entries:2047 # do not use error.msg but render a more detailed message instead2048 # and show links to all certs with same code2049 message = _('A course with same code already exists: ')2050 message += '<a href="%s">%s</a>' % (2051 self.url(entry), getattr(entry, '__name__', u'Unnamed'))2052 self.flash(message, type='warning')2053 self.redirect(self.url(self.context, u'@@addcourse'))2054 return2055 message = _(u'Course ${a} successfully created.', mapping = {'a':course.code})2056 self.flash(message)2057 ob_class = self.__implemented__.__name__.replace('waeup.kofa.','')2058 self.context.__parent__.__parent__.__parent__.logger.info(2059 '%s - added: %s' % (ob_class, data['code']))2060 self.redirect(self.url(self.context, u'@@manage')+'#tab2')2061 return2062 2063 @action(_('Cancel'), validator=NullValidator)2064 def cancel(self, **data):2065 self.redirect(self.url(self.context))2066 return2067 2068 class CertificateAddFormPage(KofaAddFormPage):2069 """Add-form to add certificate to a department.2070 """2071 grok.context(IDepartment)2072 grok.name('addcertificate')2073 grok.require('waeup.manageAcademics')2074 label = _(u'Add certificate')2075 form_fields = grok.AutoFields(ICertificate)2076 pnav = 12077 2078 @action(_('Add certificate'))2079 def addCertificate(self, **data):2080 certificate = createObject(u'waeup.Certificate')2081 self.applyData(certificate, **data)2082 try:2083 self.context.certificates.addCertificate(certificate)2084 except DuplicationError, error:2085 # signals duplication error2086 entries = error.entries2087 for entry in entries:2088 # do not use error.msg but render a more detailed message instead2089 # and show links to all certs with same code2090 message = _('A certificate with same code already exists: ')2091 message += '<a href="%s">%s</a>' % (2092 self.url(entry), getattr(entry, '__name__', u'Unnamed'))2093 self.flash(message, type='warning')2094 self.redirect(self.url(self.context, u'@@addcertificate'))2095 return2096 message = _(u'Certificate ${a} successfully created.', mapping = {'a':certificate.code})2097 self.flash(message)2098 ob_class = self.__implemented__.__name__.replace('waeup.kofa.','')2099 self.context.__parent__.__parent__.__parent__.logger.info(2100 '%s - added: %s' % (ob_class, data['code']))2101 self.redirect(self.url(self.context, u'@@manage')+'#tab3')2102 return2103 2104 @action(_('Cancel'), validator=NullValidator)2105 def cancel(self): #, **data):2106 self.redirect(self.url(self.context))2107 return2108 2109 #2110 # Courses pages2111 #2112 class CoursePage(KofaDisplayFormPage):2113 """Course index page.2114 """2115 grok.context(ICourse)2116 grok.name('index')2117 grok.require('waeup.viewAcademics')2118 pnav = 12119 form_fields = grok.AutoFields(ICourse)2120 2121 @property2122 def label(self):2123 return '%s (%s)' % (self.context.title, self.context.code)2124 2125 class CourseManageFormPage(KofaEditFormPage,2126 LocalRoleAssignmentUtilityView):2127 """Edit form page for courses.2128 """2129 grok.context(ICourse)2130 grok.name('manage')2131 grok.require('waeup.manageAcademics')2132 grok.template('coursemanagepage')2133 label = _(u'Edit course')2134 pnav = 12135 taboneactions = [_('Save'),_('Cancel')]2136 tabtwoactions1 = [_('Remove selected local roles')]2137 tabtwoactions2 = [_('Add local role')]2138 2139 form_fields = grok.AutoFields(ICourse).omit('code')2140 2141 @action(_('Save'), style='primary')2142 def save(self, **data):2143 return msave(self, **data)2144 2145 @action(_('Cancel'), validator=NullValidator)2146 def cancel(self, **data):2147 self.redirect(self.url(self.context))2148 return2149 2150 @action(_('Add local role'), validator=NullValidator)2151 def addLocalRole(self, **data):2152 return add_local_role(self,2,**data)2153 2154 @action(_('Remove selected local roles'))2155 def delLocalRoles(self, **data):2156 return del_local_roles(self,2,**data)2157 2158 #2159 # Certificate pages2160 #2161 class CertificatePage(KofaDisplayFormPage):2162 """Index page for certificates.2163 """2164 grok.context(ICertificate)2165 grok.name('index')2166 grok.require('waeup.viewAcademics')2167 pnav = 12168 form_fields = grok.AutoFields(ICertificate)2169 grok.template('certificatepage')2170 2171 @property2172 def label(self):2173 return "%s (%s)" % (self.context.title, self.context.code)2174 2175 def update(self):2176 return super(CertificatePage, self).update()2177 2178 class CertificateManageFormPage(KofaEditFormPage,2179 LocalRoleAssignmentUtilityView):2180 """Manage the properties of a `Certificate` instance.2181 """2182 grok.context(ICertificate)2183 grok.name('manage')2184 grok.require('waeup.manageAcademics')2185 pnav = 12186 label = _('Edit certificate')2187 2188 form_fields = grok.AutoFields(ICertificate).omit('code')2189 2190 pnav = 12191 grok.template('certificatemanagepage')2192 taboneactions = [_('Save'),_('Cancel')]2193 tabtwoactions = [_('Add certificate course'),2194 _('Remove selected certificate courses'),_('Cancel')]2195 tabthreeactions1 = [_('Remove selected local roles')]2196 tabthreeactions2 = [_('Add local role')]2197 2198 @property2199 def label(self):2200 return _('Manage certificate')2201 2202 @action(_('Save'), style='primary')2203 def save(self, **data):2204 return msave(self, **data)2205 2206 @jsaction(_('Remove selected certificate courses'))2207 def delCertificateCourses(self, **data):2208 delSubobjects(self, redirect='@@manage', tab='2')2209 return2210 2211 @action(_('Add certificate course'), validator=NullValidator)2212 def addCertificateCourse(self, **data):2213 self.redirect(self.url(self.context, 'addcertificatecourse'))2214 return2215 2216 @action(_('Cancel'), validator=NullValidator)2217 def cancel(self, **data):2218 self.redirect(self.url(self.context))2219 return2220 2221 @action(_('Add local role'), validator=NullValidator)2222 def addLocalRole(self, **data):2223 return add_local_role(self,3,**data)2224 2225 @action(_('Remove selected local roles'))2226 def delLocalRoles(self, **data):2227 return del_local_roles(self,3,**data)2228 2229 2230 class CertificateCourseAddFormPage(KofaAddFormPage):2231 """Add-page to add a course ref to a certificate2232 """2233 grok.context(ICertificate)2234 grok.name('addcertificatecourse')2235 grok.require('waeup.manageAcademics')2236 form_fields = grok.AutoFields(ICertificateCourse)2237 pnav = 12238 label = _('Add certificate course')2239 2240 @action(_('Add certificate course'))2241 def addCertcourse(self, **data):2242 try:2243 self.context.addCertCourse(**data)2244 except KeyError:2245 self.status = self.flash(_('The chosen certificate course is already '2246 'part of this certificate.'), type='warning')2247 return2248 self.status = self.flash(2249 _("certificate course ${a}_${b} added.",2250 mapping = {'a': data['course'].code, 'b': data['level']}))2251 code = "%s_%s" % (data['course'].code, data['level'])2252 ob_class = self.__implemented__.__name__.replace('waeup.kofa.','')2253 grok.getSite().logger.info('%s - added: %s' % (ob_class, code))2254 self.redirect(self.url(self.context, u'@@manage')+'#tab2')2255 return2256 2257 @action(_('Cancel'), validator=NullValidator)2258 def cancel(self, **data):2259 self.redirect(self.url(self.context))2260 return2261 2262 2263 #2264 # Certificate course pages...2265 #2266 class CertificateCoursePage(KofaPage):2267 """CertificateCourse index page.2268 """2269 grok.context(ICertificateCourse)2270 grok.name('index')2271 grok.require('waeup.viewAcademics')2272 pnav = 12273 #form_fields = grok.AutoFields(ICertificateCourse)2274 2275 @property2276 def label(self):2277 return '%s' % (self.context.longtitle)2278 2279 @property2280 def leveltitle(self):2281 return course_levels.getTerm(self.context.level).title2282 2283 class CertificateCourseManageFormPage(KofaEditFormPage):2284 """Manage the basic properties of a `CertificateCourse` instance.2285 """2286 grok.context(ICertificateCourse)2287 grok.name('manage')2288 grok.require('waeup.manageAcademics')2289 form_fields = grok.AutoFields(ICertificateCourse).omit('code')2290 label = _('Edit certificate course')2291 pnav = 12292 2293 @action(_('Save and return'), style='primary')2294 def saveAndReturn(self, **data):2295 parent = self.context.__parent__2296 if self.context.level == data['level']:2297 msave(self, **data)2298 else:2299 # The level changed. We have to create a new certcourse as2300 # the key of the entry will change as well...2301 old_level = self.context.level2302 data['course'] = self.context.course2303 parent.addCertCourse(**data)2304 parent.delCertCourses(data['course'].code, level=old_level)2305 self.flash(_('Form has been saved.'))2306 old_code = "%s_%s" % (data['course'].code, old_level)2307 new_code = "%s_%s" % (data['course'].code, data['level'])2308 ob_class = self.__implemented__.__name__.replace('waeup.kofa.','')2309 grok.getSite().logger.info(2310 '%s - renamed: %s to %s' % (ob_class, old_code, new_code))2311 self.redirect(self.url(parent))2312 return2313 2314 @action(_('Cancel'), validator=NullValidator)2315 def cancel(self, **data):2316 self.redirect(self.url(self.context))2317 return2318 2319 1567 class ChangePasswordRequestPage(KofaForm): 2320 1568 """Captcha'd page for all kind of users to request a password change. … … 2335 1583 2336 1584 def _searchUser(self, identifier, email): 2337 # Search student2338 cat = queryUtility(ICatalog, name='students_catalog')2339 results = cat.searchResults(1585 # Search customer 1586 #cat = queryUtility(ICatalog, name='customers_catalog') 1587 #results = cat.searchResults( 2340 1588 #reg_number=(identifier, identifier), 2341 email=(email,email)) 2342 for result in results: 2343 if result.student_id == identifier or \ 2344 result.reg_number == identifier or \ 2345 result.matric_number == identifier: 2346 return result 2347 # Search applicant 2348 cat = queryUtility(ICatalog, name='applicants_catalog') 2349 if cat is not None: 2350 results = cat.searchResults( 2351 #reg_number=(identifier, identifier), 2352 email=(email,email)) 2353 for result in results: 2354 if result.applicant_id == identifier or \ 2355 result.reg_number == identifier: 2356 return result 1589 # email=(email,email)) 1590 #for result in results: 1591 # if result.student_id == identifier or \ 1592 # result.reg_number == identifier or \ 1593 # result.matric_number == identifier: 1594 # return result 2357 1595 # Search portal user 2358 1596 user = grok.getSite()['users'].get(identifier, None) … … 2367 1605 # No need to flash something. 2368 1606 return 2369 # Search student or applicant1607 # Search customer 2370 1608 identifier = data['identifier'] 2371 1609 email = data['email'] -
main/waeup.kofa/branches/henrik-regista/src/waeup/kofa/browser/pdf.py
r10595 r11947 566 566 567 567 @classmethod 568 def _addCourse(cls, table_data, row_num, course_label, course_link,569 lang, domain):570 """Add course data to `table_data`.571 """572 if not course_label or not course_link:573 return table_data, row_num574 f_label= translate(575 _(course_label), domain, target_language=lang)576 f_label = Paragraph(f_label, ENTRY1_STYLE)577 f_text = Paragraph(course_link, ENTRY1_STYLE)578 table_data.append([f_label, f_text])579 row_num += 1580 return table_data, row_num581 582 @classmethod583 def _addDeptAndFaculty(cls, table_data, row_num, dept, faculty,584 lang, domain):585 """Add `dept` and `faculty` as table rows to `table_data`.586 587 `dept` and `faculty` are expected to be strings or None. In588 latter case they are not put into the table.589 """590 for label, text in (('Department:', dept), ('Faculty:', faculty)):591 if text is None:592 continue593 label = translate(_(label), domain, target_language=lang)594 table_data.append([595 Paragraph(label, ENTRY1_STYLE),596 Paragraph(text, ENTRY1_STYLE)])597 row_num += 1598 return table_data, row_num599 600 @classmethod601 568 def _drawSignatureBoxes(cls, canvas, width, height, signatures=[]): 602 569 """Draw signature boxes into canvas. … … 661 628 def getWidgetsTable(self, form_fields, context, view, lang='en', 662 629 domain='waeup.kofa', separators=None, 663 course_label=None, course_link=None, dept=None, 664 faculty=None, colWidths=None, twoDataCols=False): 630 colWidths=None, twoDataCols=False): 665 631 """Return a reportlab `Table` instance, created from widgets 666 632 determined by `form_fields` and `context`. … … 679 645 - `separators` 680 646 a list of separators. 681 - `course_label` and `course_link`682 if a course should be added to the table, `course_label`683 and `course_link` can be given, both being strings. They684 will be rendered in an extra-row.685 - `dept` and `faculty`686 if these are given, we render extra rows with faculty and687 department.688 647 - `colWidths` 689 648 defines the the column widths of the data in the right column … … 699 658 table_data, row_num = self._getWidgetsTableData( 700 659 widgets, separators, domain, lang, twoDataCols) 701 702 # Add course (admitted, etc.) if applicable703 table_data, row_num = self._addCourse(704 table_data, row_num, course_label, course_link, lang, domain,)705 706 ## Add dept. and faculty if applicable707 table_data, row_num = self._addDeptAndFaculty(708 table_data, row_num, dept, faculty, lang, domain)709 660 710 661 # render two-column table of tables if applicable -
main/waeup.kofa/branches/henrik-regista/src/waeup/kofa/browser/templates/datacenterexportpage.pt
r11826 r11947 34 34 </div> 35 35 </form> 36 37 <br />38 39 <p i18n:translate="">40 Student data exports have to be further configured. You can create CSV files41 on the <a href="@@exportconfig">student data export configuration page</a>.42 </p>43 36 44 37 <br /><br /> -
main/waeup.kofa/branches/henrik-regista/src/waeup/kofa/browser/templates/default_waeup_edit_form.pt
r7737 r11947 5 5 <tbody> 6 6 <tal:widgets content="structure provider:widgets" /> 7 <tal:files content="structure provider:files" />8 7 </tbody> 9 8 </table> -
main/waeup.kofa/branches/henrik-regista/src/waeup/kofa/browser/templates/staffsitelayout.pt
r11463 r11947 73 73 74 74 <!-- Diazo element--> 75 <span tal:condition="layout/getStudentName">76 <div class="wfstatus">77 <span tal:replace="python:context.student.student_id">78 Id79 </span>80 •81 <span tal:replace="python:context.student.translated_state">82 State83 </span>84 </div>85 </span>86 <!-- /Diazo element-->87 88 <!-- Diazo element-->89 75 <div class="sidebar well"> 90 <div tal:condition="layout/getStudentName">91 <div class="kofa-sidebar-title" tal:content="layout/getStudentName">STUDENTNAME</div>92 <ul class="nav">93 <tal:left content="structure provider:left_studentmanage" />94 </ul>95 </div>96 76 <div tal:condition="layout/isAuthenticated"> 97 77 <div class="kofa-sidebar-title" tal:content="layout/getUserTitle">USERNAME</div> -
main/waeup.kofa/branches/henrik-regista/src/waeup/kofa/browser/templates/studentsitelayout.pt
r11463 r11947 30 30 <ul class="nav kofa-navbar-left"> 31 31 <tal:primary_nav content="structure provider:primary_nav" /> 32 <tal:primary_nav content="structure provider:primary_nav_student" />33 32 </ul> 34 33 <!-- /Diazo element--> … … 72 71 73 72 <!-- Diazo element--> 74 <span tal:condition="layout/getStudentName">75 <div class="wfstatus">76 <span tal:replace="python:context.student.student_id">77 Id78 </span>79 •80 <span tal:replace="python:context.student.translated_state">81 State82 </span>83 </div>84 </span>85 <!-- /Diazo element-->86 87 <!-- Diazo element-->88 73 <div class="kofa-content"> 89 74 <div class="actionbar" tal:condition="provider:actionbar"> -
main/waeup.kofa/branches/henrik-regista/src/waeup/kofa/browser/templates/usereditformpage.pt
r11254 r11947 18 18 </td> 19 19 </tr> 20 <tal:files content="structure provider:files" />21 20 </tbody> 22 21 </table> -
main/waeup.kofa/branches/henrik-regista/src/waeup/kofa/browser/tests/test_permissions.py
r8920 r11947 38 38 manager_pages = [ 39 39 # The pages that should only be accessible by manager... 40 '/@@manage', '/@@administration', '/faculties/@@search',40 '/@@manage', '/@@administration', 41 41 '/users/@@index', '/users/@@add', '/users/alice/@@manage', 42 42 '/datacenter/@@index', '/datacenter/@@upload', '/datacenter/@@import1', 43 43 '/datacenter/@@import2', '/datacenter/@@import3', '/datacenter/@@import4', 44 44 '/datacenter/@@logs', '/datacenter/@@show', '/datacenter/@@manage', 45 '/faculties/@@index', '/faculties/@@add', '/faculties/@@manage',46 '/faculties/fac1/@@index', '/faculties/fac1/@@manage',47 '/faculties/fac1/@@add',48 '/faculties/fac1/dept1/@@index',49 '/faculties/fac1/dept1/@@manage',50 '/faculties/fac1/dept1/@@addcourse',51 '/faculties/fac1/dept1/@@addcertificate',52 '/faculties/fac1/dept1/courses/crs1/@@index',53 '/faculties/fac1/dept1/courses/crs1/@@manage',54 '/faculties/fac1/dept1/certificates/cert1/@@index',55 '/faculties/fac1/dept1/certificates/cert1/@@manage',56 '/faculties/fac1/dept1/certificates/cert1/@@addcertificatecourse',57 '/faculties/fac1/dept1/certificates/cert1/crs1_100/@@index',58 '/faculties/fac1/dept1/certificates/cert1/crs1_100/@@manage',59 45 ] 60 46 public_pages = [ … … 79 65 app['datacenter'].setStoragePath(self.dc_root) 80 66 app['users'].addUser('alice', 'alice') 81 fac1 = createObject('waeup.Faculty')82 fac1.code = "fac1"83 app['faculties'].addFaculty(fac1)84 dept = createObject('waeup.Department')85 dept.code = 'dept1'86 fac1.addDepartment(dept)87 course = createObject('waeup.Course')88 course.code = 'crs1'89 dept.courses.addCourse(course)90 cert = createObject('waeup.Certificate')91 cert.code = 'cert1'92 dept.certificates.addCertificate(cert)93 cert.addCertCourse(course)94 67 95 68 self.browser = Browser() -
main/waeup.kofa/branches/henrik-regista/src/waeup/kofa/browser/viewlets.py
r11862 r11947 24 24 from zope.traversing.browser import absoluteURL 25 25 from waeup.kofa.browser.pages import ( 26 UniversityPage, FacultiesContainerPage, DatacenterPage, FacultyPage, 27 DepartmentPage, CoursePage, CertificatePage, CertificateCoursePage, 26 UniversityPage, DatacenterPage, 28 27 UsersContainerPage, UserManageFormPage) 29 28 from waeup.kofa.browser.interfaces import ( 30 IFacultiesContainer, IFaculty, IDepartment, ICourse, ICertificate, 31 ICertificateCourse, IBreadcrumbContainer, IUniversity, IUsersContainer) 29 IBreadcrumbContainer, IUniversity, IUsersContainer) 32 30 from waeup.kofa.interfaces import ( 33 31 IKofaUtils, IKofaObject, IKofaXMLExporter, … … 399 397 grok.order(1) 400 398 401 class ManageFacultiesContainerActionButton(ManageActionButton):402 """ 'Manage settings' button for faculties.403 """404 grok.context(IFacultiesContainer)405 grok.view(FacultiesContainerPage)406 text = _('Manage academic section')407 408 class ExportFacultiesStudentsActionButton(ManageActionButton):409 """ 'Export student data' button for faculties.410 """411 grok.context(IFacultiesContainer)412 grok.view(FacultiesContainerPage)413 grok.name('exportfacultystudents')414 grok.require('waeup.showStudents')415 icon = 'actionicon_down.png'416 text = _('Export student data')417 target = 'exports'418 grok.order(3)419 420 class SearchFacultiesContainerActionButton(ManageActionButton):421 """ 'Manage settings' button for faculties.422 """423 grok.context(IFacultiesContainer)424 grok.view(FacultiesContainerPage)425 text = _('Search academic section')426 icon = 'actionicon_search.png'427 target = '@@search'428 429 class ManageFacultyActionButton(ManageActionButton):430 """ 'Manage settings' button for faculties.431 """432 grok.context(IFaculty)433 grok.view(FacultyPage)434 text = _('Manage faculty')435 436 class StudentSearchActionButton(ManageActionButton):437 grok.order(2)438 grok.context(IFaculty)439 grok.view(FacultyPage)440 grok.name('findstudents')441 grok.require('waeup.showStudents')442 text = _('Find students')443 icon = 'actionicon_search.png'444 target = 'find_students'445 446 class ManageDepartmentActionButton(ManageActionButton):447 """ 'Manage settings' button for departments.448 """449 grok.context(IDepartment)450 grok.view(DepartmentPage)451 text = _('Manage department')452 grok.order(1)453 454 class ShowDepartmentStudentsActionButton(ManageActionButton):455 """ 'Show students' button for departments.456 """457 grok.context(IDepartment)458 grok.view(DepartmentPage)459 grok.name('showdepartmentstudents')460 grok.require('waeup.showStudents')461 icon = 'actionicon_student.png'462 text = _('Show students')463 target = 'students'464 grok.order(2)465 466 class ExportDepartmentStudentsActionButton(ManageActionButton):467 """ 'Export student data' button for departments.468 """469 grok.context(IDepartment)470 grok.view(DepartmentPage)471 grok.name('exportdepartmentstudents')472 grok.require('waeup.showStudents')473 icon = 'actionicon_down.png'474 text = _('Export student data')475 target = 'exports'476 grok.order(3)477 478 class ClearDepartmentStudentsActionButton(ManageActionButton):479 """ 'Clear all students' button for departments.480 """481 grok.context(IDepartment)482 grok.view(DepartmentPage)483 grok.name('cleardepartmentstudents')484 grok.require('waeup.clearAllStudents')485 icon = 'actionicon_accept.png'486 text = _('Clear all students')487 target = 'clearallstudents'488 grok.order(4)489 490 @property491 def onclick(self):492 return "return window.confirm(%s);" % _(493 "'All students, who requested clearance in this department, will be cleared. Are you sure?'")494 495 class ManageCourseActionButton(ManageActionButton):496 """ 'Edit settings' button for courses.497 """498 grok.context(ICourse)499 grok.view(CoursePage)500 text = _('Edit course')501 grok.order(1)502 503 class ShowCourseStudentsActionButton(ManageActionButton):504 """ 'Show students' button in course.505 """506 grok.context(ICourse)507 grok.view(CoursePage)508 grok.name('showcoursestudents')509 grok.require('waeup.showStudents')510 icon = 'actionicon_student.png'511 text = _('Show students')512 target = 'students'513 grok.order(2)514 515 class ExportCourseStudentsActionButton(ManageActionButton):516 """ 'Export student data' button for courses.517 """518 grok.context(ICourse)519 grok.view(CoursePage)520 grok.name('exportcoursestudents')521 grok.require('waeup.showStudents')522 icon = 'actionicon_down.png'523 text = _('Export student data')524 target = 'exports'525 grok.order(3)526 527 class UpdateScoresActionButton(ManageActionButton):528 """ 'Update scores' button in course.529 """530 grok.context(ICourse)531 grok.view(CoursePage)532 grok.name('updatescores')533 grok.require('waeup.editScores')534 icon = 'actionicon_scores.png'535 text = _('Update scores')536 target = 'edit_scores'537 grok.order(4)538 539 class ManageCertificateActionButton(ManageActionButton):540 """ 'Manage settings' button for certificates.541 """542 grok.context(ICertificate)543 grok.view(CertificatePage)544 text = _('Manage certificate')545 grok.order(1)546 547 class ShowCertificateStudentsActionButton(ManageActionButton):548 """ 'Show students' button for certificates.549 """550 grok.context(ICertificate)551 grok.view(CertificatePage)552 grok.name('showcertificatestudents')553 grok.require('waeup.showStudents')554 icon = 'actionicon_student.png'555 text = _('Show students')556 target = 'students'557 grok.order(2)558 559 class ExportCertificateStudentsActionButton(ManageActionButton):560 """ 'Export student data' button for certificates.561 """562 grok.context(ICertificate)563 grok.view(CertificatePage)564 grok.name('exportcertificatestudents')565 grok.require('waeup.showStudents')566 icon = 'actionicon_down.png'567 text = _('Export student data')568 target = 'exports'569 grok.order(3)570 571 class ManageCertificateCourseActionButton(ManageActionButton):572 """ 'Manage settings' button for certificate courses.573 """574 grok.context(ICertificateCourse)575 grok.view(CertificateCoursePage)576 text = _('Edit certificate course')577 578 399 class AddUserActionButton(AddActionButton): 579 400 grok.require('waeup.manageUsers') … … 676 497 # tab_title = u'Home' 677 498 678 class FacultiesTab(PrimaryNavTab): 679 """Faculties-tab in primary navigation. 680 """ 681 grok.order(2) 682 grok.require('waeup.viewAcademics') 683 684 pnav = 1 685 tab_title = _(u'Academics') 686 687 @property 688 def link_target(self): 689 return self.view.application_url('faculties') 690 691 499 692 500 class EnquiriesTab(PrimaryNavTab): 693 501 """Contact tab in primary navigation. … … 793 601 super(SubobjectLister, self).update() 794 602 return 795 796 797 class FacultiesContainerListHead(grok.Viewlet):798 """The header line of faculty container subobject lists.799 """800 grok.order(1)801 grok.viewletmanager(SubobjectLister)802 grok.context(IFacultiesContainer)803 grok.require('waeup.viewAcademics')804 805 def render(self):806 return u'<th>Code</th><th>Title</th><th></th>'807 808 class FacultyListName(grok.Viewlet):809 """Display a the title of a faculty as link in a list.810 """811 grok.order(1)812 grok.viewletmanager(SubobjectLister)813 grok.context(IFaculty)814 grok.require('waeup.viewAcademics')815 816 def render(self):817 return u'<a href="%s">%s</a>' % (818 self.view.url(self.context), self.context.__name__)819 820 class FacultyListTitle(grok.Viewlet):821 """Display the title of a faculty in a list.822 """823 grok.order(2)824 grok.viewletmanager(SubobjectLister)825 grok.context(IFaculty)826 grok.require('waeup.viewAcademics')827 828 def render(self):829 return self.context.title830 831 class FacultyRemoveButton(grok.Viewlet):832 """Render a remove button for faculty lists.833 """834 grok.order(3)835 grok.viewletmanager(SubobjectLister)836 grok.context(IFaculty)837 grok.require('waeup.manageAcademics')838 839 def render(self):840 return u'<div class="text-right"><form method="POST">' + \841 '<input class="text-right" type="submit" value="remove" />' + \842 '</form></div>' -
main/waeup.kofa/branches/henrik-regista/src/waeup/kofa/configuration.py
r11477 r11947 24 24 from waeup.kofa.interfaces import ( 25 25 ISessionConfiguration, IConfigurationContainer, ISessionConfigurationAdd, 26 a cademic_sessions_vocab)26 application_sessions_vocab) 27 27 from waeup.kofa.utils.helpers import attrs_to_fields 28 28 … … 41 41 'ConfigurationContainers contain only ' 42 42 'ISessionConfiguration instances') 43 code = unicode(sessionconfiguration.a cademic_session)43 code = unicode(sessionconfiguration.application_session) 44 44 self[code] = sessionconfiguration 45 45 return … … 55 55 56 56 def getSessionString(self): 57 return a cademic_sessions_vocab.getTerm(self.academic_session).title57 return application_sessions_vocab.getTerm(self.application_session).title 58 58 59 59 SessionConfiguration = attrs_to_fields(SessionConfiguration) -
main/waeup.kofa/branches/henrik-regista/src/waeup/kofa/imagestorage.py
r11480 r11947 20 20 A few words about storing files with ``waeup.kofa``. The need for this 21 21 feature arised initially from the need to store passport files for 22 applicants and students. These files are dynamic (can be changed22 customers. These files are dynamic (can be changed 23 23 anytime), mean a lot of traffic and cost a lot of memory/disk space. 24 24 … … 97 97 98 98 The file store supports special handling for certain files. For 99 example we want applicantimages to be stored in a different directory100 than studentimages, etc. Because the file store cannot know all99 example we want some customer images to be stored in a different directory 100 than other customer images, etc. Because the file store cannot know all 101 101 details about these special treatment of certain files, it looks up 102 102 helpers (handlers) to provide the information it needs for really … … 120 120 121 121 Examples for such a file store handler can be found in the 122 :mod:`waeup.kofa. applicants.applicant` module. Please see also the122 :mod:`waeup.kofa.customers.customer` module. Please see also the 123 123 :class:`DefaultFileStoreHandler` class below for more details. 124 124 … … 169 169 170 170 Often the internal filename or file id of a file depends on a 171 context. For example when we store passport photographs of applicants,172 then each image belongs to a certain applicantinstance. It is not173 difficult to maintain such a connection manually: Say every applicant171 context. For example when we store passport photographs of customers, 172 then each image belongs to a certain customer instance. It is not 173 difficult to maintain such a connection manually: Say every customer 174 174 had an id, then we could put this id into the filename as well and 175 175 would build the filename to store/get the connected file by using that 176 176 filename. You then would create filenames of a format like this:: 177 177 178 __<MARKER-STRING>__ applicant0001179 180 where `` applicant0001`` would tell exactly which applicantyou can see178 __<MARKER-STRING>__customer0001 179 180 where ``customer0001`` would tell exactly which customer you can see 181 181 on the photograph. You notice that the internal file id might have 182 182 nothing to do with once uploaded filenames. The id above could have -
main/waeup.kofa/branches/henrik-regista/src/waeup/kofa/interfaces.py
r11804 r11947 84 84 SimpleTerm(value, value, title) for title, value in terms]) 85 85 86 def a cademic_sessions():86 def application_sessions(): 87 87 curr_year = datetime.now().year 88 88 year_range = range(1995, curr_year + 2) 89 89 return [('%s/%s' % (year,year+1), year) for year in year_range] 90 90 91 a cademic_sessions_vocab = SimpleKofaVocabulary(*academic_sessions())91 application_sessions_vocab = SimpleKofaVocabulary(*application_sessions()) 92 92 93 93 registration_states_vocab = SimpleKofaVocabulary( … … 145 145 return dict(getUtility(IKofaUtils).EXAM_GRADES)[value] 146 146 147 class DisablePaymentGroupSource(ContextualDictSourceFactoryBase):148 """A source for filtering groups of students149 """150 #: name of dict to deliver from kofa utils.151 DICT_NAME = 'DISABLE_PAYMENT_GROUP_DICT'152 153 147 # Define a validation method for email addresses 154 148 class NotAnEmailAddress(schema.ValidationError): … … 278 272 """Send credentials as email. 279 273 280 Input is the applicantfor which credentials are sent and the274 Input is the customer for which credentials are sent and the 281 275 password. 282 276 … … 531 525 title = _(u'Public Name'), 532 526 description = u"Substitute for officer's real name " 533 "in studentobject histories.",527 "in object histories.", 534 528 required = False,) 535 529 … … 655 649 ) 656 650 657 carry_over = schema.Bool(658 title = _(u'Carry-over Course Registration'),659 default = False,660 )661 662 current_academic_session = schema.Choice(663 title = _(u'Current Academic Session'),664 description = _(u'Session for which score editing is allowed'),665 source = academic_sessions_vocab,666 default = None,667 required = False,668 readonly = False,669 )670 671 next_matric_integer = schema.Int(672 title = _(u'Next Matriculation Number Integer'),673 description = _(u'Integer used for constructing the next '674 'matriculation number'),675 default = 0,676 readonly = False,677 required = False,678 )679 651 680 652 class ISessionConfiguration(IKofaObject): … … 682 654 """ 683 655 684 a cademic_session = schema.Choice(685 title = _(u' Academic Session'),686 source = a cademic_sessions_vocab,656 application_session = schema.Choice( 657 title = _(u'Period'), 658 source = application_sessions_vocab, 687 659 default = None, 688 660 required = True, … … 690 662 ) 691 663 692 application_fee = schema.Float(693 title = _(u'Application Fee'),694 default = 0.0,695 required = False,696 )697 698 clearance_fee = schema.Float(699 title = _(u'Acceptance Fee'),700 default = 0.0,701 required = False,702 )703 704 booking_fee = schema.Float(705 title = _(u'Bed Booking Fee'),706 default = 0.0,707 required = False,708 )709 710 maint_fee = schema.Float(711 title = _(u'Rent (fallback)'),712 default = 0.0,713 required = False,714 )715 716 transcript_fee = schema.Float(717 title = _(u'Transcript Fee'),718 default = 0.0,719 required = False,720 )721 722 clearance_enabled = schema.Bool(723 title = _(u'Clearance enabled'),724 default = False,725 )726 727 payment_disabled = schema.List(728 title = _(u'Payment disabled'),729 value_type = schema.Choice(730 source = DisablePaymentGroupSource(),731 ),732 required = False,733 default = [],734 )735 664 736 665 def getSessionString(): … … 743 672 """ 744 673 745 a cademic_session = schema.Choice(674 application_session = schema.Choice( 746 675 title = _(u'Academic Session'), 747 source = a cademic_sessions_vocab,676 source = application_sessions_vocab, 748 677 default = None, 749 678 required = True, … … 751 680 ) 752 681 753 ISessionConfigurationAdd['a cademic_session'].order = ISessionConfiguration[754 'a cademic_session'].order682 ISessionConfigurationAdd['application_session'].order = ISessionConfiguration[ 683 'application_session'].order 755 684 756 685 class IDataCenter(IKofaObject): … … 873 802 needing to know about that parts. The site simply collects all 874 803 available plugins, calls them and the plugins care for their 875 respective subarea like the applicants area or the datacenter804 respective subarea like the cutomers area or the datacenter 876 805 area. 877 806 … … 1112 1041 interpret `attr` as a hint for what type of file for a given 1113 1042 context should be stored if there are several types 1114 possible. For instance for a certain studentsome file could1043 possible. For instance for a certain customer some file could 1115 1044 be the connected passport photograph or some certificate scan 1116 1045 or whatever. Each of them has to be stored in a different -
main/waeup.kofa/branches/henrik-regista/src/waeup/kofa/mandates/container.py
r8910 r11947 56 56 def setup(self, site, name, logger): 57 57 if 'mandates' in site.keys(): 58 logger.warn('Could not create container for faculties in Kofa.')58 logger.warn('Could not create container for mandates in Kofa.') 59 59 return 60 60 site['mandates'] = MandatesContainer() -
main/waeup.kofa/branches/henrik-regista/src/waeup/kofa/mandates/tests.py
r11681 r11947 85 85 shutil.rmtree(self.dc_root) 86 86 87 def test_set_student_password(self):87 def xx_test_set_student_password(self): 88 88 student = createObject('waeup.Student') 89 89 # Add and execute a mandate with missing parameters. … … 129 129 self.assertTrue('system - PasswordMandate used: bob' in logcontent) 130 130 131 def test_set_applicant_password(self):132 applicant = createObject('waeup.Applicant')133 applicant.applicant_id = u'abc'134 mandate = PasswordMandate()135 mandate.params['user'] = applicant136 mandate.params['password'] = 'mypwd1'137 self.app['mandates'].addMandate(mandate)138 msg = mandate.execute()139 # Password has been set.140 self.assertEqual(msg, 'Password has been successfully set. Login with your new password.')141 self.assertTrue(IUserAccount(applicant).checkPassword('mypwd1'))142 logfile = os.path.join(143 self.app['datacenter'].storage, 'logs', 'main.log')144 logcontent = open(logfile).read()145 self.assertTrue('system - PasswordMandate used: abc' in logcontent)146 147 131 def test_remove_expired(self): 148 132 # mandate1 is an old mandate which just expired. … … 159 143 self.assertEqual([i for i in self.app['mandates'].keys()], [u'23456']) 160 144 161 def test_browser(self):145 def xx_test_browser(self): 162 146 student = createObject('waeup.Student') 163 147 self.app['students'].addStudent(student) -
main/waeup.kofa/branches/henrik-regista/src/waeup/kofa/payments/interfaces.py
r11450 r11947 19 19 from zope import schema 20 20 from waeup.kofa.interfaces import ( 21 IKofaObject, SimpleKofaVocabulary, a cademic_sessions_vocab,21 IKofaObject, SimpleKofaVocabulary, application_sessions_vocab, 22 22 ContextualDictSourceFactoryBase) 23 23 from waeup.kofa.interfaces import MessageFactory as _ … … 68 68 p_session = schema.Choice( 69 69 title = _(u'Payment Session'), 70 source = a cademic_sessions_vocab,70 source = application_sessions_vocab, 71 71 required = True, 72 72 ) … … 133 133 def approve(): 134 134 "Approve an online payment and set to paid." 135 136 class IPayer(IKofaObject):137 """An interface for an adapter to publish student and applicant data138 through a simple webservice.139 140 """141 display_fullname = Attribute('Name of payer')142 id = Attribute('Id of payer')143 reg_number = Attribute('Reg number of payer')144 matric_number = Attribute('Matric number of payer')145 faculty = Attribute('Faculty of payer')146 department = Attribute('Department of payer')147 email= Attribute('Email of payer')148 phone= Attribute('Phone number of payer')149 current_mode= Attribute('Current study mode of payer')150 current_level= Attribute('Current level of payer') -
main/waeup.kofa/branches/henrik-regista/src/waeup/kofa/permissions.py
r11862 r11947 44 44 grok.name('waeup.Authenticated') 45 45 46 class View AcademicsPermission(grok.Permission):47 grok.name('waeup.view Academics')48 49 class Manage AcademicsPermission(grok.Permission):50 grok.name('waeup.manage Academics')46 class ViewProductsPermission(grok.Permission): 47 grok.name('waeup.viewProducts') 48 49 class ManageProductsPermission(grok.Permission): 50 grok.name('waeup.manageProducts') 51 51 52 52 class ManagePortal(grok.Permission): … … 56 56 grok.name('waeup.manageUsers') 57 57 58 class ShowStudents(grok.Permission):59 grok.name('waeup.showStudents')60 61 class ClearAllStudents(grok.Permission):62 grok.name('waeup.clearAllStudents')63 64 class EditScores(grok.Permission):65 grok.name('waeup.editScores')66 67 58 class EditUser(grok.Permission): 68 59 grok.name('waeup.editUser') … … 104 95 105 96 # Local Roles 106 class ApplicationsManager(grok.Role):107 grok.name('waeup.local.ApplicationsManager')108 grok.title(u'Applications Manager')109 grok.permissions('waeup.viewAcademics')110 111 class DepartmentManager(grok.Role):112 grok.name('waeup.local.DepartmentManager')113 grok.title(u'Department Manager')114 grok.permissions('waeup.manageAcademics',115 'waeup.showStudents',116 'waeup.exportData')117 118 class DepartmentOfficer(grok.Role):119 grok.name('waeup.local.DepartmentOfficer')120 grok.title(u'Department Officer')121 grok.permissions('waeup.showStudents',122 'waeup.viewAcademics',123 'waeup.exportPaymentsOverview')124 125 class ClearanceOfficer(grok.Role):126 """The clearance officer role is meant for the127 assignment of dynamic roles only.128 """129 grok.name('waeup.local.ClearanceOfficer')130 grok.title(u'Clearance Officer')131 grok.permissions('waeup.showStudents',132 'waeup.viewAcademics',133 'waeup.exportData',134 'waeup.clearAllStudents')135 136 class LocalStudentsManager(grok.Role):137 """The local students manager role is meant for the138 assignment of dynamic roles only.139 """140 grok.name('waeup.local.LocalStudentsManager')141 grok.title(u'Students Manager')142 grok.permissions('waeup.showStudents',143 'waeup.viewAcademics',144 'waeup.exportData')145 146 class LocalWorkflowManager(grok.Role):147 """The local workflow manager role is meant for the148 assignment of dynamic roles only.149 """150 grok.name('waeup.local.LocalWorkflowManager')151 grok.title(u'Student Workflow Manager')152 grok.permissions('waeup.showStudents',153 'waeup.viewAcademics',154 'waeup.exportData')155 156 class UGClearanceOfficer(grok.Role):157 """The clearance officer role is meant for the158 assignment of dynamic roles only.159 """160 grok.name('waeup.local.UGClearanceOfficer')161 grok.title(u'UG Clearance Officer')162 grok.permissions('waeup.showStudents',163 'waeup.viewAcademics',164 'waeup.exportData',165 'waeup.clearAllStudents')166 167 class PGClearanceOfficer(grok.Role):168 """The clearance officer role is meant for the169 assignment of dynamic roles only.170 """171 grok.name('waeup.local.PGClearanceOfficer')172 grok.title(u'PG Clearance Officer')173 grok.permissions('waeup.showStudents',174 'waeup.viewAcademics',175 'waeup.exportData',176 'waeup.clearAllStudents')177 178 class CourseAdviser100(grok.Role):179 """The 100 level course adviser role is meant for the180 assignment of dynamic roles only.181 """182 grok.name('waeup.local.CourseAdviser100')183 grok.title(u'Course Adviser 100L')184 grok.permissions('waeup.showStudents',185 'waeup.viewAcademics',186 'waeup.exportData')187 188 class CourseAdviser200(grok.Role):189 """The course 200 level adviser role is meant for the190 assignment of dynamic roles only.191 """192 grok.name('waeup.local.CourseAdviser200')193 grok.title(u'Course Adviser 200L')194 grok.permissions('waeup.showStudents',195 'waeup.viewAcademics',196 'waeup.exportData')197 198 class CourseAdviser300(grok.Role):199 """The 300 level course adviser role is meant for the200 assignment of dynamic roles only.201 """202 grok.name('waeup.local.CourseAdviser300')203 grok.title(u'Course Adviser 300L')204 grok.permissions('waeup.showStudents',205 'waeup.viewAcademics',206 'waeup.exportData')207 208 class CourseAdviser400(grok.Role):209 """The 400 level course adviser role is meant for the210 assignment of dynamic roles only.211 """212 grok.name('waeup.local.CourseAdviser400')213 grok.title(u'Course Adviser 400L')214 grok.permissions('waeup.showStudents',215 'waeup.viewAcademics',216 'waeup.exportData')217 218 class CourseAdviser500(grok.Role):219 """The 500 level course adviser role is meant for the220 assignment of dynamic roles only.221 """222 grok.name('waeup.local.CourseAdviser500')223 grok.title(u'Course Adviser 500L')224 grok.permissions('waeup.showStudents',225 'waeup.viewAcademics',226 'waeup.exportData')227 228 class CourseAdviser600(grok.Role):229 """The 600 level course adviser role is meant for the230 assignment of dynamic roles only.231 """232 grok.name('waeup.local.CourseAdviser600')233 grok.title(u'Course Adviser 600L')234 grok.permissions('waeup.showStudents',235 'waeup.viewAcademics',236 'waeup.exportData')237 238 class CourseAdviser700(grok.Role):239 """The 700 level course adviser role is meant for the240 assignment of dynamic roles only.241 """242 grok.name('waeup.local.CourseAdviser700')243 grok.title(u'Course Adviser 700L')244 grok.permissions('waeup.showStudents',245 'waeup.viewAcademics',246 'waeup.exportData')247 248 class CourseAdviser800(grok.Role):249 """The 800 level course adviser role is meant for the250 assignment of dynamic roles only.251 """252 grok.name('waeup.local.CourseAdviser800')253 grok.title(u'Course Adviser 800L')254 grok.permissions('waeup.showStudents',255 'waeup.viewAcademics',256 'waeup.exportData')257 258 class Lecturer(grok.Role):259 """The lecturer role is meant for the260 assignment of dynamic roles only.261 """262 grok.name('waeup.local.Lecturer')263 grok.title(u'Lecturer')264 grok.permissions('waeup.showStudents',265 'waeup.editScores',266 'waeup.viewAcademics',267 'waeup.exportData')268 97 269 98 class Owner(grok.Role): … … 273 102 274 103 # Site Roles 275 class AcademicsOfficer(grok.Role): 276 grok.name('waeup.AcademicsOfficer') 277 grok.title(u'Academics Officer (view only)') 278 grok.permissions('waeup.viewAcademics') 279 280 class AcademicsManager(grok.Role): 281 grok.name('waeup.AcademicsManager') 282 grok.title(u'Academics Manager') 283 grok.permissions('waeup.viewAcademics', 284 'waeup.manageAcademics') 285 286 class ACManager(grok.Role): 287 grok.name('waeup.ACManager') 288 grok.title(u'Access Code Manager') 289 grok.permissions('waeup.manageACBatches') 104 class ProductsOfficer(grok.Role): 105 grok.name('waeup.ProductsOfficer') 106 grok.title(u'Products Officer (view only)') 107 grok.permissions('waeup.viewProducts') 108 109 class ProductssManager(grok.Role): 110 grok.name('waeup.ProductsManager') 111 grok.title(u'Products Manager') 112 grok.permissions('waeup.viewProducts', 113 'waeup.manageProducts') 290 114 291 115 class DataCenterManager(grok.Role): … … 306 130 'waeup.exportData') 307 131 308 class BursaryOfficer(grok.Role):309 grok.name('waeup.BursaryOfficer')310 grok.title(u'Bursary Officer')311 grok.permissions('waeup.showStudents',312 'waeup.viewAcademics',313 'waeup.exportBursaryData')314 315 132 class UsersManager(grok.Role): 316 133 grok.name('waeup.UsersManager') … … 329 146 grok.permissions('waeup.managePortal', 330 147 'waeup.manageUsers', 331 'waeup.view Academics', 'waeup.manageAcademics',148 'waeup.viewProducts', 'waeup.manageProducts', 332 149 'waeup.manageACBatches', 333 150 'waeup.manageDataCenter', … … 335 152 'waeup.exportData', 336 153 'waeup.viewTranscript', 337 'waeup.managePortalConfiguration', 'waeup.viewApplication', 338 'waeup.manageApplication', 'waeup.handleApplication', 339 'waeup.viewApplicantsTab', 'waeup.payApplicant', 340 'waeup.viewApplicationStatistics', 341 'waeup.viewStudent', 'waeup.manageStudent', 342 'waeup.clearStudent', 'waeup.payStudent', 343 'waeup.uploadStudentFile', 'waeup.showStudents', 344 'waeup.clearAllStudents', 345 'waeup.editScores', 346 'waeup.triggerTransition', 347 'waeup.viewStudentsContainer','waeup.viewStudentsTab', 348 'waeup.handleAccommodation', 349 'waeup.viewHostels', 'waeup.manageHostels', 154 'waeup.managePortalConfiguration', 350 155 'waeup.editUser', 351 'waeup.loginAsStudent',352 156 'waeup.manageReports', 353 157 'waeup.manageJobs', … … 363 167 grok.permissions(#'waeup.managePortal', 364 168 #'waeup.manageUsers', 365 'waeup.view Academics', 'waeup.manageAcademics',169 'waeup.viewProducts', 'waeup.manageProducts', 366 170 #'waeup.manageACBatches', 367 171 'waeup.manageDataCenter', … … 369 173 'waeup.exportData', 370 174 'waeup.viewTranscript', 371 'waeup.managePortalConfiguration', 'waeup.viewApplication', 372 'waeup.manageApplication', 'waeup.handleApplication', 373 'waeup.viewApplicantsTab', 'waeup.payApplicant', 374 'waeup.viewApplicationStatistics', 375 'waeup.viewStudent', 'waeup.manageStudent', 376 'waeup.clearStudent', 'waeup.payStudent', 377 'waeup.uploadStudentFile', 'waeup.showStudents', 378 'waeup.clearAllStudents', 379 'waeup.editScores', 380 #'waeup.triggerTransition', 381 'waeup.viewStudentsContainer','waeup.viewStudentsTab', 382 'waeup.handleAccommodation', 383 'waeup.viewHostels', 'waeup.manageHostels', 175 'waeup.managePortalConfiguration', 384 176 #'waeup.editUser', 385 #'waeup.loginAsStudent',386 177 'waeup.manageReports', 387 178 #'waeup.manageJobs', -
main/waeup.kofa/branches/henrik-regista/src/waeup/kofa/permissions.txt
r10639 r11947 29 29 30 30 >>> sorted(list(get_all_roles())) 31 [(u'waeup. ACManager', <waeup.kofa.permissions.ACManager object at 0x...]31 [(u'waeup.DataCenterManager', <waeup.kofa.permissions.DataCenterManager object at 0x...] 32 32 33 33 :func:`get_waeup_roles` … … 39 39 >>> from waeup.kofa.permissions import get_waeup_roles 40 40 >>> len(list(get_waeup_roles())) 41 2241 9 42 42 43 43 >>> len(list(get_waeup_roles(also_local=True))) 44 4244 10 45 45 46 46 … … 53 53 >>> from waeup.kofa.permissions import get_waeup_role_names 54 54 >>> list(get_waeup_role_names()) 55 [u'waeup.ACManager', 56 u'waeup.AcademicsManager', 57 u'waeup.AcademicsOfficer', 58 u'waeup.AccommodationOfficer', 59 u'waeup.Applicant', 60 u'waeup.ApplicationsManager', 61 u'waeup.ApplicationsOfficer', 62 u'waeup.BursaryOfficer', 63 u'waeup.DataCenterManager', 64 u'waeup.ExportManager', 65 u'waeup.ImportManager', 66 u'waeup.PortalManager', 67 u'waeup.Student', 68 u'waeup.StudentImpersonator', 69 u'waeup.StudentsClearanceOfficer', 70 u'waeup.StudentsCourseAdviser', 71 u'waeup.StudentsManager', 72 u'waeup.StudentsOfficer', 73 u'waeup.TranscriptOfficer', 74 u'waeup.UsersManager', 75 u'waeup.WorkflowManager', 76 u'waeup.xmlrpcusers1'] 55 [u'waeup.DataCenterManager', 56 u'waeup.ExportManager', 57 u'waeup.ImportManager', 58 u'waeup.PortalManager', 59 u'waeup.ProductsManager', 60 u'waeup.ProductsOfficer', 61 u'waeup.UsersManager', 62 u'waeup.WorkflowManager', 63 u'waeup.xmlrpcusers1'] 77 64 78 65 :func:`get_users_with_local_roles` -
main/waeup.kofa/branches/henrik-regista/src/waeup/kofa/tests/test_app.py
r9217 r11947 57 57 return 58 58 59 def test_update_plugins(self):60 # We can update plugins61 setSite(self.app)62 del self.app['accesscodes']63 self.app.updatePlugins()64 self.assertTrue('accesscodes' in self.app.keys())65 return66 67 59 def test_jobs(self): 68 60 # We can get the global job manager when traversing to it... -
main/waeup.kofa/branches/henrik-regista/src/waeup/kofa/utils/batching.py
r11849 r11947 338 338 obj = self.callFactory() 339 339 # Override all values in row, also 340 # student_ids and applicant_ids which have been340 # customer ids which have been 341 341 # generated in the respective __init__ methods before. 342 342 self.updateEntry(obj, row, site, base) -
main/waeup.kofa/branches/henrik-regista/src/waeup/kofa/utils/browser.py
r9127 r11947 26 26 27 27 from waeup.kofa.interfaces import IUniversity 28 29 def replaceStudentMessages(old, new):30 students = grok.getSite()['students']31 for student in students.values():32 history = IObjectHistory(student)33 history.modifyMessages(old, new)34 return35 36 def replaceApplicantMessages(old, new):37 applicants = grok.getSite()['applicants']38 for container in applicants.values():39 for applicant in container.values():40 history = IObjectHistory(applicant)41 history.modifyMessages(old, new)42 return43 44 def removeStudentMessage(student_id, number):45 students = grok.getSite()['students']46 student = students.get(student_id, None)47 if student:48 history = IObjectHistory(student)49 success, text = history.removeMessage(number)50 return success, text51 52 def removeApplicantMessage(applicant_id, number):53 applicants = grok.getSite()['applicants']54 try:55 container, application_number = applicant_id.split('_')56 except:57 return False, 'applicant_id is wrong'58 container = applicants.get(container, None)59 if not container:60 return False, 'No such container'61 applicant = container.get(application_number, None)62 if applicant is None:63 return False, 'No such applicant'64 history = IObjectHistory(applicant)65 success, text = history.removeMessage(number)66 return success, text67 28 68 29 class ReindexPage(UtilityView, grok.View): … … 95 56 self.redirect(self.url(self.context, '@@index')) 96 57 return 97 98 class ModifyAllStudentHistory(UtilityView, grok.View):99 """ View to modify all student histories.100 101 """102 grok.context(IUniversity)103 grok.name('modify_student_history')104 grok.require('waeup.managePortal')105 106 def update(self,old=None, new=None):107 if None in (old, new):108 self.flash('Syntax: /modify_student_history?old=[old string]&new=[new string]')109 return110 replaceStudentMessages(old, new)111 self.context.logger.info(112 "'%s' replaced by '%s' in all student histories." % (old, new))113 self.flash('Finished')114 return115 116 def render(self):117 self.redirect(self.url(self.context, '@@index'))118 return119 120 class RemoveStudentHistoryMessage(UtilityView, grok.View):121 """ View to remove a single student history entry.122 123 """124 grok.context(IUniversity)125 grok.name('remove_student_history_message')126 grok.require('waeup.managePortal')127 128 def update(self,student_id=None, number=None):129 if None in (student_id, number):130 self.flash('Syntax: /remove_student_history_message?student_id=[id]&number=[line number, starting with 0]')131 return132 try:133 number=int(number)134 except:135 self.flash('Error')136 return137 success, text = removeStudentMessage(student_id, number)138 if not success:139 self.flash('Error: %s' % text)140 return141 self.context.logger.info(142 "line '%s' removed in %s history" % (text, student_id))143 self.flash('Finished')144 return145 146 def render(self):147 self.redirect(self.url(self.context, '@@index'))148 return149 150 class ModifyAllApplicantHistory(UtilityView, grok.View):151 """ View to modify all student histories.152 153 """154 grok.context(IUniversity)155 grok.name('modify_applicant_history')156 grok.require('waeup.managePortal')157 158 def update(self,old=None, new=None):159 if None in (old, new):160 self.flash('Syntax: /modify_applicant_history?old=[old string]&new=[new string]')161 return162 replaceApplicantMessages(old, new)163 self.context.logger.info(164 "'%s' replaced by '%s' in all applicant histories." % (old, new))165 self.flash('Finished')166 return167 168 def render(self):169 self.redirect(self.url(self.context, '@@index'))170 return171 172 class RemoveApplicantHistoryMessage(UtilityView, grok.View):173 """ View to remove a single applicant history entry.174 175 """176 grok.context(IUniversity)177 grok.name('remove_applicant_history_message')178 grok.require('waeup.managePortal')179 180 def update(self,applicant_id=None, number=None):181 if None in (applicant_id, number):182 self.flash('Syntax: /remove_applicant_history_message?applicant_id=[id]&number=[line number, starting with 0]')183 return184 try:185 number=int(number)186 except:187 self.flash('Error')188 return189 success, text = removeApplicantMessage(applicant_id, number)190 if not success:191 self.flash('Error: %s' % text)192 return193 self.context.logger.info(194 "line '%s' removed in %s history" % (text, applicant_id))195 self.flash('Finished')196 return197 198 def render(self):199 self.redirect(self.url(self.context, '@@index'))200 return -
main/waeup.kofa/branches/henrik-regista/src/waeup/kofa/utils/helpers.py
r11824 r11947 235 235 grok.name(u'waeup.Factory') 236 236 title = u"Create instances of ``factory``.", 237 description = u"This factory instantiates new applicant instances."237 description = u"This factory instantiates new e.g. applicant instances." 238 238 factory = None 239 239 -
main/waeup.kofa/branches/henrik-regista/src/waeup/kofa/utils/tests/test_converters.py
r8216 r11947 38 38 DELETION_MARKER, IGNORE_MARKER) 39 39 from waeup.kofa.schoolgrades import ResultEntryField 40 from waeup.kofa.university import Faculty41 40 from waeup.kofa.utils.converters import ( 42 41 IObjectConverter, IFieldConverter, DefaultFieldConverter, -
main/waeup.kofa/branches/henrik-regista/src/waeup/kofa/utils/utils.py
r11821 r11947 258 258 """Send credentials as email. 259 259 260 Input is the applicantfor which credentials are sent and the260 Input is the customer for which credentials are sent and the 261 261 password. 262 262 -
main/waeup.kofa/branches/henrik-regista/src/waeup/kofa/webservices.py
r10477 r11947 20 20 from zope.component import getUtility 21 21 from zope.catalog.interfaces import ICatalog 22 from waeup.kofa.payments.interfaces import IPayer 23 from waeup.kofa.interfaces import IUniversity, academic_sessions_vocab 24 25 class PaymentDataWebservice(grok.View): 26 """A simple webservice to publish payment and payer details on request from 27 accepted IP addresses without authentication. 28 29 """ 30 grok.context(IUniversity) 31 grok.name('paymentrequest') 32 grok.require('waeup.Public') 33 34 #ACCEPTED_IP = ('174.36.230.28', ) 35 ACCEPTED_IP = ('127.0.0.1', ) 36 37 def update(self, P_ID=None): 38 if P_ID == None: 39 self.output = '-1' 40 return 41 real_ip = self.request.get('HTTP_X_FORWARDED_FOR', None) 42 if real_ip: 43 self.context.logger.info('PaymentDataWebservice called: %s' % real_ip) 44 if real_ip and self.ACCEPTED_IP: 45 if real_ip not in self.ACCEPTED_IP: 46 self.output = '-4' 47 return 48 cat = getUtility(ICatalog, name='payments_catalog') 49 results = list( 50 cat.searchResults(p_id=(P_ID, P_ID), p_state=('paid', 'paid'))) 51 if len(results) != 1: 52 self.output = '-1' 53 return 54 try: 55 owner = IPayer(results[0]) 56 full_name = owner.display_fullname 57 reg_number = owner.reg_number 58 matric_number = owner.matric_number 59 faculty = owner.faculty 60 department = owner.department 61 except (TypeError, AttributeError): 62 self.output = '-3' 63 return 64 amount = results[0].amount_auth 65 payment_category = results[0].category 66 payment_item = results[0].p_item 67 academic_session = academic_sessions_vocab.getTerm( 68 results[0].p_session).title 69 self.output = ( 70 'FULL_NAME=%s&' + 71 'FACULTY=%s&' + 72 'DEPARTMENT=%s&' + 73 'PAYMENT_ITEM=%s&' + 74 'PAYMENT_CATEGORY=%s&' + 75 'ACADEMIC_SESSION=%s&' + 76 'MATRIC_NUMBER=%s&' + 77 'REG_NUMBER=%s&' + 78 'FEE_AMOUNT=%s') % (full_name, faculty, 79 department, payment_item, payment_category, 80 academic_session, matric_number, reg_number, amount) 81 return 82 83 def render(self): 84 return self.output 22 from waeup.kofa.interfaces import IUniversity, application_sessions_vocab 85 23 86 24 class XMLRPCPermission(grok.Permission):
Note: See TracChangeset for help on using the changeset viewer.