Changeset 9208
- Timestamp:
- 20 Sep 2012, 08:22:52 (12 years ago)
- Location:
- main/waeup.kofa/branches/uli-async-update
- Files:
-
- 25 edited
- 3 copied
Legend:
- Unmodified
- Added
- Removed
-
main/waeup.kofa/branches/uli-async-update
- Property svn:mergeinfo changed
/main/waeup.kofa/trunk merged: 9172,9178,9180,9182-9184,9186-9189,9191-9204
- Property svn:mergeinfo changed
-
main/waeup.kofa/branches/uli-async-update/src/waeup/kofa/applicants/browser.py
r9169 r9208 1042 1042 return 1043 1043 1044 @action(_(' Get login credentials'), style='primary')1044 @action(_('Send login credentials to email address'), style='primary') 1045 1045 def register(self, **data): 1046 1046 if not self.captcha_result.is_valid: -
main/waeup.kofa/branches/uli-async-update/src/waeup/kofa/applicants/tests/test_browser.py
r9169 r9208 935 935 self.browser.getControl(name="form.phone.area").value = '555' 936 936 self.browser.getControl(name="form.phone.ext").value = '6666666' 937 self.browser.getControl(" Getlogin credentials").click()937 self.browser.getControl("Send login credentials").click() 938 938 self.assertEqual(self.browser.url, 939 939 self.container_path + '/registration_complete?email=xx%40yy.zz') … … 962 962 self.browser.getControl(name="form.reg_number").value = 'anynumber' 963 963 self.browser.getControl(name="form.email").value = 'xx@yy.zz' 964 self.browser.getControl(" Getlogin credentials").click()964 self.browser.getControl("Send login credentials").click() 965 965 self.assertTrue('No application record found.' 966 966 in self.browser.contents) … … 972 972 self.browser.getControl(name="form.reg_number").value = '1234' 973 973 self.browser.getControl(name="form.email").value = 'xx@yy.zz' 974 self.browser.getControl(" Getlogin credentials").click()974 self.browser.getControl("Send login credentials").click() 975 975 self.assertTrue('An error occurred.' in self.browser.contents) 976 976 # Let's set this attribute manually … … 981 981 self.browser.getControl(name="form.reg_number").value = '1234' 982 982 self.browser.getControl(name="form.email").value = 'xx@yy.zz' 983 self.browser.getControl(" Getlogin credentials").click()983 self.browser.getControl("Send login credentials").click() 984 984 # Anonymous is not informed that firstname verification failed. 985 985 # It seems that the record doesn't exist. … … 991 991 self.browser.getControl(name="form.firstname").value = 'John' 992 992 self.browser.getControl(name="form.reg_number").value = '1234' 993 self.browser.getControl(" Getlogin credentials").click()993 self.browser.getControl("Send login credentials").click() 994 994 self.assertTrue('Your password has already been set and used.' 995 995 in self.browser.contents) … … 1005 1005 self.browser.getControl(name="form.reg_number").value = '1234' 1006 1006 self.browser.getControl(name="form.email").value = 'new@yy.zz' 1007 self.browser.getControl(" Getlogin credentials").click()1007 self.browser.getControl("Send login credentials").click() 1008 1008 # Yeah, we succeded ... 1009 1009 self.assertTrue('Your registration was successful.' … … 1021 1021 self.browser.getControl(name="form.identifier").value = '1234' 1022 1022 self.browser.getControl(name="form.email").value = 'aa@aa.ng' 1023 self.browser.getControl(" Getlogin credentials").click()1023 self.browser.getControl("Send login credentials").click() 1024 1024 self.assertTrue('No record found' in self.browser.contents) 1025 1025 self.applicant.email = 'aa@aa.ng' … … 1029 1029 self.browser.getControl(name="form.identifier").value = '1234' 1030 1030 self.browser.getControl(name="form.email").value = 'aa@aa.ng' 1031 self.browser.getControl(" Getlogin credentials").click()1031 self.browser.getControl("Send login credentials").click() 1032 1032 self.assertTrue( 1033 1033 'An email with your user name and password has been sent' -
main/waeup.kofa/branches/uli-async-update/src/waeup/kofa/browser/batchprocessing.txt
r9169 r9208 97 97 'Course Processor', 'CourseTicket Processor', 98 98 'Department Processor', 'Faculty Processor', 99 'Hostel Processor', 99 100 'Student Payment Processor', 'Student Processor', 100 101 'StudentStudyCourse Processor (update only)', … … 427 428 >>> browser.open('http://localhost/app/datacenter') 428 429 429 Prepare a CSV file for certificate courses:430 Prepare a CSV file for users: 430 431 431 432 >>> open('users.csv', 'wb').write( 432 433 ... """name,title,public_name,email,phone,roles 433 434 ... uli,Uli Fouquet,Chief Developer,uli@abc.de,+49-234-567 434 ... henrik, 435 ... henrik,Henrik Bettermann,Admin,henrik@abc.de,+49-234-567,['waeup.PortalManager'] 435 436 ... """) 436 437 -
main/waeup.kofa/branches/uli-async-update/src/waeup/kofa/browser/browser.txt
r9169 r9208 81 81 >>> browser.getControl(name="form.identifier").value = 'forgetful' 82 82 >>> browser.getControl(name="form.email").value = 'aa@aa.ng' 83 >>> browser.getControl(" Getlogin credentials").click()83 >>> browser.getControl("Send login credentials").click() 84 84 >>> print browser.contents 85 85 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"... -
main/waeup.kofa/branches/uli-async-update/src/waeup/kofa/browser/pages.py
r9177 r9208 2218 2218 return None 2219 2219 2220 @action(_(' Get login credentials'), style='primary')2220 @action(_('Send login credentials to email address'), style='primary') 2221 2221 def request(self, **data): 2222 2222 if not self.captcha_result.is_valid: -
main/waeup.kofa/branches/uli-async-update/src/waeup/kofa/browser/static/jquery.dataTables.min.js
r6820 r9208 15 15 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 16 16 * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details. 17 * 18 * Customized by Henrik Bettermann: this.aLengthMenu, this._iDisplayLength, this._iDisplayEnd 19 * 17 20 */ 18 21 (function(j,ra,p){j.fn.dataTableSettings=[];var D=j.fn.dataTableSettings;j.fn.dataTableExt={};var n=j.fn.dataTableExt;n.sVersion="1.7.6";n.sErrMode="alert";n.iApiIndex=0;n.oApi={};n.afnFiltering=[];n.aoFeatures=[];n.ofnSearch={};n.afnSortData=[];n.oStdClasses={sPagePrevEnabled:"paginate_enabled_previous",sPagePrevDisabled:"paginate_disabled_previous",sPageNextEnabled:"paginate_enabled_next",sPageNextDisabled:"paginate_disabled_next",sPageJUINext:"",sPageJUIPrev:"",sPageButton:"paginate_button",sPageButtonActive:"paginate_active", … … 38 41 [];this.aoColumns=[];this.iNextId=0;this.asDataSearch=[];this.oPreviousSearch={sSearch:"",bRegex:false,bSmart:true};this.aoPreSearchCols=[];this.aaSorting=[[0,"asc",0]];this.aaSortingFixed=null;this.asStripClasses=[];this.asDestoryStrips=[];this.sDestroyWidth=0;this.fnFooterCallback=this.fnHeaderCallback=this.fnRowCallback=null;this.aoDrawCallback=[];this.fnInitComplete=null;this.sTableId="";this.nTableWrapper=this.nTBody=this.nTFoot=this.nTHead=this.nTable=null;this.bInitialised=false;this.aoOpenRows= 39 42 [];this.sDom="lfrtip";this.sPaginationType="two_button";this.iCookieDuration=7200;this.sCookiePrefix="SpryMedia_DataTables_";this.fnCookieCallback=null;this.aoStateSave=[];this.aoStateLoad=[];this.sAjaxSource=this.oLoadedState=null;this.bAjaxDataGet=true;this.fnServerData=function(a,b,c){j.ajax({url:a,data:b,success:c,dataType:"json",cache:false,error:function(d,f){f=="parsererror"&&alert("DataTables warning: JSON data from server could not be parsed. This is caused by a JSON formatting error.")}})}; 40 this.fnFormatNumber=function(a){if(a<1E3)return a;else{var b=a+"";a=b.split("");var c="";b=b.length;for(var d=0;d<b;d++){if(d%3===0&&d!==0)c=","+c;c=a[b-d-1]+c}}return c};this.aLengthMenu=[10,25,50,100,1000,5000];this.bDrawing=this.iDraw=0;this.iDrawError=-1;this._iDisplayLength=10 ;this._iDisplayStart=0;this._iDisplayEnd=10;this._iRecordsDisplay=this._iRecordsTotal=0;this.bJUI=false;this.oClasses=n.oStdClasses;this.bSorted=this.bFiltered=false;this.oInit=null}function r(a){return function(){var b=[A(this[n.iApiIndex])].concat(Array.prototype.slice.call(arguments));43 this.fnFormatNumber=function(a){if(a<1E3)return a;else{var b=a+"";a=b.split("");var c="";b=b.length;for(var d=0;d<b;d++){if(d%3===0&&d!==0)c=","+c;c=a[b-d-1]+c}}return c};this.aLengthMenu=[10,25,50,100,1000,5000];this.bDrawing=this.iDraw=0;this.iDrawError=-1;this._iDisplayLength=1000;this._iDisplayStart=0;this._iDisplayEnd=1000;this._iRecordsDisplay=this._iRecordsTotal=0;this.bJUI=false;this.oClasses=n.oStdClasses;this.bSorted=this.bFiltered=false;this.oInit=null}function r(a){return function(){var b=[A(this[n.iApiIndex])].concat(Array.prototype.slice.call(arguments)); 41 44 return n.oApi[a].apply(this,b)}}function s(a){var b,c;if(a.bInitialised===false)setTimeout(function(){s(a)},200);else{sa(a);U(a);K(a,true);a.oFeatures.bAutoWidth&&$(a);b=0;for(c=a.aoColumns.length;b<c;b++)if(a.aoColumns[b].sWidth!==null)a.aoColumns[b].nTh.style.width=v(a.aoColumns[b].sWidth);if(a.oFeatures.bSort)O(a);else{a.aiDisplay=a.aiDisplayMaster.slice();E(a);C(a)}if(a.sAjaxSource!==null&&!a.oFeatures.bServerSide)a.fnServerData.call(a.oInstance,a.sAjaxSource,[],function(d){for(b=0;b<d.aaData.length;b++)u(a, 42 45 d.aaData[b]);a.iInitDisplayStart=a._iDisplayStart;if(a.oFeatures.bSort)O(a);else{a.aiDisplay=a.aiDisplayMaster.slice();E(a);C(a)}K(a,false);w(a,d)});else if(!a.oFeatures.bServerSide){K(a,false);w(a)}}}function w(a,b){a._bInitComplete=true;if(typeof a.fnInitComplete=="function")typeof b!="undefined"?a.fnInitComplete.call(a.oInstance,a,b):a.fnInitComplete.call(a.oInstance,a)}function y(a,b,c){o(a.oLanguage,b,"sProcessing");o(a.oLanguage,b,"sLengthMenu");o(a.oLanguage,b,"sEmptyTable");o(a.oLanguage, -
main/waeup.kofa/branches/uli-async-update/src/waeup/kofa/browser/templates/datacenterfinishedpage.pt
r9169 r9208 3 3 <tr> 4 4 <th i18n:translate="">File</th> 5 <th i18n:translate=""> Size</th>5 <th i18n:translate="">Datasets</th> 6 6 <th i18n:translate="">Upload Date</th> 7 7 </tr> … … 11 11 <td><a tal:attributes="href python: 'download?filename=' + file.rel_path" 12 12 tal:content="file/name">FILENAME</a></td> 13 <td tal:content=" file/size">12 k</td>13 <td tal:content="python: file.lines-1">12 k</td> 14 14 <td tal:content="file/uploaddate">Mar 12, 2008</td> 15 15 </tr> -
main/waeup.kofa/branches/uli-async-update/src/waeup/kofa/browser/templates/datacenterpage.pt
r9169 r9208 16 16 <th></th> 17 17 <th i18n:translate="">File</th> 18 <th i18n:translate=""> Size</th>18 <th i18n:translate="">Datasets</th> 19 19 <th i18n:translate="">Upload Date</th> 20 20 </tr> … … 28 28 <td><a tal:attributes="href python: 'download?filename=' + file.name" 29 29 tal:content="file/name">FILENAME</a></td> 30 <td tal:content=" file/size">12 k</td>30 <td tal:content="python: file.lines - 1">100</td> 31 31 <td tal:content="file/uploaddate">Mar 12, 2008</td> 32 32 </tr> -
main/waeup.kofa/branches/uli-async-update/src/waeup/kofa/hostels/browser.py
r9166 r9208 93 93 94 94 def title(self): 95 co = self.context. getBedCoordinates()95 co = self.context.coordinates 96 96 return _('Block ${a}, Room ${b}, Bed ${c}', 97 97 mapping = {'a':co[1], 'b':co[2], 'c':co[3]}) … … 130 130 form_fields = grok.AutoFields(IHostelsContainer) 131 131 taboneactions = [_('Save')] 132 tabtwoactions = [_('Add hostel'), _('Remove selected')] 132 tabtwoactions = [_('Add hostel'), 133 _('Clear all hostels'), 134 _('Remove selected')] 133 135 134 136 def update(self): … … 164 166 return 165 167 168 @jsaction(_('Clear all hostels')) 169 def clearHostels(self, **data): 170 self.context.clearAllHostels() 171 self.flash(_('All hostels cleared.')) 172 write_log_message(self, 'all hostels cleared') 173 self.redirect(self.url(self.context, '@@manage')+'?tab2') 174 return 175 166 176 @action(_('Save'), style='primary') 167 177 def save(self, **data): … … 232 242 tabtwoactions = [_('Update all beds'), 233 243 _('Switch reservation of selected beds'), 234 _('Release selected beds')] 244 _('Release selected beds'), 245 _('Clear hostel')] 235 246 not_occupied = NOT_OCCUPIED 236 247 … … 243 254 tabs.need() 244 255 datatable.need() 256 warning.need() 245 257 self.tab1 = self.tab2 = '' 246 258 qs = self.request.get('QUERY_STRING', '') … … 327 339 return 328 340 341 @jsaction(_('Clear hostel')) 342 def clearHostel(self, **data): 343 self.context.clearHostel() 344 self.flash(_('Hostel cleared.')) 345 write_log_message(self, 'cleared') 346 self.redirect(self.url(self.context, '@@manage')+'?tab2') 347 return 348 329 349 class BedManageFormPage(KofaEditFormPage): 330 350 """ View to edit bed data … … 334 354 grok.require('waeup.manageHostels') 335 355 form_fields = grok.AutoFields(IBedAllocateStudent).omit( 336 'bed_id' ).omit('bed_number').omit('bed_type')356 'bed_id', 'bed_number', 'bed_type') 337 357 label = _('Allocate student') 338 358 pnav = 5 -
main/waeup.kofa/branches/uli-async-update/src/waeup/kofa/hostels/browser_templates/containerpage.pt
r8685 r9208 21 21 <th i18n:translate="">Id</th> 22 22 <th i18n:translate="">Name</th> 23 <th i18n:translate="">Booked Beds</th> 23 24 </tr> 24 25 </thead> 25 26 <tbody> 26 <tr tal:repeat="value context/values"> 27 <td> <a tal:attributes="href value/__name__"> 28 <span tal:content="value/hostel_id">ID</span></a></td> 29 <td tal:content="value/hostel_name">NAME</td> 30 </tr> 27 <tal:tbody repeat="value context/values"> 28 <tr tal:define = "stats value/bed_statistics"> 29 <td> <a tal:attributes="href value/__name__"> 30 <span tal:content="value/hostel_id">ID</span></a></td> 31 <td tal:content="value/hostel_name">NAME</td> 32 <td> 33 <span tal:replace="stats/booked">10</span> of <span tal:replace="stats/total">100</span> 34 </td> 35 </tr> 36 </tal:tbody> 31 37 </tbody> 32 38 </table> -
main/waeup.kofa/branches/uli-async-update/src/waeup/kofa/hostels/container.py
r8686 r9208 51 51 return 52 52 53 def clearAllHostels(self): 54 """Clear all hostels. 55 """ 56 for hostel in self.values(): 57 hostel.clearHostel() 58 return 59 53 60 logger_name = 'waeup.kofa.${sitename}.hostels' 54 61 logger_filename = 'hostels.log' -
main/waeup.kofa/branches/uli-async-update/src/waeup/kofa/hostels/hostel.py
r8685 r9208 22 22 from zope.event import notify 23 23 from zope.component import getUtility 24 from zope.component.interfaces import IFactory 24 25 from datetime import datetime 25 26 from waeup.kofa.utils.helpers import attrs_to_fields … … 40 41 target = self.__name__ 41 42 return grok.getSite()['hostels'].logger_info(ob_class,target,comment) 43 44 @property 45 def bed_statistics(self): 46 total = len(self.keys()) 47 booked = 0 48 for value in self.values(): 49 if value.owner != NOT_OCCUPIED: 50 booked += 1 51 return {'booked':booked, 'total':total} 52 53 def clearHostel(self): 54 """Remove all beds 55 """ 56 keys = [i for i in self.keys()] # create deep copy 57 for bed in keys: 58 del self[bed] 59 return 42 60 43 61 def addBed(self, bed): … … 128 146 grok.provides(IBed) 129 147 130 def getBedCoordinates(self): 148 @property 149 def coordinates(self): 131 150 """Determine the coordinates from the bed_id. 132 151 """ 133 152 return self.bed_id.split('_') 153 154 # The following property attributes are only needed 155 # for the exporter to ease evaluation with Excel. 156 157 @property 158 def hall(self): 159 return self.coordinates[0] 160 161 @property 162 def block(self): 163 return self.coordinates[1] 164 165 @property 166 def room(self): 167 return self.coordinates[2] 168 169 @property 170 def bed(self): 171 return self.coordinates[3] 172 173 @property 174 def special_handling(self): 175 return self.bed_type.split('_')[0] 176 177 @property 178 def sex(self): 179 return self.bed_type.split('_')[1] 180 181 @property 182 def bt(self): 183 return self.bed_type.split('_')[2] 184 134 185 135 186 def bookBed(self, student_id): … … 145 196 """ 146 197 sh, sex, bt = self.bed_type.split('_') 147 hostel_id, block, room_nr, bed = self. getBedCoordinates()198 hostel_id, block, room_nr, bed = self.coordinates 148 199 hostel = self.__parent__ 149 200 beds_for_fresh = getattr(hostel,'beds_for_fresh',[]) … … 221 272 Bed = attrs_to_fields(Bed) 222 273 274 class HostelFactory(grok.GlobalUtility): 275 """A factory for hostels. 276 277 We need this factory for the hostel processor. 278 """ 279 grok.implements(IFactory) 280 grok.name(u'waeup.Hostel') 281 title = u"Create a new hostel.", 282 description = u"This factory instantiates new hostel instances." 283 284 def __call__(self, *args, **kw): 285 return Hostel() 286 287 def getInterfaces(self): 288 return implementedBy(Hostel) 289 290 223 291 @grok.subscribe(IBedTicket, grok.IObjectRemovedEvent) 224 292 def handle_bedticket_removed(bedticket, event): … … 229 297 bedticket.bed.owner = NOT_OCCUPIED 230 298 notify(grok.ObjectModifiedEvent(bedticket.bed)) 299 -
main/waeup.kofa/branches/uli-async-update/src/waeup/kofa/hostels/interfaces.py
r9169 r9208 17 17 ## 18 18 from datetime import datetime 19 from zope.interface import invariant, Invalid 19 from zope.interface import invariant, Invalid, Attribute 20 20 from zope import schema 21 21 from waeup.kofa.interfaces import ( … … 58 58 ) 59 59 60 def clearAllHostels(): 61 """Clear all hostels. 62 """ 63 60 64 class IHostel(IKofaObject): 61 65 """A base representation of hostels. … … 63 67 """ 64 68 69 bed_statistics = Attribute('Number of booked and total beds') 70 65 71 def loggerInfo(ob_class, comment): 66 72 """Adds an INFO message to the log file 73 """ 74 75 def clearHostel(): 76 """Remove all beds. 67 77 """ 68 78 … … 189 199 """ 190 200 201 coordinates = Attribute('The coordinates of the bed from bed_id') 202 191 203 def loggerInfo(ob_class, comment): 192 204 """Adds an INFO message to the log file 193 205 """ 194 206 195 def getBedCoordinates():196 """Determine the coordinates from bed_id.197 """198 207 def bookBed(student_id): 199 208 """Book a bed for a student. -
main/waeup.kofa/branches/uli-async-update/src/waeup/kofa/hostels/tests.py
r8686 r9208 19 19 Tests for hostels and their UI components. 20 20 """ 21 import os 21 22 import shutil 22 23 import tempfile … … 36 37 from waeup.kofa.hostels.container import HostelsContainer 37 38 from waeup.kofa.hostels.hostel import Hostel, Bed 39 from waeup.kofa.hostels.batching import HostelProcessor 40 from waeup.kofa.hostels.export import BedExporter, HostelExporter 38 41 from waeup.kofa.testing import (FunctionalLayer, FunctionalTestCase) 39 42 from waeup.kofa.students.student import Student 40 43 from waeup.kofa.students.accommodation import BedTicket 41 44 from waeup.kofa.university.department import Department 45 46 HOSTEL_SAMPLE_DATA = open( 47 os.path.join(os.path.dirname(__file__), 'sample_hostel_data.csv'), 48 'rb').read() 49 50 HOSTEL_HEADER_FIELDS = HOSTEL_SAMPLE_DATA.split( 51 '\n')[0].split(',') 42 52 43 53 class HostelsContainerTestCase(FunctionalTestCase): … … 142 152 # Create a bed 143 153 bed = Bed() 144 bed.bed_id = u' xyz'154 bed.bed_id = u'hall_block_room_bed' 145 155 bed.bed_number = 1 146 bed.bed_type = u'a bc'156 bed.bed_type = u'a_b_c' 147 157 self.app['hostels'][hostel.hostel_id][bed.bed_id] = bed 148 158 … … 157 167 self.browser.handleErrors = False 158 168 169 self.logfile = os.path.join( 170 self.app['datacenter'].storage, 'logs', 'hostels.log') 171 159 172 def tearDown(self): 160 173 super(HostelsFullSetup, self).tearDown() … … 174 187 # We can find a certain bed 175 188 cat = queryUtility(ICatalog, name='beds_catalog') 176 results = cat.searchResults(bed_type=(u'a bc', u'abc'))189 results = cat.searchResults(bed_type=(u'a_b_c', u'a_b_c')) 177 190 results = [x for x in results] # Turn results generator into list 178 191 assert len(results) == 1 179 assert results[0] is self.app['hostels']['hall-x'][' xyz']192 assert results[0] is self.app['hostels']['hall-x']['hall_block_room_bed'] 180 193 181 194 def test_search_by_owner(self): 182 195 # We can find a certain bed 183 myobj = self.app['hostels']['hall-x'][' xyz']196 myobj = self.app['hostels']['hall-x']['hall_block_room_bed'] 184 197 myobj.owner = u'abc' 185 198 notify(grok.ObjectModifiedEvent(myobj)) … … 188 201 results = [x for x in results] # Turn results generator into list 189 202 assert len(results) == 1 190 assert results[0] is self.app['hostels']['hall-x'][' xyz']203 assert results[0] is self.app['hostels']['hall-x']['hall_block_room_bed'] 191 204 192 205 class HostelsUITests(HostelsFullSetup): … … 300 313 self.assertMatches( 301 314 '...No allocated bed selected...', self.browser.contents) 302 # Managers can manually allocate studen stafter cancellation315 # Managers can manually allocate students after cancellation 303 316 self.browser.open(self.container_path + '/hall-1/hall-1_A_101_A') 304 317 self.browser.getControl(name="form.owner").value = [self.student_id] … … 334 347 # Also the number of the bed has changed. 335 348 self.assertFalse(new_number == old_number) 349 # The number of occupied bed are displayed on container page. 350 self.browser.open(self.container_path) 351 self.assertTrue('1 of 8' in self.browser.contents) 336 352 # Remove entire hostel 337 353 self.browser.open(self.manage_container_path) … … 346 362 results = [x for x in results] 347 363 assert len(results) == 0 364 365 def test_clear_hostels(self): 366 self.browser.addHeader('Authorization', 'Basic mgr:mgrpw') 367 self.browser.open(self.container_path) 368 self.browser.getLink("Manage accommodation").click() 369 self.browser.getControl("Add hostel").click() 370 self.browser.getControl("Create hostel").click() 371 hall = self.app['hostels']['hall-1'] 372 hall.blocks_for_female = ['A','B'] 373 hall.rooms_per_floor = 1 374 hall.beds_for_fresh = ['A'] 375 hall.beds_for_returning = ['B'] 376 hall.beds_for_final = ['C'] 377 hall.beds_for_all = ['D','E'] 378 self.browser.open(self.container_path + '/hall-1/manage') 379 self.browser.getControl("Update all beds").click() 380 cat = queryUtility(ICatalog, name='beds_catalog') 381 results = cat.searchResults(bed_type=(None, None)) 382 self.assertEqual(len(results), 11) 383 self.browser.getControl("Clear hostel").click() 384 self.assertEqual(len(self.app['hostels']['hall-1']), 0) 385 # Only the bed in hall-x remains in the catalog. 386 results = cat.searchResults(bed_type=(None, None)) 387 self.assertEqual(len(results), 1) 388 # We can clear all hostels at the same time. 389 self.browser.open(self.manage_container_path) 390 self.browser.getControl("Clear all hostels").click() 391 results = cat.searchResults(bed_type=(None, None)) 392 self.assertEqual(len(results), 0) 393 # Both actions have been logged. 394 logcontent = open(self.logfile).read() 395 self.assertTrue('INFO - zope.mgr - hostels.browser.HostelManageFormPage' 396 ' - hall-1 - cleared' in logcontent) 397 self.assertTrue('zope.mgr - hostels.browser.HostelsContainerManagePage' 398 ' - hostels - all hostels cleared' in logcontent) 399 400 class ExportTests(HostelsFullSetup): 401 402 layer = FunctionalLayer 403 404 def setUp(self): 405 super(ExportTests, self).setUp() 406 self.workdir = tempfile.mkdtemp() 407 self.outfile = os.path.join(self.workdir, 'myoutput.csv') 408 return 409 410 def test_export_hostels(self): 411 exporter = HostelExporter() 412 exporter.export_all(self.app, self.outfile) 413 result = open(self.outfile, 'rb').read() 414 self.assertEqual( 415 result, 416 'beds_for_all,beds_for_final,beds_for_fresh,beds_for_pre,' 417 'beds_for_returning,beds_reserved,blocks_for_female,' 418 'blocks_for_male,floors_per_block,hostel_id,hostel_name,' 419 'rooms_per_floor,sort_id,special_handling\r\n,,,,,[],,,1,' 420 'hall-x,Hall 1,2,10,regular\r\n' 421 ) 422 return 423 424 def test_export_beds(self): 425 exporter = BedExporter() 426 exporter.export_all(self.app, self.outfile) 427 result = open(self.outfile, 'rb').read() 428 self.assertEqual( 429 result, 430 'bed_id,bed_number,bed_type,owner,hall,block,room,bed,' 431 'special_handling,sex,bt\r\nhall_block_room_bed,1,a_b_c,,' 432 'hall,block,room,bed,a,b,c\r\n' 433 ) 434 return 435 436 class HostelProcessorTest(HostelsFullSetup): 437 438 layer = FunctionalLayer 439 440 def test_import(self): 441 self.processor = HostelProcessor() 442 self.workdir = tempfile.mkdtemp() 443 self.csv_file = os.path.join(self.workdir, 'sample_student_data.csv') 444 open(self.csv_file, 'wb').write(HOSTEL_SAMPLE_DATA) 445 num, num_warns, fin_file, fail_file = self.processor.doImport( 446 self.csv_file, HOSTEL_HEADER_FIELDS) 447 self.assertEqual(num_warns,0) 448 self.assertEqual(len(self.app['hostels'].keys()), 11) # including hall-x 449 self.assertEqual(self.app['hostels'][ 450 'block-a-upper-hostel'].hostel_id,'block-a-upper-hostel') 451 self.assertEqual(self.app['hostels'][ 452 'block-a-upper-hostel'].beds_for_final, ['A', 'B']) 453 logcontent = open(self.logfile).read() 454 self.assertTrue( 455 "Hostel Processor - block-a-upper-hostel - " 456 "Record updated: beds_for_pre=['G'], floors_per_block=1, " 457 "beds_for_final=['A', 'B'], rooms_per_floor=32, " 458 "blocks_for_male=[], hostel_id=block-a-upper-hostel, " 459 "sort_id=20, beds_for_returning=['C', 'D'], " 460 "hostel_name=Block A Upper Hostel, beds_for_fresh=['E', 'F'], " 461 "blocks_for_female=['A'], beds_for_all=[], beds_reserved=[]" 462 in logcontent) 463 shutil.rmtree(os.path.dirname(fin_file)) 464 return -
main/waeup.kofa/branches/uli-async-update/src/waeup/kofa/permissions.py
r9169 r9208 213 213 'waeup.uploadStudentFile', 'waeup.showStudents', 214 214 'waeup.viewStudentsContainer','waeup.viewStudentsTab', 215 'waeup.handleAccommodation', 215 216 'waeup.viewHostels', 'waeup.manageHostels', 216 217 'waeup.editUser' -
main/waeup.kofa/branches/uli-async-update/src/waeup/kofa/students/browser.py
r9169 r9208 361 361 return 362 362 363 class ExportPDFAdmissionSlipPage(UtilityView, grok.View): 364 """Deliver a PDF Admission slip. 365 """ 366 grok.context(IStudent) 367 grok.name('admission_slip.pdf') 368 grok.require('waeup.viewStudent') 369 prefix = 'form' 370 371 form_fields = grok.AutoFields(IStudentBase).select('student_id', 'reg_number') 372 373 @property 374 def label(self): 375 portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE 376 return translate(_('Admission Letter of'), 377 'waeup.kofa', target_language=portal_language) \ 378 + ' %s' % self.context.display_fullname 379 380 def render(self): 381 students_utils = getUtility(IStudentsUtils) 382 return students_utils.renderPDFAdmissionLetter(self, 383 self.context.student) 384 363 385 class StudentBaseManageFormPage(KofaEditFormPage): 364 386 """ View to manage student base data … … 1234 1256 if error is not None: 1235 1257 self.flash(error) 1236 if ' Would you like' in error:1258 if 'previous session' in error: 1237 1259 self.redirect(self.url(self.context) + '/@@addpp') 1238 1260 return … … 1409 1431 buttonname = _('Create bed ticket') 1410 1432 notice = '' 1433 with_ac = True 1411 1434 1412 1435 def update(self, SUBMIT=None): … … 1449 1472 self.redirect(self.url(self.context)) 1450 1473 return 1451 self.ac_series = self.request.form.get('ac_series', None) 1452 self.ac_number = self.request.form.get('ac_number', None) 1474 if self.with_ac: 1475 self.ac_series = self.request.form.get('ac_series', None) 1476 self.ac_number = self.request.form.get('ac_number', None) 1453 1477 if SUBMIT is None: 1454 1478 return 1455 pin = '%s-%s-%s' % (self.ac_prefix, self.ac_series, self.ac_number) 1456 code = get_access_code(pin) 1457 if not code: 1458 self.flash(_('Activation code is invalid.')) 1459 return 1479 if self.with_ac: 1480 pin = '%s-%s-%s' % (self.ac_prefix, self.ac_series, self.ac_number) 1481 code = get_access_code(pin) 1482 if not code: 1483 self.flash(_('Activation code is invalid.')) 1484 return 1460 1485 # Search and book bed 1461 1486 cat = queryUtility(ICatalog, name='beds_catalog', default=None) … … 1463 1488 owner=(student.student_id,student.student_id)) 1464 1489 if len(entries): 1465 # If bed space has bee manually allocated use this bed1490 # If bed space has been manually allocated use this bed 1466 1491 bed = [entry for entry in entries][0] 1467 1492 else: … … 1479 1504 mapping = {'a':acc_details['bt']})) 1480 1505 return 1481 # Mark pin as used (this also fires a pin related transition) 1482 if code.state == USED: 1483 self.flash(_('Activation code has already been used.')) 1484 return 1485 else: 1486 comment = _(u'invalidated') 1487 # Here we know that the ac is in state initialized so we do not 1488 # expect an exception, but the owner might be different 1489 if not invalidate_accesscode( 1490 pin,comment,self.context.student.student_id): 1491 self.flash(_('You are not the owner of this access code.')) 1506 if self.with_ac: 1507 # Mark pin as used (this also fires a pin related transition) 1508 if code.state == USED: 1509 self.flash(_('Activation code has already been used.')) 1492 1510 return 1511 else: 1512 comment = _(u'invalidated') 1513 # Here we know that the ac is in state initialized so we do not 1514 # expect an exception, but the owner might be different 1515 if not invalidate_accesscode( 1516 pin,comment,self.context.student.student_id): 1517 self.flash(_('You are not the owner of this access code.')) 1518 return 1493 1519 # Create bed ticket 1494 1520 bedticket = createObject(u'waeup.BedTicket') 1495 bedticket.booking_code = pin 1521 if self.with_ac: 1522 bedticket.booking_code = pin 1496 1523 bedticket.booking_session = acc_details['booking_session'] 1497 1524 bedticket.bed_type = acc_details['bt'] 1498 1525 bedticket.bed = bed 1499 1526 hall_title = bed.__parent__.hostel_name 1500 coordinates = bed. getBedCoordinates()[1:]1527 coordinates = bed.coordinates[1:] 1501 1528 block, room_nr, bed_nr = coordinates 1502 1529 bc = _('${a}, Block ${b}, Room ${c}, Bed ${d} (${e})', mapping = { … … 1521 1548 grok.require('waeup.handleAccommodation') 1522 1549 form_fields = grok.AutoFields(IBedTicket) 1550 form_fields['booking_date'].custom_widget = FriendlyDatetimeDisplayWidget('le') 1523 1551 pnav = 4 1524 1552 … … 1547 1575 def label(self): 1548 1576 portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE 1549 return translate(_('Bed Allocation: '), 1577 #return translate(_('Bed Allocation: '), 1578 # 'waeup.kofa', target_language=portal_language) \ 1579 # + ' %s' % self.context.bed_coordinates 1580 return translate(_('Bed Allocation Slip'), 1550 1581 'waeup.kofa', target_language=portal_language) \ 1551 + ' %s' % self.context. bed_coordinates1582 + ' %s' % self.context.getSessionString() 1552 1583 1553 1584 def render(self): … … 1614 1645 self.context.bed = new_bed 1615 1646 hall_title = new_bed.__parent__.hostel_name 1616 coordinates = new_bed. getBedCoordinates()[1:]1647 coordinates = new_bed.coordinates[1:] 1617 1648 block, room_nr, bed_nr = coordinates 1618 1649 bc = _('${a}, Block ${b}, Room ${c}, Bed ${d} (${e})', mapping = { -
main/waeup.kofa/branches/uli-async-update/src/waeup/kofa/students/browser_templates/basepage.pt
r7811 r9208 18 18 <tal:password replace="view/hasPassword" /> 19 19 </td> 20 < tr>20 </tr> 21 21 <tal:files content="structure provider:files" /> 22 22 </tbody> -
main/waeup.kofa/branches/uli-async-update/src/waeup/kofa/students/interfaces.py
r9169 r9208 156 156 current_level = Attribute('The current level of the student') 157 157 current_mode = Attribute('The current mode of the student') 158 current_verdict = Attribute('The current verdict of the student') 158 159 fullname = Attribute('All name parts separated by hyphens') 159 160 display_fullname = Attribute('The fullname of an applicant') -
main/waeup.kofa/branches/uli-async-update/src/waeup/kofa/students/student.py
r9169 r9208 134 134 level = getattr( 135 135 self.get('studycourse', None), 'current_level', None) 136 return level 137 138 @property 139 def current_verdict(self): 140 level = getattr( 141 self.get('studycourse', None), 'current_verdict', None) 136 142 return level 137 143 -
main/waeup.kofa/branches/uli-async-update/src/waeup/kofa/students/tests/test_browser.py
r9169 r9208 403 403 404 404 layer = FunctionalLayer 405 406 def test_student_properties(self): 407 self.student['studycourse'].current_level = 100 408 self.assertEqual(self.student.current_level, 100) 409 self.student['studycourse'].current_session = 2011 410 self.assertEqual(self.student.current_session, 2011) 411 self.student['studycourse'].current_verdict = 'A' 412 self.assertEqual(self.student.current_verdict, 'A') 413 return 405 414 406 415 def test_basic_auth(self): … … 1183 1192 self.assertTrue( 1184 1193 'You logged in.' in self.browser.contents) 1185 # Student can upload a passport picture1194 # Admitted student can upload a passport picture 1186 1195 self.browser.open(self.student_path + '/change_portrait') 1187 1196 ctrl = self.browser.getControl(name='passportuploadedit') … … 1194 1203 '<img align="middle" height="125px" src="passport.jpg" />' 1195 1204 in self.browser.contents) 1205 # Students can open admission letter 1206 self.browser.getLink("Base Data").click() 1207 self.browser.getLink("Download admission letter").click() 1208 self.assertEqual(self.browser.headers['Status'], '200 Ok') 1209 self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf') 1196 1210 # Student can view the clearance data 1211 self.browser.open(self.student_path) 1197 1212 self.browser.getLink("Clearance Data").click() 1198 1213 # Student can't open clearance edit form before starting clearance … … 1584 1599 1585 1600 def test_student_previous_payments(self): 1601 configuration = createObject('waeup.SessionConfiguration') 1602 configuration.academic_session = 2000 1603 configuration.clearance_fee = 3456.0 1604 configuration.booking_fee = 123.4 1605 self.student['studycourse'].entry_session = 2002 1606 self.app['configuration'].addSessionConfiguration(configuration) 1607 configuration2 = createObject('waeup.SessionConfiguration') 1608 configuration2.academic_session = 2003 1609 configuration2.clearance_fee = 3456.0 1610 configuration2.booking_fee = 123.4 1611 self.student['studycourse'].entry_session = 2002 1612 self.app['configuration'].addSessionConfiguration(configuration2) 1586 1613 # Login 1587 1614 self.browser.open(self.login_path) … … 1606 1633 # Previous session payment form is provided 1607 1634 self.browser.getControl(name="form.p_category").value = ['schoolfee'] 1635 self.browser.getControl(name="form.p_session").value = ['2000'] 1636 self.browser.getControl(name="form.p_level").value = ['300'] 1637 self.browser.getControl("Create ticket").click() 1638 self.assertMatches('...The previous session must not fall below...', 1639 self.browser.contents) 1640 self.browser.getControl(name="form.p_category").value = ['schoolfee'] 1608 1641 self.browser.getControl(name="form.p_session").value = ['2004'] 1642 self.browser.getControl(name="form.p_level").value = ['300'] 1643 self.browser.getControl("Create ticket").click() 1644 self.assertMatches('...This is not a previous session...', 1645 self.browser.contents) 1646 self.browser.getControl(name="form.p_category").value = ['schoolfee'] 1647 self.browser.getControl(name="form.p_session").value = ['2003'] 1609 1648 self.browser.getControl(name="form.p_level").value = ['300'] 1610 1649 self.browser.getControl("Create ticket").click() … … 1619 1658 1620 1659 # Payment session is properly set 1621 self.assertEqual(self.student['payments'][value].p_session, 200 4)1660 self.assertEqual(self.student['payments'][value].p_session, 2003) 1622 1661 self.assertEqual(self.student['payments'][value].p_level, 300) 1623 1662 … … 1954 1993 self.browser.getControl(name="form.identifier").value = '123' 1955 1994 self.browser.getControl(name="form.email").value = 'aa@aa.ng' 1956 self.browser.getControl(" Getlogin credentials").click()1995 self.browser.getControl("Send login credentials").click() 1957 1996 self.assertTrue('An email with' in self.browser.contents) 1958 1997 -
main/waeup.kofa/branches/uli-async-update/src/waeup/kofa/students/utils.py
r9169 r9208 138 138 f_label = formatted_label(size=12) % _('Study Course') 139 139 f_label = Paragraph(f_label, style["Normal"]) 140 f_text = formatted_text(studentview.context.certcode, size=12) 140 f_text = formatted_text( 141 studentview.context['studycourse'].certificate.longtitle(), size=12) 142 f_text = Paragraph(f_text, style["Normal"]) 143 data_right.append([f_label,f_text]) 144 145 f_label = formatted_label(size=12) % _('Department') 146 f_label = Paragraph(f_label, style["Normal"]) 147 f_text = formatted_text( 148 studentview.context[ 149 'studycourse'].certificate.__parent__.__parent__.longtitle(), 150 size=12) 151 f_text = Paragraph(f_text, style["Normal"]) 152 data_right.append([f_label,f_text]) 153 154 f_label = formatted_label(size=12) % _('Faculty') 155 f_label = Paragraph(f_label, style["Normal"]) 156 f_text = formatted_text( 157 studentview.context[ 158 'studycourse'].certificate.__parent__.__parent__.__parent__.longtitle(), 159 size=12) 141 160 f_text = Paragraph(f_text, style["Normal"]) 142 161 data_right.append([f_label,f_text]) … … 309 328 return _('Study course data are incomplete.'), None 310 329 if previous_session: 330 if previous_session < student['studycourse'].entry_session: 331 return _('The previous session must not fall below ' 332 'your entry session.'), None 333 if previous_session > student['studycourse'].current_session - 1: 334 return _('This is not a previous session.'), None 311 335 if previous_level == 100: 312 336 amount = getattr(certificate, 'school_fee_1', 0.0) … … 328 352 amount = getattr(certificate, 'school_fee_2', 0.0) 329 353 elif category == 'clearance': 330 p_item = student['studycourse'].certificate.code 354 try: 355 p_item = student['studycourse'].certificate.code 356 except (AttributeError, TypeError): 357 return _('Study course data are incomplete.'), None 331 358 amount = academic_session.clearance_fee 332 359 elif category == 'bed_allocation': … … 371 398 entry_session = studycourse.entry_session 372 399 current_level = studycourse.current_level 373 if not (entry_session and current_level andcertificate):374 return 400 if None in (entry_session, current_level, certificate): 401 return d 375 402 end_level = certificate.end_level 376 403 if current_level == 10: … … 398 425 return available_beds[0] 399 426 427 def renderPDFAdmissionLetter(self, view, student=None): 428 """Render pdf admission letter. 429 """ 430 # XXX: we have to fix the import problems here. 431 from waeup.kofa.browser.interfaces import IPDFCreator 432 from waeup.kofa.browser.pdf import format_html, NOTE_STYLE 433 if student is None: 434 return 435 style = getSampleStyleSheet() 436 creator = getUtility(IPDFCreator) 437 data = [] 438 doc_title = view.label 439 author = '%s (%s)' % (view.request.principal.title, 440 view.request.principal.id) 441 footer_text = view.label 442 if getattr(student, 'student_id', None) is not None: 443 footer_text = "%s - %s - " % (student.student_id, footer_text) 444 445 # Admission text 446 portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE 447 inst_name = grok.getSite()['configuration'].name 448 text = trans(_( 449 'This is to inform you that you have been provisionally' 450 ' admitted into ${a} as follows:', mapping = {'a': inst_name}), 451 portal_language) 452 html = format_html(text) 453 data.append(Paragraph(html, NOTE_STYLE)) 454 data.append(Spacer(1, 20)) 455 456 # Student data 457 data.append(render_student_data(view)) 458 459 # Insert history 460 data.append(Spacer(1, 20)) 461 datelist = student.history.messages[0].split()[0].split('-') 462 creation_date = u'%s/%s/%s' % (datelist[2], datelist[1], datelist[0]) 463 text = trans(_( 464 'Your Kofa student record was created on ${a}.', 465 mapping = {'a': creation_date}), 466 portal_language) 467 html = format_html(text) 468 data.append(Paragraph(html, NOTE_STYLE)) 469 470 # Create pdf stream 471 view.response.setHeader( 472 'Content-Type', 'application/pdf') 473 pdf_stream = creator.create_pdf( 474 data, None, doc_title, author=author, footer=footer_text, 475 note=None) 476 return pdf_stream 477 400 478 def renderPDF(self, view, filename='slip.pdf', student=None, 401 479 studentview=None, tableheader=None, tabledata=None, … … 428 506 429 507 # Insert widgets 430 data.append(Paragraph(view.title, style["Heading3"])) 431 portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE 432 separators = getattr(self, 'SEPARATORS_DICT', {}) 433 table = creator.getWidgetsTable( 434 view.form_fields, view.context, None, lang=portal_language, 435 separators=separators) 436 data.append(table) 508 if view.form_fields: 509 data.append(Paragraph(view.title, style["Heading3"])) 510 portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE 511 separators = getattr(self, 'SEPARATORS_DICT', {}) 512 table = creator.getWidgetsTable( 513 view.form_fields, view.context, None, lang=portal_language, 514 separators=separators) 515 data.append(table) 437 516 438 517 # Insert scanned docs -
main/waeup.kofa/branches/uli-async-update/src/waeup/kofa/students/viewlets.py
r9169 r9208 150 150 151 151 class ContactActionButton(ManageActionButton): 152 grok.order( 4)152 grok.order(5) 153 153 grok.context(IStudent) 154 154 grok.view(StudentBaseDisplayFormPage) … … 166 166 target = 'manage_base' 167 167 168 class AdmissionSlipActionButton(ManageActionButton): 169 grok.order(4) 170 grok.context(IStudent) 171 grok.view(StudentBaseDisplayFormPage) 172 grok.require('waeup.viewStudent') 173 icon = 'actionicon_pdf.png' 174 text = _('Download admission letter') 175 target = 'admission_slip.pdf' 176 168 177 class StudentTransfernButton(ManageActionButton): 169 grok.order( 5)178 grok.order(6) 170 179 grok.context(IStudent) 171 180 grok.view(StudentBaseDisplayFormPage) … … 176 185 177 186 class StudentDeactivateActionButton(ManageActionButton): 178 grok.order( 6)187 grok.order(7) 179 188 grok.context(IStudent) 180 189 grok.view(StudentBaseDisplayFormPage) … … 196 205 197 206 class StudentActivateActionButton(ManageActionButton): 198 grok.order( 6)207 grok.order(7) 199 208 grok.context(IStudent) 200 209 grok.view(StudentBaseDisplayFormPage) … … 624 633 @property 625 634 def targets(self): 626 student _url = self.view.application_url() + (627 '/students/%s' % self.request.principal.id)628 #app_slip = getUtility(IExtFileStore).getFileByContext(629 # self.context.student, 'application_slip')635 student = grok.getSite()['students'][self.request.principal.id] 636 student_url = self.view.url(student) 637 app_slip = getUtility(IExtFileStore).getFileByContext( 638 student, 'application_slip') 630 639 targets = [] 631 #if app_slip:632 #targets = [{'url':student_url + '/application_slip', 'title':'Application Slip'},]640 if app_slip: 641 targets = [{'url':student_url + '/application_slip', 'title':'Application Slip'},] 633 642 targets += [ 634 643 {'url':student_url, 'title':'Base Data'}, -
main/waeup.kofa/branches/uli-async-update/src/waeup/kofa/userscontainer.py
r9169 r9208 112 112 If `filepath` is ``None``, a raw string with CSV data is returned. 113 113 """ 114 writer, outfile = self.get_csv_writer(filepath)115 114 users = site.get('users', {}) 116 115 return self.export(users.values(), filepath) -
main/waeup.kofa/branches/uli-async-update/tools/fix_import_file.py
r9169 r9208 102 102 'type': 'company', 103 103 'date': 'date', 104 'core_or_elective': 'bool', 104 105 'category': 'p_category', 105 106 'reg_transition': 'reg_state', # we completely change this column, … … 205 206 """ 206 207 if len(value) == 7: 207 return ' B' + value208 return 'K' + value 208 209 return value 209 210 … … 324 325 if value == 'True': 325 326 return 'yes' 327 return 328 329 @classmethod 330 def bool(self, value, row): 331 """ True --> 1 332 """ 333 if value in ('TRUE', 'True'): 334 return '1' 335 elif value in ('FALSE', 'False'): 336 return '0' 326 337 return 327 338
Note: See TracChangeset for help on using the changeset viewer.