source: main/waeup.kofa/trunk/src/waeup/kofa/applicants/tests/test_browser.py @ 10844

Last change on this file since 10844 was 10843, checked in by Henrik Bettermann, 11 years ago

Add test which ensures that no error occurs if we unselect special_application.

  • Property svn:keywords set to Id
File size: 61.6 KB
Line 
1## $Id: test_browser.py 10843 2013-12-11 13:22:38Z henrik $
2##
3## Copyright (C) 2011 Uli Fouquet & Henrik Bettermann
4## This program is free software; you can redistribute it and/or modify
5## it under the terms of the GNU General Public License as published by
6## the Free Software Foundation; either version 2 of the License, or
7## (at your option) any later version.
8##
9## This program is distributed in the hope that it will be useful,
10## but WITHOUT ANY WARRANTY; without even the implied warranty of
11## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12## GNU General Public License for more details.
13##
14## You should have received a copy of the GNU General Public License
15## along with this program; if not, write to the Free Software
16## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17##
18"""
19Test the applicant-related UI components.
20"""
21import os
22import pytz
23import shutil
24import tempfile
25import grok
26from datetime import datetime
27from StringIO import StringIO
28from datetime import datetime, date, timedelta
29from mechanize import LinkNotFoundError
30from zc.async.testing import wait_for_result
31from zope.event import notify
32from zope.catalog.interfaces import ICatalog
33from zope.component import createObject, getUtility
34from zope.component.hooks import setSite, clearSite
35from zope.security.interfaces import Unauthorized
36from zope.testbrowser.testing import Browser
37from hurry.workflow.interfaces import IWorkflowInfo, IWorkflowState
38from waeup.kofa.testing import FunctionalLayer, FunctionalTestCase
39from waeup.kofa.app import University
40from waeup.kofa.payments.interfaces import IPayer
41from waeup.kofa.configuration import SessionConfiguration
42from waeup.kofa.applicants.container import ApplicantsContainer
43from waeup.kofa.applicants.applicant import Applicant
44from waeup.kofa.interfaces import (
45    IExtFileStore, IFileStoreNameChooser, IUserAccount, IJobManager)
46from waeup.kofa.university.faculty import Faculty
47from waeup.kofa.university.department import Department
48from waeup.kofa.tests.test_async import FunctionalAsyncTestCase
49
50PH_LEN = 15911  # Length of placeholder file
51
52session_1 = datetime.now().year - 2
53container_name_1 = u'app%s' % session_1
54session_2 = datetime.now().year - 1
55container_name_2 = u'app%s' % session_2
56
57class ApplicantsFullSetup(FunctionalTestCase):
58    # A test case that only contains a setup and teardown
59    #
60    # Complete setup for applicants handlings is rather complex and
61    # requires lots of things created before we can start. This is a
62    # setup that does all this, creates a university, creates PINs,
63    # etc.  so that we do not have to bother with that in different
64    # test cases.
65
66    layer = FunctionalLayer
67
68    def setUp(self):
69        super(ApplicantsFullSetup, self).setUp()
70
71        # Setup a sample site for each test
72        app = University()
73        self.dc_root = tempfile.mkdtemp()
74        app['datacenter'].setStoragePath(self.dc_root)
75
76        # Prepopulate the ZODB...
77        self.getRootFolder()['app'] = app
78        # we add the site immediately after creation to the
79        # ZODB. Catalogs and other local utilities are not setup
80        # before that step.
81        self.app = self.getRootFolder()['app']
82        # Set site here. Some of the following setup code might need
83        # to access grok.getSite() and should get our new app then
84        setSite(app)
85
86        self.login_path = 'http://localhost/app/login'
87        self.root_path = 'http://localhost/app/applicants'
88        self.search_path = 'http://localhost/app/applicants/search'
89        self.manage_root_path = self.root_path + '/@@manage'
90        self.add_container_path = self.root_path + '/@@add'
91        self.container_path = 'http://localhost/app/applicants/%s' % container_name_1
92        self.manage_container_path = self.container_path + '/@@manage'
93
94        # Add an applicants container
95        applicantscontainer = ApplicantsContainer()
96        applicantscontainer.code = container_name_1
97        applicantscontainer.prefix = 'app'
98        applicantscontainer.year = session_1
99        applicantscontainer.title = u'This is the %s container' % container_name_1
100        applicantscontainer.application_category = 'basic'
101        applicantscontainer.mode = 'create'
102        applicantscontainer.strict_deadline = True
103        delta = timedelta(days=10)
104        applicantscontainer.startdate = datetime.now(pytz.utc) - delta
105        applicantscontainer.enddate = datetime.now(pytz.utc) + delta
106        self.app['applicants'][container_name_1] = applicantscontainer
107        self.applicantscontainer = self.app['applicants'][container_name_1]
108
109        # Populate university
110        certificate = createObject('waeup.Certificate')
111        certificate.code = 'CERT1'
112        certificate.application_category = 'basic'
113        certificate.start_level = 100
114        certificate.end_level = 500
115        certificate.study_mode = u'ug_ft'
116        self.certificate = certificate
117        self.app['faculties']['fac1'] = Faculty()
118        # The code has explicitely to be set, otherwise we don't
119        # find created students in their department
120        self.app['faculties']['fac1']['dep1'] = Department(code=u'dep1')
121        self.department = self.app['faculties']['fac1']['dep1']
122        self.app['faculties']['fac1']['dep1'].certificates.addCertificate(
123            certificate)
124
125        # Put the prepopulated site into test ZODB and prepare test
126        # browser
127        self.browser = Browser()
128        self.browser.handleErrors = False
129
130        # Create 5 access codes with prefix'FOO' and cost 9.99 each
131        pin_container = self.app['accesscodes']
132        pin_container.createBatch(
133            datetime.now(), 'some_userid', 'APP', 9.99, 5)
134        pins = pin_container[pin_container.keys()[0]].values()
135        self.pins = [x.representation for x in pins]
136        self.existing_pin = self.pins[0]
137        parts = self.existing_pin.split('-')[1:]
138        self.existing_series, self.existing_number = parts
139
140        # Add an applicant
141        self.applicant = createObject('waeup.Applicant')
142        # reg_number is the only field which has to be preset here
143        # because managers are allowed to edit this required field
144        self.applicant.reg_number = u'1234'
145        self.applicant.course1 = certificate
146        app['applicants'][container_name_1].addApplicant(self.applicant)
147        IUserAccount(
148            self.app['applicants'][container_name_1][
149            self.applicant.application_number]).setPassword('apwd')
150        self.manage_path = 'http://localhost/app/applicants/%s/%s/%s' % (
151            container_name_1, self.applicant.application_number, 'manage')
152        self.edit_path = 'http://localhost/app/applicants/%s/%s/%s' % (
153            container_name_1, self.applicant.application_number, 'edit')
154        self.view_path = 'http://localhost/app/applicants/%s/%s' % (
155            container_name_1, self.applicant.application_number)
156
157    def login(self):
158        # Perform an applicant login. This creates an applicant record.
159        #
160        # This helper also sets `self.applicant`, which is the
161        # applicant object created.
162        self.browser.open(self.login_path)
163        self.browser.getControl(
164            name="form.login").value = self.applicant.applicant_id
165        self.browser.getControl(name="form.password").value = 'apwd'
166        self.browser.getControl("Login").click()
167
168    def fill_correct_values(self):
169        # Fill the edit form with suitable values
170        self.browser.getControl(name="form.firstname").value = 'John'
171        self.browser.getControl(name="form.middlename").value = 'Anthony'
172        self.browser.getControl(name="form.lastname").value = 'Tester'
173        self.browser.getControl(name="form.course1").value = ['CERT1']
174        self.browser.getControl(name="form.date_of_birth").value = '09/09/1988'
175        self.browser.getControl(name="form.sex").value = ['m']
176        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
177
178    def tearDown(self):
179        super(ApplicantsFullSetup, self).tearDown()
180        clearSite()
181        shutil.rmtree(self.dc_root)
182
183class ApplicantsRootUITests(ApplicantsFullSetup):
184    # Tests for ApplicantsRoot class
185
186    layer = FunctionalLayer
187
188    def test_anonymous_access(self):
189        # Anonymous users can access applicants root
190        self.browser.open(self.root_path)
191        self.assertEqual(self.browser.headers['Status'], '200 Ok')
192        self.assertFalse(
193            'Manage ' in self.browser.contents)
194        return
195
196    def test_anonymous_no_actions(self):
197        # Make sure anonymous users cannot access actions
198        self.browser.open(self.root_path)
199        self.assertRaises(
200            LookupError, self.browser.getControl, "Add local role")
201        # Manage screen neither linked nor accessible for anonymous
202        self.assertRaises(
203            LinkNotFoundError,
204            self.browser.getLink, 'Manage application section')
205        self.assertRaises(
206            Unauthorized, self.browser.open, self.manage_root_path)
207        # Add container screen not accessible for anonymous
208        self.assertRaises(
209            Unauthorized, self.browser.open, self.add_container_path)
210        return
211
212    def test_manage_access(self):
213        # Managers can access the manage pages of applicants root
214        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
215        self.browser.open(self.root_path)
216        self.assertTrue('Manage application section' in self.browser.contents)
217        # There is a manage link
218        link = self.browser.getLink('Manage application section')
219        link.click()
220        self.assertEqual(self.browser.headers['Status'], '200 Ok')
221        self.assertEqual(self.browser.url, self.manage_root_path)
222        return
223
224    def test_hide_container(self):
225        self.browser.open(self.root_path)
226        self.assertTrue(
227            '<a href="http://localhost/app/applicants/app2011">'
228            'This is the app2011 container</a>' in self.browser.contents)
229        self.app['applicants']['app2011'].hidden = True
230        self.browser.open(self.root_path)
231        # Anonymous users can't see hidden containers
232        self.assertFalse(
233            '<a href="http://localhost/app/applicants/app2011">'
234            'This is the app2011 container</a>' in self.browser.contents)
235        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
236        self.browser.open(self.root_path)
237        self.assertTrue(
238            '<a href="http://localhost/app/applicants/app2011">'
239            'This is the app2011 container</a>' in self.browser.contents)
240        return
241
242    def test_search(self):
243        # Managers can access the manage pages of applicants root
244        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
245        self.browser.open(self.manage_path)
246        self.fill_correct_values()
247        self.browser.getControl("Save").click()
248        self.browser.open(self.root_path)
249        self.assertTrue('Manage application section' in self.browser.contents)
250        # There is a search link
251        link = self.browser.getLink('Find applicants')
252        link.click()
253        self.assertEqual(self.browser.headers['Status'], '200 Ok')
254        # We can find an applicant ...
255        # ... via his name
256        self.browser.getControl(name="searchtype").value = ['fullname']
257        self.browser.getControl(name="searchterm").value = 'John'
258        self.browser.getControl("Find applicant").click()
259        self.assertTrue('John Anthony Tester' in self.browser.contents)
260        self.browser.getControl(name="searchtype").value = ['fullname']
261        self.browser.getControl(name="searchterm").value = 'Tester'
262        self.browser.getControl("Find applicant").click()
263        self.assertTrue('John Anthony Tester' in self.browser.contents)
264        self.browser.open(self.search_path)
265        # ... and via his reg_number ...
266        self.browser.getControl(name="searchtype").value = ['reg_number']
267        self.browser.getControl(name="searchterm").value = '2345'
268        self.browser.getControl("Find applicant").click()
269        self.assertFalse('John Anthony Tester' in self.browser.contents)
270        self.browser.getControl(name="searchtype").value = ['reg_number']
271        self.browser.getControl(name="searchterm").value = '1234'
272        self.browser.getControl("Find applicant").click()
273        self.assertTrue('John Anthony Tester' in self.browser.contents)
274        # ... and not via his application_number ...
275        self.browser.getControl(name="searchtype").value = ['applicant_id']
276        self.browser.getControl(
277            name="searchterm").value = self.applicant.application_number
278        self.browser.getControl("Find applicant").click()
279        self.assertFalse('John Anthony Tester' in self.browser.contents)
280        # ... but ia his applicant_id ...
281        self.browser.getControl(name="searchtype").value = ['applicant_id']
282        self.browser.getControl(
283            name="searchterm").value = self.applicant.applicant_id
284        self.browser.getControl("Find applicant").click()
285        self.assertTrue('John Anthony Tester' in self.browser.contents)
286        # ... and via his email
287        self.browser.getControl(name="searchtype").value = ['email']
288        self.browser.getControl(name="searchterm").value = 'xx@yy.zz'
289        self.browser.getControl("Find applicant").click()
290        self.assertTrue('John Anthony Tester' in self.browser.contents)
291        return
292
293    def test_manage_actions_access(self):
294        # Managers can access the action on manage screen
295        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
296        self.browser.open(self.manage_root_path)
297        self.browser.getControl("Add local role").click()
298        self.assertTrue('No user selected' in self.browser.contents)
299        return
300
301    def test_local_roles_add_delete(self):
302        # Managers can assign and delete local roles of applicants root
303        myusers = self.app['users']
304        myusers.addUser('bob', 'bobssecret')
305        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
306        self.browser.open('http://localhost/app/faculties/fac1/dep1/manage')
307        self.browser.getControl(name="user").value = ['bob']
308        self.browser.getControl(name="local_role").value = [
309            'waeup.local.ApplicationsManager']
310        self.browser.getControl("Add local role").click()
311        self.assertTrue('<td>bob</td>' in self.browser.contents)
312        # Remove the role assigned
313        ctrl = self.browser.getControl(name='role_id')
314        ctrl.getControl(
315            value='bob|waeup.local.ApplicationsManager').selected = True
316        self.browser.getControl("Remove selected local roles").click()
317        self.assertTrue(
318            'Local role successfully removed: bob|waeup.local.ApplicationsManager'
319            in self.browser.contents)
320        self.assertFalse('<td>bob</td>' in self.browser.contents)
321        return
322
323    def test_add_delete_container(self):
324        # Managers can add and delete applicants containers
325        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
326        self.browser.open(self.manage_root_path)
327        self.browser.getControl("Add applicants container").click()
328        self.assertEqual(self.browser.headers['Status'], '200 Ok')
329        self.assertEqual(self.browser.url, self.add_container_path)
330        self.browser.getControl(name="form.prefix").value = ['app']
331        self.browser.getControl("Add applicants container").click()
332        self.assertTrue(
333            'There were errors' in self.browser.contents)
334        self.browser.getControl(name="form.prefix").value = ['app']
335        self.browser.getControl(name="form.year").value = [str(session_2)]
336        self.browser.getControl(name="form.mode").value = ['create']
337        self.browser.getControl(
338            name="form.application_category").value = ['basic']
339        self.browser.getControl("Add applicants container").click()
340        self.assertTrue('Added:' in self.browser.contents)
341        self.browser.getLink("app2011").click()
342        self.assertTrue('Manage applicants container'
343            in self.browser.contents)
344        self.browser.open(self.add_container_path)
345        self.browser.getControl("Cancel").click()
346        self.assertEqual(self.browser.url, self.manage_root_path)
347        self.browser.open(self.add_container_path)
348        self.browser.getControl(name="form.prefix").value = ['app']
349        self.browser.getControl(name="form.year").value = [str(session_2)]
350        self.browser.getControl(name="form.mode").value = ['create']
351        self.browser.getControl(
352            name="form.application_category").value = ['basic']
353        self.browser.getControl("Add applicants container").click()
354        self.assertTrue('exists already in the database'
355                        in self.browser.contents)
356        self.browser.open(self.manage_root_path)
357        ctrl = self.browser.getControl(name='val_id')
358        ctrl.getControl(value=container_name_2).selected = True
359        self.browser.getControl("Remove selected", index=0).click()
360        self.assertTrue('Successfully removed:' in self.browser.contents)
361        self.browser.open(self.add_container_path)
362        self.browser.getControl(name="form.prefix").value = ['app']
363        self.browser.getControl(name="form.year").value = [str(session_2)]
364        self.browser.getControl(name="form.mode").value = ['create']
365        #self.browser.getControl(name="form.ac_prefix").value = ['APP']
366        self.browser.getControl(
367            name="form.application_category").value = ['basic']
368        self.browser.getControl("Add applicants container").click()
369        del self.app['applicants'][container_name_2]
370        ctrl = self.browser.getControl(name='val_id')
371        ctrl.getControl(value=container_name_2).selected = True
372        self.browser.getControl("Remove selected", index=0).click()
373        self.assertMatches('...Could not delete...', self.browser.contents)
374        return
375
376class ApplicantsContainerUITests(ApplicantsFullSetup):
377    # Tests for ApplicantsContainer class views and pages
378
379    layer = FunctionalLayer
380
381    def test_anonymous_access(self):
382        # Anonymous users can access applicants containers
383        self.browser.open(self.container_path)
384        self.assertEqual(self.browser.headers['Status'], '200 Ok')
385        self.assertFalse(
386            'Manage ' in self.browser.contents)
387        return
388
389    def test_manage_access(self):
390        # Managers can access the manage pages of applicants
391        # containers and can perform actions
392        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
393        self.browser.open(self.manage_container_path)
394        self.assertEqual(self.browser.headers['Status'], '200 Ok')
395        self.assertEqual(self.browser.url, self.manage_container_path)
396        self.browser.getControl(name="form.application_fee").value = '200'
397        self.browser.getControl("Save").click()
398        self.assertTrue('Form has been saved' in self.browser.contents)
399        logfile = os.path.join(
400            self.app['datacenter'].storage, 'logs', 'applicants.log')
401        logcontent = open(logfile).read()
402        self.assertTrue(
403            'zope.mgr - applicants.browser.ApplicantsContainerManageFormPage - '
404            'app2011 - saved: application_fee\n' in logcontent)
405        self.browser.getControl("Remove selected", index=0).click()
406        self.assertTrue('No applicant selected' in self.browser.contents)
407        self.browser.getControl("Add local role").click()
408        self.assertTrue('No user selected' in self.browser.contents)
409        self.browser.getControl("Cancel", index=0).click()
410        self.assertEqual(self.browser.url, self.container_path)
411        return
412
413    def test_statistics(self):
414        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
415        self.browser.open(self.container_path)
416        self.browser.getLink("Container statistics").click()
417        self.assertTrue('<td>initialized</td>' in self.browser.contents)
418        self.assertTrue('<td>1</td>' in self.browser.contents)
419        self.assertEqual(self.applicantscontainer.statistics[0],
420            {'not admitted': 0, 'started': 0, 'created': 0,
421            'admitted': 0, 'submitted': 0, 'initialized': 1, 'paid': 0})
422        #self.assertEqual(self.applicantscontainer.statistics[1],
423        #    {u'fac1': 0})
424        IWorkflowState(self.applicant).setState('submitted')
425        notify(grok.ObjectModifiedEvent(self.applicant))
426        self.assertEqual(self.applicantscontainer.statistics[0],
427            {'not admitted': 0, 'started': 0, 'created': 0,
428            'admitted': 0, 'submitted': 1, 'initialized': 0, 'paid': 0})
429        #self.assertEqual(self.applicantscontainer.statistics[1],
430        #    {u'fac1': 1})
431        return
432
433    def test_add_delete_applicants(self):
434        # Managers can add and delete applicants
435        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
436        self.add_applicant_path = self.container_path + '/addapplicant'
437        self.container_manage_path = self.container_path + '/@@manage'
438        self.browser.open(self.container_manage_path)
439        self.browser.getLink("Add applicant").click()
440        self.assertEqual(self.browser.headers['Status'], '200 Ok')
441        self.assertEqual(self.browser.url, self.add_applicant_path)
442        self.browser.getControl(name="form.firstname").value = 'Alois'
443        self.browser.getControl(name="form.middlename").value = 'Kofi'
444        self.browser.getControl(name="form.lastname").value = 'Bettermann'
445        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
446        self.browser.getControl("Create application record").click()
447        self.assertTrue('Application initialized' in self.browser.contents)
448        self.browser.open(self.container_manage_path)
449        self.assertEqual(self.browser.headers['Status'], '200 Ok')
450        ctrl = self.browser.getControl(name='val_id')
451        value = ctrl.options[0]
452        ctrl.getControl(value=value).selected = True
453        self.browser.getControl("Remove selected", index=0).click()
454        self.assertTrue('Successfully removed:' in self.browser.contents)
455        self.browser.open(self.add_applicant_path)
456        self.browser.getControl(name="form.firstname").value = 'Albert'
457        self.browser.getControl(name="form.lastname").value = 'Einstein'
458        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
459        self.browser.getControl("Create application record").click()
460        self.assertTrue('Application initialized' in self.browser.contents)
461        return
462
463class ApplicantUITests(ApplicantsFullSetup):
464    # Tests for uploading/browsing the passport image of appplicants
465
466    layer = FunctionalLayer
467
468    def test_manage_and_view_applicant(self):
469        # Managers can manage applicants
470        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
471        self.slip_path = self.view_path + '/application_slip.pdf'
472        self.browser.open(self.manage_path)
473        self.assertEqual(self.browser.headers['Status'], '200 Ok')
474        self.fill_correct_values()
475        # Fire transition
476        self.browser.getControl(name="transition").value = ['start']
477        self.browser.getControl("Save").click()
478        # Be sure that the empty phone field does not show wrong error message
479        self.assertFalse('Required input is missing' in self.browser.contents)
480        self.assertMatches('...Form has been saved...', self.browser.contents)
481        self.assertMatches('...Application started by Manager...',
482                           self.browser.contents)
483        self.browser.open(self.view_path)
484        self.assertEqual(self.browser.headers['Status'], '200 Ok')
485        # Change course_admitted
486        self.browser.open(self.manage_path)
487        self.browser.getControl(name="form.course_admitted").value = ['CERT1']
488        self.browser.getControl("Save").click()
489        self.assertMatches('...Form has been saved...', self.browser.contents)
490        # Change password
491        self.browser.getControl(name="password").value = 'secret'
492        self.browser.getControl(name="control_password").value = 'secre'
493        self.browser.getControl("Save").click()
494        self.assertMatches('...Passwords do not match...',
495                           self.browser.contents)
496        self.browser.getControl(name="password").value = 'secret'
497        self.browser.getControl(name="control_password").value = 'secret'
498        self.browser.getControl("Save").click()
499        self.assertMatches('...Form has been saved...', self.browser.contents)
500        # Pdf slip can't be opened and download button is not available
501        self.assertFalse('Download application slip' in self.browser.contents)
502        self.browser.open(self.slip_path)
503        self.assertTrue(
504            'Please pay and submit before trying to download the application slip.'
505            in self.browser.contents)
506        # If applicant is in correct state the pdf slip can be opened.
507        IWorkflowState(self.applicant).setState('submitted')
508        self.browser.open(self.manage_path)
509        self.browser.getLink("Download application slip").click()
510        self.assertEqual(self.browser.headers['Status'], '200 Ok')
511        self.assertEqual(self.browser.headers['Content-Type'],
512                         'application/pdf')
513        # Managers can view applicants even if certificate has been removed
514        del self.app['faculties']['fac1']['dep1'].certificates['CERT1']
515        self.browser.open(self.view_path)
516        self.assertEqual(self.browser.headers['Status'], '200 Ok')
517        self.browser.open(self.slip_path)
518        self.assertEqual(self.browser.headers['Status'], '200 Ok')
519        return
520
521    def test_passport_edit_view(self):
522        # We get a default image after login
523        self.browser.open(self.login_path)
524        self.login()
525        self.browser.open(self.browser.url + '/passport.jpg')
526        self.assertEqual(self.browser.headers['status'], '200 Ok')
527        self.assertEqual(self.browser.headers['content-type'], 'image/jpeg')
528        self.assertTrue('JFIF' in self.browser.contents)
529        self.assertEqual(
530            self.browser.headers['content-length'], str(PH_LEN))
531
532    def test_applicant_login(self):
533        self.applicant.suspended = True
534        self.login()
535        self.assertTrue(
536            'You entered invalid credentials.' in self.browser.contents)
537        self.applicant.suspended = False
538        self.browser.getControl("Login").click()
539        self.assertTrue(
540            'You logged in.' in self.browser.contents)
541
542    def test_applicant_access(self):
543        # Applicants can edit their record
544        self.browser.open(self.login_path)
545        self.login()
546        self.assertTrue(
547            'You logged in.' in self.browser.contents)
548        self.browser.open(self.edit_path)
549        self.assertTrue(self.browser.url != self.login_path)
550        self.assertEqual(self.browser.headers['Status'], '200 Ok')
551        self.fill_correct_values()
552        self.assertTrue(IUserAccount(self.applicant).checkPassword('apwd'))
553        self.browser.getControl("Save").click()
554        self.assertMatches('...Form has been saved...', self.browser.contents)
555        # Applicants don't see manage and search links ...
556        self.browser.open(self.root_path)
557        self.assertEqual(self.browser.headers['Status'], '200 Ok')
558        self.assertFalse('Search' in self.browser.contents)
559        self.assertFalse('Manage application section' in self.browser.contents)
560        # ... and can't access the manage page
561        self.assertRaises(
562            Unauthorized, self.browser.open, self.manage_path)
563        return
564
565    def image_url(self, filename):
566        return self.edit_path.replace('edit', filename)
567
568    def test_after_login_default_browsable(self):
569        # After login we see the placeholder image in the edit view
570        self.login()
571        self.assertEqual(self.browser.url, self.view_path)
572        self.browser.open(self.edit_path)
573        # There is a correct <img> link included
574        self.assertTrue(
575              '<img src="passport.jpg" height="180px" />' in self.browser.contents)
576        # Browsing the link shows a real image
577        self.browser.open(self.image_url('passport.jpg'))
578        self.assertEqual(
579            self.browser.headers['content-type'], 'image/jpeg')
580        self.assertEqual(len(self.browser.contents), PH_LEN)
581
582    def test_after_submit_default_browsable(self):
583        # After submitting an applicant form the default image is
584        # still visible
585        self.login()
586        self.browser.open(self.edit_path)
587        self.browser.getControl("Save").click() # submit form
588        # There is a correct <img> link included
589        self.assertTrue(
590            '<img src="passport.jpg" height="180px" />' in self.browser.contents)
591        # Browsing the link shows a real image
592        self.browser.open(self.image_url('passport.jpg'))
593        self.assertEqual(
594            self.browser.headers['content-type'], 'image/jpeg')
595        self.assertEqual(len(self.browser.contents), PH_LEN)
596
597    def test_uploaded_image_respects_file_size_restriction(self):
598        # When we upload an image that is too big ( > 10 KB) we will
599        # get an error message
600        self.login()
601        self.browser.open(self.edit_path)
602        # Create a pseudo image file and select it to be uploaded in form
603        photo_content = 'A' * 1024 * 21  # A string of 21 KB size
604        pseudo_image = StringIO(photo_content)
605        ctrl = self.browser.getControl(name='form.passport')
606        file_ctrl = ctrl.mech_control
607        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
608        self.browser.getControl("Save").click() # submit form
609        # There is a correct <img> link included
610        self.assertTrue(
611            '<img src="passport.jpg" height="180px" />' in self.browser.contents)
612        # We get a warning message
613        self.assertTrue(
614            'Uploaded image is too big' in self.browser.contents)
615        # Browsing the image gives us the default image, not the
616        # uploaded one.
617        self.browser.open(self.image_url('passport.jpg'))
618        self.assertEqual(
619            self.browser.headers['content-type'], 'image/jpeg')
620        self.assertEqual(len(self.browser.contents), PH_LEN)
621        # There is really no file stored for the applicant
622        img = getUtility(IExtFileStore).getFile(
623            IFileStoreNameChooser(self.applicant).chooseName())
624        self.assertTrue(img is None)
625
626    def test_uploaded_image_browsable_w_errors(self):
627        # We can upload a different image and browse it after submit,
628        # even if there are still errors in the form
629        self.login()
630        self.browser.open(self.edit_path)
631        # Create a pseudo image file and select it to be uploaded in form
632        photo_content = 'I pretend to be a graphics file'
633        pseudo_image = StringIO(photo_content)
634        ctrl = self.browser.getControl(name='form.passport')
635        file_ctrl = ctrl.mech_control
636        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
637        self.browser.getControl("Save").click() # submit form
638        # There is a correct <img> link included
639        self.assertTrue(
640            '<img src="passport.jpg" height="180px" />' in self.browser.contents)
641        # Browsing the link shows a real image
642        self.browser.open(self.image_url('passport.jpg'))
643        self.assertEqual(
644            self.browser.headers['content-type'], 'image/jpeg')
645        self.assertEqual(self.browser.contents, photo_content)
646
647    def test_uploaded_image_stored_in_imagestorage_w_errors(self):
648        # After uploading a new passport pic the file is correctly
649        # stored in an imagestorage
650        self.login()
651        self.browser.open(self.edit_path)
652        # Create a pseudo image file and select it to be uploaded in form
653        pseudo_image = StringIO('I pretend to be a graphics file')
654        ctrl = self.browser.getControl(name='form.passport')
655        file_ctrl = ctrl.mech_control
656        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
657        self.browser.getControl("Save").click() # submit form
658        storage = getUtility(IExtFileStore)
659        file_id = IFileStoreNameChooser(self.applicant).chooseName()
660        pseudo_image.seek(0) # reset our file data source
661        self.assertEqual(
662            storage.getFile(file_id).read(), pseudo_image.read())
663        return
664
665    def test_uploaded_image_browsable_wo_errors(self):
666        # We can upload a different image and browse it after submit,
667        # if there are no errors in form
668        self.login()
669        self.browser.open(self.edit_path)
670        self.fill_correct_values() # fill other fields with correct values
671        # Create a pseudo image file and select it to be uploaded in form
672        pseudo_image = StringIO('I pretend to be a graphics file')
673        ctrl = self.browser.getControl(name='form.passport')
674        file_ctrl = ctrl.mech_control
675        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
676        self.browser.getControl("Save").click() # submit form
677        # There is a correct <img> link included
678        self.assertTrue(
679            '<img src="passport.jpg" height="180px" />' in self.browser.contents)
680        # Browsing the link shows a real image
681        self.browser.open(self.image_url('passport.jpg'))
682        self.assertEqual(
683            self.browser.headers['content-type'], 'image/jpeg')
684        self.assertEqual(len(self.browser.contents), 31)
685
686    def test_uploaded_image_stored_in_imagestorage_wo_errors(self):
687        # After uploading a new passport pic the file is correctly
688        # stored in an imagestorage if form contains no errors
689        self.login()
690        self.browser.open(self.edit_path)
691        self.fill_correct_values() # fill other fields with correct values
692        # Create a pseudo image file and select it to be uploaded in form
693        pseudo_image = StringIO('I pretend to be a graphics file')
694        ctrl = self.browser.getControl(name='form.passport')
695        file_ctrl = ctrl.mech_control
696        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
697        self.browser.getControl("Save").click() # submit form
698        storage = getUtility(IExtFileStore)
699        file_id = IFileStoreNameChooser(self.applicant).chooseName()
700        # The stored image can be fetched
701        fd = storage.getFile(file_id)
702        file_len = len(fd.read())
703        self.assertEqual(file_len, 31)
704        # When an applicant is removed, also the image is gone.
705        del self.app['applicants']['app2011'][self.applicant.application_number]
706        fd = storage.getFile(file_id)
707        self.assertTrue(fd is None)
708
709    def test_uploaded_images_equal(self):
710        # Make sure uploaded images do really differ if we eject a
711        # change notfication (and do not if we don't)
712        self.login()
713        self.browser.open(self.edit_path)
714        self.fill_correct_values() # fill other fields with correct values
715        self.browser.getControl("Save").click() # submit form
716        # Now go on as an officer
717        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
718        self.browser.open(self.manage_path)
719
720        # Create a pseudo image file and select it to be uploaded in form
721        pseudo_image = StringIO('I pretend to be a graphics file')
722        ctrl = self.browser.getControl(name='form.passport')
723        file_ctrl = ctrl.mech_control
724        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
725        file_id = IFileStoreNameChooser(self.applicant).chooseName()
726        setSite(self.app)
727        passport0 = getUtility(IExtFileStore).getFile(file_id)
728        self.browser.getControl("Save").click() # submit form with changed pic
729        passport1 = getUtility(IExtFileStore).getFile(file_id).read()
730        self.browser.getControl("Save").click() # submit form w/o changes
731        passport2 = getUtility(IExtFileStore).getFile(file_id).read()
732        self.assertTrue(passport0 is None)
733        self.assertTrue(passport0 != passport1)
734        self.assertTrue(passport1 == passport2)
735        return
736
737    def test_upload_image_by_manager_with_logging(self):
738        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
739        self.browser.open(self.manage_path)
740        # Create a pseudo image file and select it to be uploaded in form
741        photo_content = 'A' * 1024 * 5  # A string of 5 KB size
742        pseudo_image = StringIO(photo_content)
743        ctrl = self.browser.getControl(name='form.passport')
744        file_ctrl = ctrl.mech_control
745        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
746        self.browser.getControl("Save").click() # submit form
747        # Even though the form could not be saved ...
748        self.assertTrue(
749            'Required input is missing' in self.browser.contents)
750        # ... the file has been successfully uploaded
751        logfile = os.path.join(
752            self.app['datacenter'].storage, 'logs', 'applicants.log')
753        logcontent = open(logfile).read()
754        self.assertTrue(
755            'zope.mgr - applicants.browser.ApplicantManageFormPage - '
756            '%s - saved: passport'
757            % (self.applicant.applicant_id)
758            in logcontent)
759
760    def test_pay_portal_application_fee(self):
761        self.login()
762        self.browser.open(self.edit_path)
763        # Payment tickets can't be created before the form has been validated
764        self.browser.getControl("Add online payment ticket").click()
765        self.assertTrue('Required input is missing' in self.browser.contents)
766        self.fill_correct_values()
767        # We have to save the form otherwise the filled fields will be cleared
768        # after adding an online payment, because adding an online payment
769        # requires a filled form but does not save it
770        self.browser.getControl("Save").click()
771        self.browser.getControl("Add online payment ticket").click()
772        # Session object missing
773        self.assertTrue(
774            'Session configuration object is not available'
775            in self.browser.contents)
776        configuration = SessionConfiguration()
777        configuration.academic_session = session_1
778        configuration.application_fee = 200.0
779        self.app['configuration'].addSessionConfiguration(configuration)
780        self.browser.open(self.edit_path)
781        self.browser.getControl("Add online payment ticket").click()
782        self.assertMatches('...Payment ticket created...',
783                           self.browser.contents)
784        self.assertMatches('...Activation Code...',
785                           self.browser.contents)
786        # Payment ticket can be removed if they haven't received a
787        # valid callback
788        self.browser.open(self.edit_path)
789        ctrl = self.browser.getControl(name='val_id')
790        value = ctrl.options[0]
791        ctrl.getControl(value=value).selected = True
792        self.browser.getControl("Remove selected", index=0).click()
793        self.assertMatches('...Successfully removed...', self.browser.contents)
794        # We will try the callback request view
795        self.browser.getControl("Add online payment ticket").click()
796        self.browser.open(self.edit_path)
797        ctrl = self.browser.getControl(name='val_id')
798        value = ctrl.options[0]
799        self.browser.getLink(value).click()
800        self.assertMatches('...Amount Authorized...',
801                           self.browser.contents)
802        payment_url = self.browser.url
803        payment_id = self.applicant.keys()[0]
804        payment = self.applicant[payment_id]
805        self.assertEqual(payment.p_item,'This is the %s container' % container_name_1)
806        self.assertEqual(payment.p_session, session_1)
807        self.assertEqual(payment.p_category,'application')
808        self.assertEqual(payment.amount_auth,200.0)
809        # Applicant is payer of the payment ticket.
810        self.assertEqual(
811            IPayer(payment).display_fullname, 'John Anthony Tester')
812        self.assertEqual(
813            IPayer(payment).id, self.applicant.applicant_id)
814        self.assertEqual(IPayer(payment).faculty, 'N/A')
815        self.assertEqual(IPayer(payment).department, 'N/A')
816        # The pdf payment slip can't yet be opened
817        #self.browser.open(payment_url + '/payment_receipt.pdf')
818        #self.assertMatches('...Ticket not yet paid...',
819        #                   self.browser.contents)
820        # Approve payment
821        # Applicants can't approve payments
822        self.assertRaises(
823            Unauthorized, self.browser.open, payment_url + '/approve')
824        # We approve the payment by bypassing the view
825        payment.approve()
826        # The payment slip can be downloaded now
827        self.browser.open(payment_url)
828        self.browser.getLink("Download payment slip").click()
829        self.assertEqual(self.browser.headers['Status'], '200 Ok')
830        self.assertEqual(self.browser.headers['Content-Type'],
831                         'application/pdf')
832        # Applicant is is not yet in state 'paid' because it was only
833        # the payment which we set to paid
834        self.browser.open(self.view_path)
835        self.assertMatches('...started...',
836                           self.browser.contents)
837        self.assertTrue(self.applicant.state == 'started')
838        # Let's logout and approve the payment as manager
839        self.browser.getLink("Logout").click()
840        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
841        # First we reset the payment
842        payment.r_amount_approved = 0.0
843        payment.r_code = u''
844        payment.p_state = 'unpaid'
845        payment.r_desc = u''
846        payment.payment_date = None
847        self.browser.open(payment_url)
848        self.browser.getLink("Approve payment").click()
849        self.assertEqual(payment.p_state, 'paid')
850        self.assertEqual(payment.r_amount_approved, 200.0)
851        self.assertEqual(payment.r_code, 'AP')
852        self.assertTrue(self.applicant.state == 'paid')
853        # Approval is logged in students.log ...
854        logfile = os.path.join(
855            self.app['datacenter'].storage, 'logs', 'applicants.log')
856        logcontent = open(logfile).read()
857        self.assertTrue(
858            'zope.mgr - applicants.browser.OnlinePaymentApprovePage - '
859            '%s - payment approved' % self.applicant.applicant_id
860            in logcontent)
861        # ... and in payments.log
862        logfile = os.path.join(
863            self.app['datacenter'].storage, 'logs', 'payments.log')
864        logcontent = open(logfile).read()
865        self.assertTrue(
866            '"zope.mgr",%s,%s,application,200.0,AP,,,,,,\n'
867            % (self.applicant.applicant_id, payment.p_id)
868            in logcontent)
869        return
870
871    def test_pay_container_application_fee(self):
872        self.login()
873        self.browser.open(self.edit_path)
874        self.fill_correct_values()
875        self.browser.getControl("Save").click()
876        configuration = SessionConfiguration()
877        configuration.academic_session = session_1
878        self.applicantscontainer.application_fee = 120.0
879        configuration.application_fee = 9999.9
880        self.app['configuration'].addSessionConfiguration(configuration)
881        self.browser.open(self.edit_path)
882        self.browser.getControl("Add online payment ticket").click()
883        self.assertMatches('...Payment ticket created...',
884                           self.browser.contents)
885        self.assertMatches('...Payment ticket created...',
886                           self.browser.contents)
887        self.assertFalse(
888            '<span>9999.9</span>' in self.browser.contents)
889        self.assertTrue(
890            '<span>120.0</span>' in self.browser.contents)
891        self.assertTrue(
892            '<span>Application Fee</span>' in self.browser.contents)
893        return
894
895    def prepare_special_container(self):
896        # Add special application container
897        container_name = u'special%s' % session_1
898        applicantscontainer = ApplicantsContainer()
899        applicantscontainer.code = container_name
900        applicantscontainer.prefix = 'special'
901        applicantscontainer.year = session_1
902        applicantscontainer.title = u'This is a special app container'
903        applicantscontainer.application_category = 'no'
904        applicantscontainer.mode = 'create'
905        applicantscontainer.strict_deadline = True
906        delta = timedelta(days=10)
907        applicantscontainer.startdate = datetime.now(pytz.utc) - delta
908        applicantscontainer.enddate = datetime.now(pytz.utc) + delta
909        self.app['applicants'][container_name] = applicantscontainer
910        # Add an applicant
911        applicant = createObject('waeup.Applicant')
912        # reg_number is the only field which has to be preset here
913        # because managers are allowed to edit this required field
914        applicant.reg_number = u'12345'
915        self.special_applicant = applicant
916        self.app['applicants'][container_name].addApplicant(applicant)
917        IUserAccount(
918            self.app['applicants'][container_name][
919            applicant.application_number]).setPassword('apwd')
920        # Add session configuration object
921        configuration = SessionConfiguration()
922        configuration.academic_session = session_1
923        configuration.transcript_fee = 200.0
924        self.app['configuration'].addSessionConfiguration(configuration)
925
926
927    def test_pay_special_fee(self):
928        self.prepare_special_container()
929        # Login
930        self.browser.open(self.login_path)
931        self.browser.getControl(
932            name="form.login").value = self.special_applicant.applicant_id
933        self.browser.getControl(name="form.password").value = 'apwd'
934        self.browser.getControl("Login").click()
935        applicant_path = self.browser.url
936        self.browser.getLink("Edit application record").click()
937        self.browser.getControl(name="form.firstname").value = 'John'
938        self.browser.getControl(name="form.middlename").value = 'Anthony'
939        self.browser.getControl(name="form.lastname").value = 'Tester'
940        self.browser.getControl(name="form.special_application").value = [
941            'transcript']
942        self.browser.getControl(name="form.date_of_birth").value = '09/09/1988'
943        #self.browser.getControl(name="form.sex").value = ['m']
944        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
945        self.browser.getControl("Save").click()
946        self.browser.getControl("Add online payment ticket").click()
947        self.assertMatches('...Payment ticket created...',
948                           self.browser.contents)
949        self.assertTrue(
950            '<span>Transcript Fee</span>' in self.browser.contents)
951        self.assertTrue(
952            'This is a special app container' in self.browser.contents)
953        self.assertTrue(
954            '<span>200.0</span>' in self.browser.contents)
955        self.browser.getLink("Logout").click()
956        # Login as manager
957        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
958        self.browser.open(applicant_path + '/manage')
959        # When unselecting special_application, the payment ticket
960        # can still be created.
961        self.browser.getControl(name="form.special_application").value = [
962            '']
963        self.browser.getControl("Save").click()
964        self.browser.getControl("Add online payment ticket").click()
965        self.assertMatches('...Payment ticket created...',
966                           self.browser.contents)
967        self.assertMatches('...<span>--</span>...',
968                           self.browser.contents)
969        return
970
971    def test_duplicate_choice(self):
972        # Make sure that that 1st and 2nd choice are different
973        self.login()
974        self.browser.open(self.edit_path)
975        self.fill_correct_values() # fill other fields with correct values
976        self.browser.getControl(name="form.course2").value = ['CERT1']
977        self.browser.getControl("Save").click()
978        self.assertTrue(
979            '1st and 2nd choice must be different' in self.browser.contents)
980        self.browser.getControl(name="form.course2").value = []
981        self.browser.getControl("Save").click()
982        self.assertTrue('Form has been saved' in self.browser.contents)
983        return
984
985    def test_final_submit(self):
986        # Make sure that a correctly filled form with passport picture
987        # can be submitted (only) after payment
988        self.login()
989        self.browser.getLink("Edit application record").click()
990        self.assertFalse('Final Submit' in self.browser.contents)
991        IWorkflowInfo(self.applicant).fireTransition('pay')
992        self.browser.open(self.edit_path)
993        self.assertTrue('Final Submit' in self.browser.contents)
994        self.fill_correct_values() # fill other fields with correct values
995        self.browser.getControl("Save").click()
996        self.browser.getControl("Final Submit").click()
997        # We forgot to upload a passport picture
998        self.assertTrue(
999            'No passport picture uploaded' in self.browser.contents)
1000        # Create a pseudo image file and select it to be uploaded in form
1001        pseudo_image = StringIO('I pretend to be a graphics file')
1002        ctrl = self.browser.getControl(name='form.passport')
1003        file_ctrl = ctrl.mech_control
1004        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
1005        self.browser.getControl("Final Submit").click() # (finally) submit form
1006        # The picture has been uploaded but the form cannot be submitted
1007        # since the passport confirmation box was not ticked
1008        self.assertTrue(
1009            'Passport picture confirmation box not ticked'
1010            in self.browser.contents)
1011        self.browser.getControl(name="confirm_passport").value = True
1012        # If application period has expired and strict-deadline is set
1013        # applicants do notsee edit button and can't open
1014        # the edit form.
1015        self.applicantscontainer.enddate = datetime.now(pytz.utc)
1016        self.browser.open(self.view_path)
1017        self.assertFalse(
1018            'Edit application record' in self.browser.contents)
1019        self.browser.open(self.edit_path)
1020        self.assertTrue(
1021            'form is locked' in self.browser.contents)
1022        # We can either postpone the enddate ...
1023        self.applicantscontainer.enddate = datetime.now(
1024            pytz.utc) + timedelta(days=10)
1025        self.browser.open(self.edit_path)
1026        self.browser.getControl(name="confirm_passport").value = True
1027        self.browser.getControl("Final Submit").click()
1028        self.assertTrue(
1029            'Application submitted' in self.browser.contents)
1030        # ... or allow submission after deadline.
1031        IWorkflowState(self.applicant).setState('paid')
1032        self.applicant.locked = False
1033        self.applicantscontainer.strict_deadline = False
1034        self.browser.open(self.edit_path)
1035        self.browser.getControl(name="confirm_passport").value = True
1036        self.browser.getControl("Final Submit").click()
1037        self.assertTrue(
1038            'Application submitted' in self.browser.contents)
1039        self.browser.goBack(count=1)
1040        self.browser.getControl("Save").click()
1041        # The form is locked.
1042        self.assertTrue(self.applicant.locked)
1043        self.assertTrue(
1044            'The requested form is locked' in self.browser.contents)
1045        self.browser.goBack(count=1)
1046        self.browser.getControl("Final Submit").click()
1047        self.assertTrue(
1048            'The requested form is locked' in self.browser.contents)
1049        return
1050
1051    def test_locking(self):
1052        # Make sure that locked forms can't be submitted
1053        self.login()
1054        self.browser.open(self.edit_path)
1055        self.fill_correct_values() # fill other fields with correct values
1056        # Create a pseudo image file and select it to be uploaded in form
1057        pseudo_image = StringIO('I pretend to be a graphics file')
1058        ctrl = self.browser.getControl(name='form.passport')
1059        file_ctrl = ctrl.mech_control
1060        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
1061        self.browser.getControl("Save").click()
1062        # Now we lock the form
1063        self.applicant.locked = True
1064        self.browser.open(self.edit_path)
1065        self.assertEqual(self.browser.headers['Status'], '200 Ok')
1066        self.assertTrue(
1067            'The requested form is locked' in self.browser.contents)
1068        return
1069
1070    def test_certificate_removed(self):
1071        self.login()
1072        self.browser.open(self.edit_path)
1073        self.fill_correct_values()
1074        self.browser.getControl("Save").click()
1075        self.browser.open(self.view_path)
1076        self.assertTrue(
1077            'Unnamed Certificate' in self.browser.contents)
1078        self.browser.open(self.edit_path)
1079        self.assertTrue(
1080            '<option selected="selected" value="CERT1">' in self.browser.contents)
1081        # Now we remove the certificate
1082        del self.app['faculties']['fac1']['dep1'].certificates['CERT1']
1083        # The certificate is still shown in display mode
1084        self.browser.open(self.view_path)
1085        self.assertTrue(
1086            'Unnamed Certificate' in self.browser.contents)
1087        # The certificate is still selectable in edit mode so that it won't
1088        # be automatically replaced by another (arbitrary) certificate
1089        self.browser.open(self.edit_path)
1090        self.assertTrue(
1091            '<option selected="selected" value="CERT1">' in self.browser.contents)
1092        # Consequently, the certificate is still shown after saving the form
1093        self.browser.getControl("Save").click()
1094        self.browser.open(self.view_path)
1095        self.assertTrue(
1096            'Unnamed Certificate' in self.browser.contents)
1097        # Even if we add a new certificate the previous (removed)
1098        # certificate is shown
1099        certificate = createObject('waeup.Certificate')
1100        certificate.code = 'CERT2'
1101        certificate.title = 'New Certificate'
1102        certificate.application_category = 'basic'
1103        self.app['faculties']['fac1']['dep1'].certificates.addCertificate(
1104            certificate)
1105        self.browser.open(self.edit_path)
1106        self.assertTrue(
1107            '<option selected="selected" value="CERT1">'
1108            in self.browser.contents)
1109
1110class ApplicantRegisterTests(ApplicantsFullSetup):
1111    # Tests for applicant registration
1112
1113    layer = FunctionalLayer
1114
1115    def test_register_applicant_create(self):
1116        # An applicant can register himself.
1117        self.browser.open(self.container_path)
1118        self.browser.getLink("Register for application").click()
1119        # Fill the edit form with suitable values
1120        self.browser.getControl(name="form.firstname").value = 'Anna'
1121        self.browser.getControl(name="form.lastname").value = 'Kurios'
1122        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
1123        self.browser.getControl(name="form.phone.country").value = ['+234']
1124        self.browser.getControl(name="form.phone.area").value = '555'
1125        self.browser.getControl(name="form.phone.ext").value = '6666666'
1126        self.browser.getControl("Send login credentials").click()
1127        self.assertEqual(self.browser.url,
1128            self.container_path + '/registration_complete?email=xx%40yy.zz')
1129        # The new applicant can be found in the catalog via the email address
1130        cat = getUtility(ICatalog, name='applicants_catalog')
1131        results = list(
1132            cat.searchResults(email=('xx@yy.zz', 'xx@yy.zz')))
1133        applicant = results[0]
1134        self.assertEqual(applicant.lastname,'Kurios')
1135        # The application_id has been copied to the reg_number
1136        self.assertEqual(applicant.applicant_id, applicant.reg_number)
1137        # The applicant can be found in the catalog via the reg_number
1138        results = list(
1139            cat.searchResults(
1140            reg_number=(applicant.reg_number, applicant.reg_number)))
1141        self.assertEqual(applicant,results[0])
1142        return
1143
1144    def test_register_applicant_update(self):
1145        # We change the application mode and check if applicants
1146        # can find and update imported records instead of creating new records.
1147        # First we check what happens if record does not exist.
1148        self.applicantscontainer.mode = 'update'
1149        self.browser.open(self.container_path + '/register')
1150        self.browser.getControl(name="form.firstname").value = 'John'
1151        self.browser.getControl(name="form.reg_number").value = 'anynumber'
1152        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
1153        self.browser.getControl("Send login credentials").click()
1154        self.assertTrue('No application record found.'
1155            in self.browser.contents)
1156        # Even with the correct reg_number we can't register
1157        # because firstname attribute is not set.
1158        self.applicantscontainer.mode = 'update'
1159        self.browser.open(self.container_path + '/register')
1160        self.browser.getControl(name="form.firstname").value = 'John'
1161        self.browser.getControl(name="form.reg_number").value = '1234'
1162        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
1163        self.browser.getControl("Send login credentials").click()
1164        self.assertTrue('An error occurred.' in self.browser.contents)
1165        # Let's set this attribute manually
1166        # and try to register with a wrong name.
1167        self.applicant.firstname = u'John'
1168        self.browser.open(self.container_path + '/register')
1169        self.browser.getControl(name="form.firstname").value = 'Johnny'
1170        self.browser.getControl(name="form.reg_number").value = '1234'
1171        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
1172        self.browser.getControl("Send login credentials").click()
1173        # Anonymous is not informed that firstname verification failed.
1174        # It seems that the record doesn't exist.
1175        self.assertTrue('No application record found.'
1176            in self.browser.contents)
1177        # Even with the correct firstname we can't register if a
1178        # password has been set and used.
1179        IWorkflowState(self.applicant).setState('started')
1180        self.browser.getControl(name="form.firstname").value = 'John'
1181        self.browser.getControl(name="form.reg_number").value = '1234'
1182        self.browser.getControl("Send login credentials").click()
1183        self.assertTrue('Your password has already been set and used.'
1184            in self.browser.contents)
1185        #IUserAccount(
1186        #    self.app['applicants'][container_name_1][
1187        #    self.applicant.application_number]).context.password = None
1188        # Even without unsetting the password we can re-register if state
1189        # is 'initialized'
1190        IWorkflowState(self.applicant).setState('initialized')
1191        self.browser.open(self.container_path + '/register')
1192        # The firstname field, used for verification, is not case-sensitive.
1193        self.browser.getControl(name="form.firstname").value = 'jOhn'
1194        self.browser.getControl(name="form.reg_number").value = '1234'
1195        self.browser.getControl(name="form.email").value = 'new@yy.zz'
1196        self.browser.getControl("Send login credentials").click()
1197        # Yeah, we succeded ...
1198        self.assertTrue('Your registration was successful.'
1199            in self.browser.contents)
1200        # ... and  applicant can be found in the catalog via the email address
1201        cat = getUtility(ICatalog, name='applicants_catalog')
1202        results = list(
1203            cat.searchResults(
1204            email=('new@yy.zz', 'new@yy.zz')))
1205        self.assertEqual(self.applicant,results[0])
1206        return
1207
1208    def test_change_password_request(self):
1209        self.browser.open('http://localhost/app/changepw')
1210        self.browser.getControl(name="form.identifier").value = '1234'
1211        self.browser.getControl(name="form.email").value = 'aa@aa.ng'
1212        self.browser.getControl("Send login credentials").click()
1213        self.assertTrue('No record found' in self.browser.contents)
1214        self.applicant.email = 'aa@aa.ng'
1215        # Update the catalog
1216        notify(grok.ObjectModifiedEvent(self.applicant))
1217        self.browser.open('http://localhost/app/changepw')
1218        self.browser.getControl(name="form.identifier").value = '1234'
1219        self.browser.getControl(name="form.email").value = 'aa@aa.ng'
1220        self.browser.getControl("Send login credentials").click()
1221        self.assertTrue(
1222            'An email with your user name and password has been sent'
1223            in self.browser.contents)
1224
1225class ApplicantsExportTests(ApplicantsFullSetup, FunctionalAsyncTestCase):
1226    # Tests for StudentsContainer class views and pages
1227
1228    layer = FunctionalLayer
1229
1230    def wait_for_export_job_completed(self):
1231        # helper function waiting until the current export job is completed
1232        manager = getUtility(IJobManager)
1233        job_id = self.app['datacenter'].running_exports[0][0]
1234        job = manager.get(job_id)
1235        wait_for_result(job)
1236        return job_id
1237
1238    def test_applicants_in_container_export(self):
1239        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
1240        container_path = 'http://localhost/app/applicants/app2011'
1241        self.browser.open(container_path)
1242        self.browser.getLink("Export applicants").click()
1243        self.browser.getControl("Start new export").click()
1244
1245        # When the job is finished and we reload the page...
1246        job_id = self.wait_for_export_job_completed()
1247        self.browser.open(container_path + '/exports')
1248        # ... the csv file can be downloaded ...
1249        self.browser.getLink("Download").click()
1250        self.assertEqual(self.browser.headers['content-type'],
1251            'text/csv; charset=UTF-8')
1252        self.assertTrue(
1253            'filename="WAeUP.Kofa_applicants_%s.csv' % job_id in
1254            self.browser.headers['content-disposition'])
1255        self.assertEqual(len(self.app['datacenter'].running_exports), 1)
1256        job_id = self.app['datacenter'].running_exports[0][0]
1257        # ... and discarded
1258        self.browser.open(container_path + '/exports')
1259        self.browser.getControl("Discard").click()
1260        self.assertEqual(len(self.app['datacenter'].running_exports), 0)
1261        # Creation, downloading and discarding is logged
1262        logfile = os.path.join(
1263            self.app['datacenter'].storage, 'logs', 'datacenter.log')
1264        logcontent = open(logfile).read()
1265        self.assertTrue(
1266            'zope.mgr - applicants.browser.ExportJobContainerJobStart - '
1267            'exported: applicants (app2011), job_id=%s'
1268            % job_id in logcontent
1269            )
1270        self.assertTrue(
1271            'zope.mgr - applicants.browser.ExportJobContainerDownload '
1272            '- downloaded: WAeUP.Kofa_applicants_%s.csv, job_id=%s'
1273            % (job_id, job_id) in logcontent
1274            )
1275        self.assertTrue(
1276            'zope.mgr - applicants.browser.ExportJobContainerOverview '
1277            '- discarded: job_id=%s' % job_id in logcontent
1278            )
Note: See TracBrowser for help on using the repository browser.