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

Last change on this file since 14000 was 13992, checked in by Henrik Bettermann, 9 years ago

Delete mandate after report creation.

  • Property svn:keywords set to Id
File size: 79.0 KB
Line 
1## $Id: test_browser.py 13992 2016-06-26 05:35:30Z 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.securitypolicy.interfaces import IPrincipalRoleManager
32from zope.event import notify
33from zope.catalog.interfaces import ICatalog
34from zope.component import createObject, getUtility
35from zope.component.hooks import setSite, clearSite
36from zope.security.interfaces import Unauthorized
37from zope.testbrowser.testing import Browser
38from hurry.workflow.interfaces import IWorkflowInfo, IWorkflowState
39from waeup.kofa.testing import FunctionalLayer, FunctionalTestCase
40from waeup.kofa.app import University
41from waeup.kofa.payments.interfaces import IPayer
42from waeup.kofa.configuration import SessionConfiguration
43from waeup.kofa.applicants.container import ApplicantsContainer
44from waeup.kofa.applicants.applicant import Applicant
45from waeup.kofa.interfaces import (
46    IExtFileStore, IFileStoreNameChooser, IUserAccount, IJobManager)
47from waeup.kofa.university.faculty import Faculty
48from waeup.kofa.university.department import Department
49from waeup.kofa.mandates.mandate import RefereeReportMandate
50from waeup.kofa.tests.test_async import FunctionalAsyncTestCase
51
52PH_LEN = 15911  # Length of placeholder file
53
54session_1 = datetime.now().year - 2
55container_name_1 = u'app%s' % session_1
56session_2 = datetime.now().year - 1
57container_name_2 = u'app%s' % session_2
58
59SAMPLE_IMAGE = os.path.join(os.path.dirname(__file__), 'test_image.jpg')
60
61class ApplicantsFullSetup(FunctionalTestCase):
62    # A test case that only contains a setup and teardown
63    #
64    # Complete setup for applicants handlings is rather complex and
65    # requires lots of things created before we can start. This is a
66    # setup that does all this, creates a university, creates PINs,
67    # etc.  so that we do not have to bother with that in different
68    # test cases.
69
70    layer = FunctionalLayer
71
72    def setUp(self):
73        super(ApplicantsFullSetup, self).setUp()
74
75        # Setup a sample site for each test
76        app = University()
77        self.dc_root = tempfile.mkdtemp()
78        app['datacenter'].setStoragePath(self.dc_root)
79
80        # Prepopulate the ZODB...
81        self.getRootFolder()['app'] = app
82        # we add the site immediately after creation to the
83        # ZODB. Catalogs and other local utilities are not setup
84        # before that step.
85        self.app = self.getRootFolder()['app']
86        # Set site here. Some of the following setup code might need
87        # to access grok.getSite() and should get our new app then
88        setSite(app)
89
90        self.login_path = 'http://localhost/app/login'
91        self.root_path = 'http://localhost/app/applicants'
92        self.search_path = 'http://localhost/app/applicants/search'
93        self.manage_root_path = self.root_path + '/@@manage'
94        self.add_container_path = self.root_path + '/@@add'
95        self.container_path = 'http://localhost/app/applicants/%s' % container_name_1
96        self.manage_container_path = self.container_path + '/@@manage'
97
98        # Add an applicants container
99        applicantscontainer = ApplicantsContainer()
100        applicantscontainer.code = container_name_1
101        applicantscontainer.prefix = 'app'
102        applicantscontainer.year = session_1
103        applicantscontainer.title = u'This is the %s container' % container_name_1
104        applicantscontainer.application_category = 'basic'
105        applicantscontainer.mode = 'create'
106        applicantscontainer.strict_deadline = True
107        delta = timedelta(days=10)
108        applicantscontainer.startdate = datetime.now(pytz.utc) - delta
109        applicantscontainer.enddate = datetime.now(pytz.utc) + delta
110        self.app['applicants'][container_name_1] = applicantscontainer
111        self.applicantscontainer = self.app['applicants'][container_name_1]
112
113        # Populate university
114        certificate = createObject('waeup.Certificate')
115        certificate.code = 'CERT1'
116        certificate.application_category = 'basic'
117        certificate.start_level = 100
118        certificate.end_level = 500
119        certificate.study_mode = u'ug_ft'
120        self.certificate = certificate
121        self.app['faculties']['fac1'] = Faculty()
122        # The code has explicitely to be set, otherwise we don't
123        # find created students in their department
124        self.app['faculties']['fac1']['dep1'] = Department(code=u'dep1')
125        self.department = self.app['faculties']['fac1']['dep1']
126        self.app['faculties']['fac1']['dep1'].certificates.addCertificate(
127            certificate)
128
129        # Put the prepopulated site into test ZODB and prepare test
130        # browser
131        self.browser = Browser()
132        self.browser.handleErrors = False
133
134        # Create 5 access codes with prefix'FOO' and cost 9.99 each
135        pin_container = self.app['accesscodes']
136        pin_container.createBatch(
137            datetime.now(), 'some_userid', 'APP', 9.99, 5)
138        pins = pin_container[pin_container.keys()[0]].values()
139        self.pins = [x.representation for x in pins]
140        self.existing_pin = self.pins[0]
141        parts = self.existing_pin.split('-')[1:]
142        self.existing_series, self.existing_number = parts
143
144        # Add an applicant
145        self.applicant = createObject('waeup.Applicant')
146        # reg_number is the only field which has to be preset here
147        # because managers are allowed to edit this required field
148        self.applicant.firstname = u'Joan'
149        self.applicant.reg_number = u'1234'
150        self.applicant.course1 = certificate
151        app['applicants'][container_name_1].addApplicant(self.applicant)
152        IUserAccount(
153            self.app['applicants'][container_name_1][
154            self.applicant.application_number]).setPassword('apwd')
155        self.manage_path = 'http://localhost/app/applicants/%s/%s/%s' % (
156            container_name_1, self.applicant.application_number, 'manage')
157        self.edit_path = 'http://localhost/app/applicants/%s/%s/%s' % (
158            container_name_1, self.applicant.application_number, 'edit')
159        self.view_path = 'http://localhost/app/applicants/%s/%s' % (
160            container_name_1, self.applicant.application_number)
161
162    def login(self):
163        # Perform an applicant login. This creates an application record.
164        #
165        # This helper also sets `self.applicant`, which is the
166        # applicant object created.
167        self.browser.open(self.login_path)
168        self.browser.getControl(
169            name="form.login").value = self.applicant.applicant_id
170        self.browser.getControl(name="form.password").value = 'apwd'
171        self.browser.getControl("Login").click()
172
173    def fill_correct_values(self):
174        # Fill the edit form with suitable values
175        self.browser.getControl(name="form.firstname").value = 'John'
176        self.browser.getControl(name="form.middlename").value = 'Anthony'
177        self.browser.getControl(name="form.lastname").value = 'Tester'
178        self.browser.getControl(name="form.course1").value = ['CERT1']
179        self.browser.getControl(name="form.date_of_birth").value = '09/09/1988'
180        self.browser.getControl(name="form.sex").value = ['m']
181        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
182
183    def tearDown(self):
184        super(ApplicantsFullSetup, self).tearDown()
185        clearSite()
186        shutil.rmtree(self.dc_root)
187
188class ApplicantsRootUITests(ApplicantsFullSetup):
189    # Tests for ApplicantsRoot class
190
191    layer = FunctionalLayer
192
193    def test_anonymous_access(self):
194        # Anonymous users can access applicants root
195        self.browser.open(self.root_path)
196        self.assertEqual(self.browser.headers['Status'], '200 Ok')
197        self.assertFalse(
198            'Manage ' in self.browser.contents)
199        return
200
201    def test_anonymous_no_actions(self):
202        # Make sure anonymous users cannot access actions
203        self.browser.open(self.root_path)
204        self.assertRaises(
205            LookupError, self.browser.getControl, "Add local role")
206        # Manage screen neither linked nor accessible for anonymous
207        self.assertRaises(
208            LinkNotFoundError,
209            self.browser.getLink, 'Manage applicants section')
210        self.assertRaises(
211            Unauthorized, self.browser.open, self.manage_root_path)
212        # Add container screen not accessible for anonymous
213        self.assertRaises(
214            Unauthorized, self.browser.open, self.add_container_path)
215        return
216
217    def test_manage_access(self):
218        # Managers can access the manage pages of applicants root
219        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
220        self.browser.open(self.root_path)
221        self.assertTrue('Manage applicants section' in self.browser.contents)
222        # There is a manage link
223        link = self.browser.getLink('Manage applicants section')
224        link.click()
225        self.assertEqual(self.browser.headers['Status'], '200 Ok')
226        self.assertEqual(self.browser.url, self.manage_root_path)
227        return
228
229    def test_hide_container(self):
230        self.browser.open(self.root_path)
231        self.assertTrue(
232            '<a href="http://localhost/app/applicants/%s">'
233            'This is the %s container</a>' % (container_name_1, container_name_1)
234            in self.browser.contents)
235        self.app['applicants'][container_name_1].hidden = True
236        self.browser.open(self.root_path)
237        # Anonymous users can't see hidden containers
238        self.assertFalse(
239            '<a href="http://localhost/app/applicants/%s">'
240            'This is the %s container</a>' % (container_name_1, container_name_1)
241            in self.browser.contents)
242        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
243        self.browser.open(self.root_path)
244        self.assertTrue(
245            '<a href="http://localhost/app/applicants/%s">'
246            'This is the %s container</a>' % (container_name_1, container_name_1)
247            in self.browser.contents)
248        return
249
250    def test_search(self):
251        # Managers can access the manage pages of applicants root
252        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
253        self.browser.open(self.manage_path)
254        self.fill_correct_values()
255        self.browser.getControl("Save").click()
256        self.browser.open(self.root_path)
257        self.assertTrue('Manage applicants section' in self.browser.contents)
258        # There is a search link
259        link = self.browser.getLink('Find applicants')
260        link.click()
261        self.assertEqual(self.browser.headers['Status'], '200 Ok')
262        # We can find an applicant ...
263        # ... via his name
264        self.browser.getControl(name="searchtype").value = ['fullname']
265        self.browser.getControl(name="searchterm").value = 'John'
266        self.browser.getControl("Find applicant").click()
267        self.assertTrue('John Anthony Tester' in self.browser.contents)
268        self.browser.getControl(name="searchtype").value = ['fullname']
269        self.browser.getControl(name="searchterm").value = 'Tester'
270        self.browser.getControl("Find applicant").click()
271        self.assertTrue('John Anthony Tester' in self.browser.contents)
272        self.browser.open(self.search_path)
273        # ... and via his reg_number ...
274        self.browser.getControl(name="searchtype").value = ['reg_number']
275        self.browser.getControl(name="searchterm").value = '2345'
276        self.browser.getControl("Find applicant").click()
277        self.assertFalse('John Anthony Tester' in self.browser.contents)
278        self.browser.getControl(name="searchtype").value = ['reg_number']
279        self.browser.getControl(name="searchterm").value = '1234'
280        self.browser.getControl("Find applicant").click()
281        self.assertTrue('John Anthony Tester' in self.browser.contents)
282        # ... and not via his application_number ...
283        self.browser.getControl(name="searchtype").value = ['applicant_id']
284        self.browser.getControl(
285            name="searchterm").value = self.applicant.application_number
286        self.browser.getControl("Find applicant").click()
287        self.assertFalse('John Anthony Tester' in self.browser.contents)
288        # ... but ia his applicant_id ...
289        self.browser.getControl(name="searchtype").value = ['applicant_id']
290        self.browser.getControl(
291            name="searchterm").value = self.applicant.applicant_id
292        self.browser.getControl("Find applicant").click()
293        self.assertTrue('John Anthony Tester' in self.browser.contents)
294        # ... and via his email
295        self.browser.getControl(name="searchtype").value = ['email']
296        self.browser.getControl(name="searchterm").value = 'xx@yy.zz'
297        self.browser.getControl("Find applicant").click()
298        self.assertTrue('John Anthony Tester' in self.browser.contents)
299        return
300
301    def test_manage_actions_access(self):
302        # Managers can access the action on manage screen
303        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
304        self.browser.open(self.manage_root_path)
305        self.browser.getControl("Add local role").click()
306        self.assertTrue('No user selected' in self.browser.contents)
307        return
308
309    def test_local_roles_add_delete(self):
310        # Managers can assign and delete local roles of applicants root
311        myusers = self.app['users']
312        myusers.addUser('bob', 'bobssecret')
313        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
314        self.browser.open('http://localhost/app/faculties/fac1/dep1/manage')
315        self.browser.getControl(name="user").value = ['bob']
316        self.browser.getControl(name="local_role").value = [
317            'waeup.local.ApplicationsManager']
318        self.browser.getControl("Add local role").click()
319        self.assertTrue('<td>bob</td>' in self.browser.contents)
320        # Remove the role assigned
321        ctrl = self.browser.getControl(name='role_id')
322        ctrl.getControl(
323            value='bob|waeup.local.ApplicationsManager').selected = True
324        self.browser.getControl("Remove selected local roles").click()
325        self.assertTrue(
326            'Local role successfully removed: bob|waeup.local.ApplicationsManager'
327            in self.browser.contents)
328        self.assertFalse('<td>bob</td>' in self.browser.contents)
329        return
330
331    def test_add_delete_container(self):
332        # Managers can add and delete applicants containers
333        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
334        self.browser.open(self.manage_root_path)
335        self.browser.getControl("Add applicants container").click()
336        self.assertEqual(self.browser.headers['Status'], '200 Ok')
337        self.assertEqual(self.browser.url, self.add_container_path)
338        self.browser.getControl(name="form.prefix").value = ['app']
339        self.browser.getControl("Add applicants container").click()
340        self.assertTrue(
341            'There were errors' in self.browser.contents)
342        self.browser.getControl(name="form.prefix").value = ['app']
343        self.browser.getControl(name="form.year").value = [str(session_2)]
344        self.browser.getControl(name="form.mode").value = ['create']
345        self.browser.getControl(
346            name="form.application_category").value = ['basic']
347        self.browser.getControl("Add applicants container").click()
348        self.assertTrue('Added:' in self.browser.contents)
349        self.browser.getLink(container_name_1).click()
350        self.assertTrue('Manage applicants container'
351            in self.browser.contents)
352        self.browser.open(self.add_container_path)
353        self.browser.getControl("Cancel").click()
354        self.assertEqual(self.browser.url, self.manage_root_path)
355        self.browser.open(self.add_container_path)
356        self.browser.getControl(name="form.prefix").value = ['app']
357        self.browser.getControl(name="form.year").value = [str(session_2)]
358        self.browser.getControl(name="form.mode").value = ['create']
359        self.browser.getControl(
360            name="form.application_category").value = ['basic']
361        self.browser.getControl("Add applicants container").click()
362        self.assertTrue('exists already in the database'
363                        in self.browser.contents)
364        self.browser.open(self.manage_root_path)
365        ctrl = self.browser.getControl(name='val_id')
366        ctrl.getControl(value=container_name_2).selected = True
367        self.browser.getControl("Remove selected", index=0).click()
368        self.assertTrue('Successfully removed:' in self.browser.contents)
369        self.browser.open(self.add_container_path)
370        self.browser.getControl(name="form.prefix").value = ['app']
371        self.browser.getControl(name="form.year").value = [str(session_2)]
372        self.browser.getControl(name="form.mode").value = ['create']
373        #self.browser.getControl(name="form.ac_prefix").value = ['APP']
374        self.browser.getControl(
375            name="form.application_category").value = ['basic']
376        self.browser.getControl("Add applicants container").click()
377        del self.app['applicants'][container_name_2]
378        ctrl = self.browser.getControl(name='val_id')
379        ctrl.getControl(value=container_name_2).selected = True
380        self.browser.getControl("Remove selected", index=0).click()
381        self.assertMatches('...Could not delete...', self.browser.contents)
382        return
383
384class ApplicantsContainerUITests(ApplicantsFullSetup):
385    # Tests for ApplicantsContainer class views and pages
386
387    layer = FunctionalLayer
388
389    def test_anonymous_access(self):
390        # Anonymous users can access applicants containers
391        self.browser.open(self.container_path)
392        self.assertEqual(self.browser.headers['Status'], '200 Ok')
393        self.assertFalse(
394            'Manage ' in self.browser.contents)
395        return
396
397    def test_manage_access(self):
398        # Managers can access the manage pages of applicants
399        # containers and can perform actions
400        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
401        self.browser.open(self.manage_container_path)
402        self.assertEqual(self.browser.headers['Status'], '200 Ok')
403        self.assertEqual(self.browser.url, self.manage_container_path)
404        self.browser.getControl(name="form.application_fee").value = '200'
405        self.browser.getControl("Save").click()
406        self.assertTrue('Form has been saved' in self.browser.contents)
407        logfile = os.path.join(
408            self.app['datacenter'].storage, 'logs', 'applicants.log')
409        logcontent = open(logfile).read()
410        self.assertTrue(
411            'zope.mgr - applicants.browser.ApplicantsContainerManageFormPage - '
412            '%s - saved: application_fee\n' % container_name_1 in logcontent)
413        self.browser.getControl("Remove selected", index=0).click()
414        self.assertTrue('No applicant selected' in self.browser.contents)
415        self.browser.getControl("Add local role").click()
416        self.assertTrue('No user selected' in self.browser.contents)
417        self.browser.getControl("Cancel", index=0).click()
418        self.assertEqual(self.browser.url, self.container_path)
419        return
420
421    def test_statistics(self):
422        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
423        self.browser.open(self.container_path)
424        self.browser.getLink("Container statistics").click()
425        self.assertTrue('<td>initialized</td>' in self.browser.contents)
426        self.assertTrue('<td>1</td>' in self.browser.contents)
427        self.assertEqual(self.applicantscontainer.statistics[0],
428            {'not admitted': 0, 'started': 0, 'created': 0,
429            'admitted': 0, 'submitted': 0, 'initialized': 1, 'paid': 0})
430        #self.assertEqual(self.applicantscontainer.statistics[1],
431        #    {u'fac1': 0})
432        IWorkflowState(self.applicant).setState('submitted')
433        notify(grok.ObjectModifiedEvent(self.applicant))
434        self.assertEqual(self.applicantscontainer.statistics[0],
435            {'not admitted': 0, 'started': 0, 'created': 0,
436            'admitted': 0, 'submitted': 1, 'initialized': 0, 'paid': 0})
437        #self.assertEqual(self.applicantscontainer.statistics[1],
438        #    {u'fac1': 1})
439        return
440
441    def test_add_delete_applicants(self):
442        # Check the global role map first
443        role_manager = IPrincipalRoleManager(grok.getSite())
444        principals = role_manager.getPrincipalsForRole('waeup.Applicant')
445        self.assertEqual(len(principals), 1)
446        self.assertEqual(principals[0][0], self.applicant.applicant_id)
447        # Managers can add and delete applicants
448        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
449        self.add_applicant_path = self.container_path + '/addapplicant'
450        self.container_manage_path = self.container_path + '/@@manage'
451        self.browser.open(self.container_manage_path)
452        self.browser.getLink("Add applicant").click()
453        self.assertEqual(self.browser.headers['Status'], '200 Ok')
454        self.assertEqual(self.browser.url, self.add_applicant_path)
455        self.browser.getControl(name="form.firstname").value = 'Alois'
456        self.browser.getControl(name="form.middlename").value = 'Kofi'
457        self.browser.getControl(name="form.lastname").value = 'Bettermann'
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        # The global role map has been extended
462        role_manager = IPrincipalRoleManager(grok.getSite())
463        principals = role_manager.getPrincipalsForRole('waeup.Applicant')
464        self.assertEqual(len(principals), 2)
465        self.browser.open(self.container_manage_path)
466        self.assertEqual(self.browser.headers['Status'], '200 Ok')
467        ctrl = self.browser.getControl(name='val_id')
468        value = ctrl.options[0]
469        ctrl.getControl(value=value).selected = True
470        self.browser.getControl("Remove selected", index=0).click()
471        self.assertTrue('Successfully removed:' in self.browser.contents)
472        # The global role map has been reduced
473        role_manager = IPrincipalRoleManager(grok.getSite())
474        principals = role_manager.getPrincipalsForRole('waeup.Applicant')
475        self.assertEqual(len(principals), 1)
476        self.browser.open(self.add_applicant_path)
477        self.browser.getControl(name="form.firstname").value = 'Albert'
478        self.browser.getControl(name="form.lastname").value = 'Einstein'
479        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
480        self.browser.getControl("Create application record").click()
481        self.assertTrue('Application initialized' in self.browser.contents)
482        return
483
484    def test_prefill_purge_container(self):
485        # Managers can pre-fill containers in create mode
486        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
487        self.prefill_path = self.container_path + '/prefill'
488        self.container_manage_path = self.container_path + '/@@manage'
489        self.browser.open(self.container_manage_path)
490        self.browser.getLink("Pre-fill").click()
491        self.assertEqual(self.browser.headers['Status'], '200 Ok')
492        self.assertEqual(self.browser.url, self.prefill_path)
493        self.browser.getControl(name="number").value = ['10']
494        self.browser.getControl("Pre-fill").click()
495        self.assertTrue('10 application records created.' in self.browser.contents)
496        self.browser.open(self.container_manage_path)
497        self.assertTrue('This container contains 10 unused pre-filled records.'
498            in self.browser.contents)
499        self.assertEqual(self.applicantscontainer.counts[0], 11)
500        self.assertEqual(self.applicantscontainer.counts[1], 1)
501        # In update mode we can't pre-fill the container
502        self.applicantscontainer.mode = 'update'
503        self.browser.open(self.container_manage_path)
504        self.browser.getLink("Pre-fill").click()
505        self.assertTrue('Container must be in create mode to be pre-filled.'
506            in self.browser.contents)
507        self.browser.open(self.manage_root_path)
508        # Number of total records is 11
509        self.assertTrue('<td>11</td>' in self.browser.contents)
510        # The statistics have not changed
511        self.browser.open(self.container_path)
512        self.browser.getLink("Container statistics").click()
513        self.assertTrue('<td>1</td>' in self.browser.contents)
514        self.assertEqual(self.applicantscontainer.statistics[0],
515            {'not admitted': 0, 'started': 0, 'created': 0,
516            'admitted': 0, 'submitted': 0, 'initialized': 1, 'paid': 0})
517        # Container can be purged
518        IWorkflowState(self.applicant).setState('submitted')
519        self.browser.open(self.container_manage_path)
520        self.browser.getLink("Purge").click()
521        self.browser.getControl("Remove").click()
522        self.assertTrue('10 application records purged' in self.browser.contents)
523        self.assertEqual(self.applicantscontainer.counts[0], 1)
524        self.assertEqual(self.applicantscontainer.counts[1], 1)
525        IWorkflowState(self.applicant).setState('initialized')
526        self.browser.open(self.container_manage_path)
527        self.browser.getLink("Purge").click()
528        self.browser.getControl("Remove").click()
529        self.assertTrue('1 application records purged' in self.browser.contents)
530        self.assertEqual(self.applicantscontainer.counts[0], 0)
531        self.assertEqual(self.applicantscontainer.counts[1], 0)
532        return
533
534class ApplicantUITests(ApplicantsFullSetup):
535    # Tests for uploading/browsing the passport image of appplicants
536
537    layer = FunctionalLayer
538
539    def test_manage_and_view_applicant(self):
540        # Managers can manage applicants
541        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
542        self.slip_path = self.view_path + '/application_slip.pdf'
543        self.browser.open(self.manage_path)
544        self.assertEqual(self.browser.headers['Status'], '200 Ok')
545        self.fill_correct_values()
546        # Fire transition
547        self.browser.getControl(name="transition").value = ['start']
548        self.browser.getControl("Save").click()
549        # Be sure that the empty phone field does not show wrong error message
550        self.assertFalse('Required input is missing' in self.browser.contents)
551        self.assertMatches('...Form has been saved...', self.browser.contents)
552        self.assertMatches('...Application started by Manager...',
553                           self.browser.contents)
554        self.browser.open(self.view_path)
555        self.assertEqual(self.browser.headers['Status'], '200 Ok')
556        # Change course_admitted
557        self.browser.open(self.manage_path)
558        self.browser.getControl(name="form.course_admitted").value = ['CERT1']
559        self.browser.getControl("Save").click()
560        self.assertMatches('...Form has been saved...', self.browser.contents)
561        # Change password
562        self.browser.getControl(name="password").value = 'secret'
563        self.browser.getControl(name="control_password").value = 'secre'
564        self.browser.getControl("Save").click()
565        self.assertMatches('...Passwords do not match...',
566                           self.browser.contents)
567        self.browser.getControl(name="password").value = 'secret'
568        self.browser.getControl(name="control_password").value = 'secret'
569        self.browser.getControl("Save").click()
570        self.assertMatches('...Form has been saved...', self.browser.contents)
571        # Pdf slip can't be opened and download button is not available
572        self.assertFalse('Download application slip' in self.browser.contents)
573        self.browser.open(self.slip_path)
574        self.assertTrue(
575            'Please pay and submit before trying to download the application slip.'
576            in self.browser.contents)
577        # If applicant is in correct state the pdf slip can be opened.
578        IWorkflowState(self.applicant).setState('submitted')
579        self.browser.open(self.manage_path)
580        self.browser.getLink("Download application slip").click()
581        self.assertEqual(self.browser.headers['Status'], '200 Ok')
582        self.assertEqual(self.browser.headers['Content-Type'],
583                         'application/pdf')
584        # Managers can view applicants even if certificate has been removed
585        del self.app['faculties']['fac1']['dep1'].certificates['CERT1']
586        self.browser.open(self.view_path)
587        self.assertEqual(self.browser.headers['Status'], '200 Ok')
588        self.browser.open(self.slip_path)
589        self.assertEqual(self.browser.headers['Status'], '200 Ok')
590        return
591
592    def test_passport_edit_view(self):
593        # We get a default image after login
594        self.browser.open(self.login_path)
595        self.login()
596        self.browser.open(self.browser.url + '/passport.jpg')
597        self.assertEqual(self.browser.headers['status'], '200 Ok')
598        self.assertEqual(self.browser.headers['content-type'], 'image/jpeg')
599        self.assertTrue('JFIF' in self.browser.contents)
600        self.assertEqual(
601            self.browser.headers['content-length'], str(PH_LEN))
602
603    def test_applicant_login(self):
604        self.applicant.suspended = True
605        self.login()
606        self.assertTrue(
607            'You entered invalid credentials.' in self.browser.contents)
608        self.applicant.suspended = False
609        self.browser.getControl("Login").click()
610        self.assertTrue(
611            'You logged in.' in self.browser.contents)
612
613    def test_maintenance_mode(self):
614        config = grok.getSite()['configuration']
615        self.login()
616        # Applicant  logged in.
617        self.assertTrue('You logged in' in self.browser.contents)
618        self.assertTrue("Joan None" in self.browser.contents)
619        # If maintenance mode is enabled, applicant is immediately logged out.
620        config.maintmode_enabled_by = u'any_user'
621        self.assertRaises(
622            Unauthorized, self.browser.open, 'http://localhost/app/faculties')
623        self.browser.open('http://localhost/app/login')
624        self.assertTrue('The portal is in maintenance mode' in self.browser.contents)
625        # Applicant really can't login if maintenance mode is enabled.
626        self.login()
627        # A second warning is raised.
628        self.assertTrue(
629            'The portal is in maintenance mode. You can\'t login!'
630            in self.browser.contents)
631        return
632
633    def test_applicant_access(self):
634        # Applicants can edit their record
635        self.browser.open(self.login_path)
636        self.login()
637        self.assertTrue(
638            'You logged in.' in self.browser.contents)
639        self.browser.open(self.edit_path)
640        self.assertTrue(self.browser.url != self.login_path)
641        self.assertEqual(self.browser.headers['Status'], '200 Ok')
642        self.fill_correct_values()
643        self.assertTrue(IUserAccount(self.applicant).checkPassword('apwd'))
644        self.browser.getControl("Save").click()
645        self.assertMatches('...Form has been saved...', self.browser.contents)
646        # Applicants don't see manage and search links ...
647        self.browser.open(self.root_path)
648        self.assertEqual(self.browser.headers['Status'], '200 Ok')
649        self.assertFalse('Search' in self.browser.contents)
650        self.assertFalse('Manage applicants section' in self.browser.contents)
651        # ... and can't access the manage page
652        self.assertRaises(
653            Unauthorized, self.browser.open, self.manage_path)
654        return
655
656    def test_message_for_created(self):
657        IWorkflowState(self.applicant).setState('created')
658        self.applicant.student_id = u'my id'
659        self.browser.open(self.login_path)
660        self.login()
661        self.assertTrue(
662            'You logged in.' in self.browser.contents)
663        self.assertTrue(
664            '<strong>Congratulations!</strong> You have been offered provisional'
665            ' admission into the %s/%s Academic Session of'
666            ' Sample University. Your student record has been created for you.'
667            % (session_1, session_1 + 1) in self.browser.contents)
668        self.assertTrue(
669            'Then enter your new student credentials: user name= my id,'
670            ' password = %s.' % self.applicant.application_number
671            in self.browser.contents)
672        return
673
674    def image_url(self, filename):
675        return self.edit_path.replace('edit', filename)
676
677    def test_after_login_default_browsable(self):
678        # After login we see the placeholder image in the edit view
679        self.login()
680        self.assertEqual(self.browser.url, self.view_path)
681        self.browser.open(self.edit_path)
682        # There is a correct <img> link included
683        self.assertTrue(
684              '<img src="passport.jpg" height="180px" />' in self.browser.contents)
685        # Browsing the link shows a real image
686        self.browser.open(self.image_url('passport.jpg'))
687        self.assertEqual(
688            self.browser.headers['content-type'], 'image/jpeg')
689        self.assertEqual(len(self.browser.contents), PH_LEN)
690
691    def test_after_submit_default_browsable(self):
692        # After submitting an applicant form the default image is
693        # still visible
694        self.login()
695        self.browser.open(self.edit_path)
696        self.browser.getControl("Save").click() # submit form
697        # There is a correct <img> link included
698        self.assertTrue(
699            '<img src="passport.jpg" height="180px" />' in self.browser.contents)
700        # Browsing the link shows a real image
701        self.browser.open(self.image_url('passport.jpg'))
702        self.assertEqual(
703            self.browser.headers['content-type'], 'image/jpeg')
704        self.assertEqual(len(self.browser.contents), PH_LEN)
705
706    def test_uploaded_image_respects_file_size_restriction(self):
707        # When we upload an image that is too big ( > 10 KB) we will
708        # get an error message
709        self.login()
710        self.browser.open(self.edit_path)
711        # Create a pseudo image file and select it to be uploaded in form
712        photo_content = 'A' * 1024 * 51  # A string of 11 KB size
713        pseudo_image = StringIO(photo_content)
714        ctrl = self.browser.getControl(name='form.passport')
715        file_ctrl = ctrl.mech_control
716        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
717        self.browser.getControl("Save").click() # submit form
718        # There is a correct <img> link included
719        self.assertTrue(
720            '<img src="passport.jpg" height="180px" />' in self.browser.contents)
721        # We get a warning message
722        self.assertTrue(
723            'Uploaded image is too big' in self.browser.contents)
724        # Browsing the image gives us the default image, not the
725        # uploaded one.
726        self.browser.open(self.image_url('passport.jpg'))
727        self.assertEqual(
728            self.browser.headers['content-type'], 'image/jpeg')
729        self.assertEqual(len(self.browser.contents), PH_LEN)
730        # There is really no file stored for the applicant
731        img = getUtility(IExtFileStore).getFile(
732            IFileStoreNameChooser(self.applicant).chooseName())
733        self.assertTrue(img is None)
734
735    def test_uploaded_image_browsable_w_errors(self):
736        # We can upload a different image and browse it after submit,
737        # even if there are still errors in the form
738        self.login()
739        self.browser.open(self.edit_path)
740        # Create a pseudo image file and select it to be uploaded in form
741        photo_content = 'I pretend to be a graphics file'
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        # There is a correct <img> link included
748        self.assertTrue(
749            '<img src="passport.jpg" height="180px" />' in self.browser.contents)
750        # Browsing the link shows a real image
751        self.browser.open(self.image_url('passport.jpg'))
752        self.assertEqual(
753            self.browser.headers['content-type'], 'image/jpeg')
754        self.assertEqual(self.browser.contents, photo_content)
755
756    def test_uploaded_image_stored_in_imagestorage_w_errors(self):
757        # After uploading a new passport pic the file is correctly
758        # stored in an imagestorage
759        self.login()
760        self.browser.open(self.edit_path)
761        # Create a pseudo image file and select it to be uploaded in form
762        pseudo_image = StringIO('I pretend to be a graphics file')
763        ctrl = self.browser.getControl(name='form.passport')
764        file_ctrl = ctrl.mech_control
765        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
766        self.browser.getControl("Save").click() # submit form
767        storage = getUtility(IExtFileStore)
768        file_id = IFileStoreNameChooser(self.applicant).chooseName()
769        pseudo_image.seek(0) # reset our file data source
770        self.assertEqual(
771            storage.getFile(file_id).read(), pseudo_image.read())
772        return
773
774    def test_uploaded_image_browsable_wo_errors(self):
775        # We can upload a different image and browse it after submit,
776        # if there are no errors in form
777        self.login()
778        self.browser.open(self.edit_path)
779        self.fill_correct_values() # fill other fields with correct values
780        # Create a pseudo image file and select it to be uploaded in form
781        pseudo_image = StringIO('I pretend to be a graphics file')
782        ctrl = self.browser.getControl(name='form.passport')
783        file_ctrl = ctrl.mech_control
784        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
785        self.browser.getControl("Save").click() # submit form
786        # There is a correct <img> link included
787        self.assertTrue(
788            '<img src="passport.jpg" height="180px" />' in self.browser.contents)
789        # Browsing the link shows a real image
790        self.browser.open(self.image_url('passport.jpg'))
791        self.assertEqual(
792            self.browser.headers['content-type'], 'image/jpeg')
793        self.assertEqual(len(self.browser.contents), 31)
794
795    def test_uploaded_image_stored_in_imagestorage_wo_errors(self):
796        # After uploading a new passport pic the file is correctly
797        # stored in an imagestorage if form contains no errors
798        self.login()
799        self.browser.open(self.edit_path)
800        self.fill_correct_values() # fill other fields with correct values
801        # Create a pseudo image file and select it to be uploaded in form
802        pseudo_image = StringIO('I pretend to be a graphics file')
803        ctrl = self.browser.getControl(name='form.passport')
804        file_ctrl = ctrl.mech_control
805        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
806        self.browser.getControl("Save").click() # submit form
807        storage = getUtility(IExtFileStore)
808        file_id = IFileStoreNameChooser(self.applicant).chooseName()
809        # The stored image can be fetched
810        fd = storage.getFile(file_id)
811        file_len = len(fd.read())
812        self.assertEqual(file_len, 31)
813        # When an applicant is removed, also the image is gone.
814        del self.app['applicants'][container_name_1][self.applicant.application_number]
815        fd = storage.getFile(file_id)
816        self.assertTrue(fd is None)
817
818    def test_uploaded_images_equal(self):
819        # Make sure uploaded images do really differ if we eject a
820        # change notfication (and do not if we don't)
821        self.login()
822        self.browser.open(self.edit_path)
823        self.fill_correct_values() # fill other fields with correct values
824        self.browser.getControl("Save").click() # submit form
825        # Now go on as an officer
826        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
827        self.browser.open(self.manage_path)
828
829        # Create a pseudo image file and select it to be uploaded in form
830        pseudo_image = StringIO('I pretend to be a graphics file')
831        ctrl = self.browser.getControl(name='form.passport')
832        file_ctrl = ctrl.mech_control
833        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
834        file_id = IFileStoreNameChooser(self.applicant).chooseName()
835        setSite(self.app)
836        passport0 = getUtility(IExtFileStore).getFile(file_id)
837        self.browser.getControl("Save").click() # submit form with changed pic
838        passport1 = getUtility(IExtFileStore).getFile(file_id).read()
839        self.browser.getControl("Save").click() # submit form w/o changes
840        passport2 = getUtility(IExtFileStore).getFile(file_id).read()
841        self.assertTrue(passport0 is None)
842        self.assertTrue(passport0 != passport1)
843        self.assertTrue(passport1 == passport2)
844        return
845
846    def test_upload_image_by_manager_with_logging(self):
847        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
848        self.browser.open(self.manage_path)
849        # Create a pseudo image file and select it to be uploaded in form
850        photo_content = 'A' * 1024 * 5  # A string of 5 KB size
851        pseudo_image = StringIO(photo_content)
852        ctrl = self.browser.getControl(name='form.passport')
853        file_ctrl = ctrl.mech_control
854        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
855        self.browser.getControl("Save").click() # submit form
856        # Even though the form could not be saved ...
857        self.assertTrue(
858            'Required input is missing' in self.browser.contents)
859        # ... the file has been successfully uploaded
860        logfile = os.path.join(
861            self.app['datacenter'].storage, 'logs', 'applicants.log')
862        logcontent = open(logfile).read()
863        self.assertTrue(
864            'zope.mgr - applicants.browser.ApplicantManageFormPage - '
865            '%s - saved: passport'
866            % (self.applicant.applicant_id)
867            in logcontent)
868
869    def test_application_slip_with_non_jpg_image(self):
870        IWorkflowState(self.applicant).setState('submitted')
871        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
872        self.browser.open(self.manage_path)
873        # Create a pseudo image file and select it to be uploaded in form
874        photo_content = 'A' * 1024 * 5  # A string of 5 KB size
875        pseudo_image = StringIO(photo_content)
876        ctrl = self.browser.getControl(name='form.passport')
877        file_ctrl = ctrl.mech_control
878        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
879        self.browser.getControl("Save").click() # submit form
880        self.browser.open(self.manage_path)
881        self.browser.getLink("Download application slip").click()
882        self.assertEqual(self.browser.headers['Status'], '200 Ok')
883        self.assertMatches(
884            '...Your image file is corrupted. Please replace...',
885            self.browser.contents)
886
887    def test_pay_portal_application_fee(self):
888        self.login()
889        self.browser.open(self.edit_path)
890        self.fill_correct_values()
891        # We have to save the form otherwise the filled fields will be cleared
892        # after adding an online payment, because adding an online payment
893        # requires a filled form but does not save it
894        self.browser.getControl("Save").click()
895        # Payment section does not appear if application fee isn't set
896        self.assertFalse('Payment Tickets' in self.browser.contents)
897        self.assertFalse('Add online payment' in self.browser.contents)
898        self.applicantscontainer.application_fee = 200.0
899        self.browser.open(self.edit_path)
900        self.browser.getControl("Add online payment ticket").click()
901        # Session object missing
902        self.assertTrue(
903            'Session configuration object is not available'
904            in self.browser.contents)
905        configuration = SessionConfiguration()
906        configuration.academic_session = session_1
907        self.app['configuration'].addSessionConfiguration(configuration)
908        self.browser.open(self.edit_path)
909        self.browser.getControl("Add online payment ticket").click()
910        self.assertMatches('...Payment ticket created...',
911                           self.browser.contents)
912        self.assertMatches('...Activation Code...',
913                           self.browser.contents)
914        self.assertTrue(
915            '<span>200.0</span>' in self.browser.contents)
916        # Payment ticket can be removed if they haven't received a
917        # valid callback
918        self.browser.open(self.edit_path)
919        ctrl = self.browser.getControl(name='val_id')
920        value = ctrl.options[0]
921        ctrl.getControl(value=value).selected = True
922        self.browser.getControl("Remove selected", index=0).click()
923        self.assertMatches('...Successfully removed...', self.browser.contents)
924        # We will try the callback request view
925        self.browser.getControl("Add online payment ticket").click()
926        self.browser.open(self.edit_path)
927        ctrl = self.browser.getControl(name='val_id')
928        value = ctrl.options[0]
929        self.browser.getLink(value).click()
930        self.assertMatches('...Amount Authorized...',
931                           self.browser.contents)
932        payment_url = self.browser.url
933        payment_id = self.applicant.keys()[0]
934        payment = self.applicant[payment_id]
935        self.assertEqual(payment.p_item,'This is the %s container' % container_name_1)
936        self.assertEqual(payment.p_session, session_1)
937        self.assertEqual(payment.p_category,'application')
938        self.assertEqual(payment.amount_auth,200.0)
939        # Applicant is payer of the payment ticket.
940        self.assertEqual(
941            IPayer(payment).display_fullname, 'John Anthony Tester')
942        self.assertEqual(
943            IPayer(payment).id, self.applicant.applicant_id)
944        self.assertEqual(IPayer(payment).faculty, 'N/A')
945        self.assertEqual(IPayer(payment).department, 'N/A')
946        # The pdf payment slip can't yet be opened
947        #self.browser.open(payment_url + '/payment_receipt.pdf')
948        #self.assertMatches('...Ticket not yet paid...',
949        #                   self.browser.contents)
950        # Approve payment
951        # Applicants can't approve payments
952        self.assertRaises(
953            Unauthorized, self.browser.open, payment_url + '/approve')
954        # We approve the payment by bypassing the view
955        payment.approve()
956        # Applicant is is not yet in state 'paid' because it was only
957        # the payment which we set to paid
958        self.browser.open(self.view_path)
959        self.assertMatches('...started...',
960                           self.browser.contents)
961        self.assertTrue(self.applicant.state == 'started')
962        # Let's logout and approve the payment as manager
963        self.browser.getLink("Logout").click()
964        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
965        # First we reset the payment
966        payment.r_amount_approved = 0.0
967        payment.r_code = u''
968        payment.p_state = 'unpaid'
969        payment.r_desc = u''
970        payment.payment_date = None
971        self.browser.open(payment_url)
972        self.browser.getLink("Approve payment").click()
973        self.assertEqual(payment.p_state, 'paid')
974        self.assertEqual(payment.r_amount_approved, 200.0)
975        self.assertEqual(payment.r_code, 'AP')
976        self.assertTrue(self.applicant.state == 'paid')
977        # Approval is logged in students.log ...
978        logfile = os.path.join(
979            self.app['datacenter'].storage, 'logs', 'applicants.log')
980        logcontent = open(logfile).read()
981        self.assertTrue(
982            'zope.mgr - applicants.browser.OnlinePaymentApprovePage - '
983            '%s - approved' % self.applicant.applicant_id
984            in logcontent)
985        # ... and in payments.log
986        logfile = os.path.join(
987            self.app['datacenter'].storage, 'logs', 'payments.log')
988        logcontent = open(logfile).read()
989        self.assertTrue(
990            '"zope.mgr",%s,%s,application,200.0,AP,,,,,,\n'
991            % (self.applicant.applicant_id, payment.p_id)
992            in logcontent)
993        # Payment slips can't be downloaded ...
994        payment_id = self.applicant.keys()[0]
995        self.browser.open(self.view_path + '/' + payment_id)
996        self.browser.getLink("Download payment slip").click()
997        self.assertTrue(
998            'Please submit the application form before trying to download payment slips.'
999            in self.browser.contents)
1000        # ... unless form is submitted.
1001        self.browser.open(self.view_path + '/edit')
1002        image = open(SAMPLE_IMAGE, 'rb')
1003        ctrl = self.browser.getControl(name='form.passport')
1004        file_ctrl = ctrl.mech_control
1005        file_ctrl.add_file(image, filename='myphoto.jpg')
1006        self.browser.getControl(name="confirm_passport").value = True
1007        self.browser.getControl("Finally Submit").click()
1008        self.browser.open(self.view_path + '/' + payment_id)
1009        self.browser.getLink("Download payment slip").click()
1010        self.assertEqual(self.browser.headers['Content-Type'],
1011                 'application/pdf')
1012        return
1013
1014    def prepare_special_container(self):
1015        # Add special application container
1016        container_name = u'special%s' % session_1
1017        applicantscontainer = ApplicantsContainer()
1018        applicantscontainer.code = container_name
1019        applicantscontainer.prefix = 'special'
1020        applicantscontainer.year = session_1
1021        applicantscontainer.title = u'This is a special app container'
1022        applicantscontainer.application_category = 'no'
1023        applicantscontainer.mode = 'create'
1024        applicantscontainer.strict_deadline = True
1025        delta = timedelta(days=10)
1026        applicantscontainer.startdate = datetime.now(pytz.utc) - delta
1027        applicantscontainer.enddate = datetime.now(pytz.utc) + delta
1028        self.app['applicants'][container_name] = applicantscontainer
1029        # Add an applicant
1030        applicant = createObject('waeup.Applicant')
1031        # reg_number is the only field which has to be preset here
1032        # because managers are allowed to edit this required field
1033        applicant.reg_number = u'12345'
1034        self.special_applicant = applicant
1035        self.app['applicants'][container_name].addApplicant(applicant)
1036        IUserAccount(
1037            self.app['applicants'][container_name][
1038            applicant.application_number]).setPassword('apwd')
1039        # Add session configuration object
1040        self.configuration = SessionConfiguration()
1041        self.configuration.academic_session = session_1
1042        #self.configuration.transcript_fee = 200.0
1043        self.configuration.clearance_fee = 300.0
1044        self.app['configuration'].addSessionConfiguration(self.configuration)
1045
1046
1047    def test_pay_special_fee(self):
1048        self.prepare_special_container()
1049        # Login
1050        self.browser.open(self.login_path)
1051        self.browser.getControl(
1052            name="form.login").value = self.special_applicant.applicant_id
1053        self.browser.getControl(name="form.password").value = 'apwd'
1054        self.browser.getControl("Login").click()
1055        applicant_path = self.browser.url
1056        self.browser.getLink("Edit application record").click()
1057        self.browser.getControl(name="form.firstname").value = 'John'
1058        self.browser.getControl(name="form.middlename").value = 'Anthony'
1059        self.browser.getControl(name="form.lastname").value = 'Tester'
1060        self.browser.getControl(name="form.special_application").value = [
1061            'transcript']
1062        self.browser.getControl(name="form.date_of_birth").value = '09/09/1988'
1063        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
1064        self.configuration.transcript_fee = 0.0
1065        self.browser.getControl("Save").click()
1066        self.browser.getControl("Add online payment ticket").click()
1067        self.assertMatches('...Amount could not be determined...',
1068                           self.browser.contents)
1069        self.configuration.transcript_fee = 200.0
1070        self.browser.getLink("Edit application record").click()
1071        self.browser.getControl("Add online payment ticket").click()
1072        self.assertMatches('...Payment ticket created...',
1073                           self.browser.contents)
1074        self.assertTrue(
1075            '<span>Transcript Fee</span>' in self.browser.contents)
1076        self.assertTrue(
1077            'This is a special app container' in self.browser.contents)
1078        self.assertTrue(
1079            '<span>200.0</span>' in self.browser.contents)
1080        self.assertEqual(len(self.special_applicant.keys()), 1)
1081        # The applicant's workflow state is paid ...
1082        self.special_applicant.payments[0].approveApplicantPayment()
1083        self.assertEqual(self.special_applicant.state, 'paid')
1084        self.browser.open(applicant_path + '/edit')
1085        # ... but he can create further tickets.
1086        self.browser.getControl(name="form.special_application").value = [
1087            'clearance']
1088        self.browser.getControl("Save").click()
1089        self.browser.getControl("Add online payment ticket").click()
1090        self.assertMatches('...Payment ticket created...',
1091                           self.browser.contents)
1092        self.browser.open(applicant_path)
1093        self.assertTrue(
1094            '<td>Acceptance Fee</td>' in self.browser.contents)
1095        self.assertEqual(len(self.special_applicant.keys()), 2)
1096        # Second payment can also be approved wthout error message
1097        flashtype, msg, log = self.special_applicant.payments[1].approveApplicantPayment()
1098        self.assertEqual(flashtype, 'success')
1099        self.assertEqual(msg, 'Payment approved')
1100        # Payment slips can't be downloaded ...
1101        payment_id = self.special_applicant.keys()[0]
1102        self.browser.open(applicant_path + '/' + payment_id)
1103        self.browser.getLink("Download payment slip").click()
1104        self.assertTrue(
1105            'Please submit the application form before trying to download payment slips.'
1106            in self.browser.contents)
1107        # ... unless form is submitted.
1108        self.browser.open(applicant_path + '/edit')
1109        image = open(SAMPLE_IMAGE, 'rb')
1110        ctrl = self.browser.getControl(name='form.passport')
1111        file_ctrl = ctrl.mech_control
1112        file_ctrl.add_file(image, filename='myphoto.jpg')
1113        self.browser.getControl(name="confirm_passport").value = True
1114        self.browser.getControl("Finally Submit").click()
1115        self.browser.open(applicant_path + '/' + payment_id)
1116        self.browser.getLink("Download payment slip").click()
1117        self.assertEqual(self.browser.headers['Content-Type'],
1118                 'application/pdf')
1119        return
1120
1121    def test_final_submit(self):
1122        # Make sure that a correctly filled form with passport picture
1123        # can be submitted (only) after payment
1124        self.login()
1125        self.browser.getLink("Edit application record").click()
1126        self.assertFalse('Finally Submit' in self.browser.contents)
1127        IWorkflowInfo(self.applicant).fireTransition('pay')
1128        self.browser.open(self.edit_path)
1129        self.assertTrue('Finally Submit' in self.browser.contents)
1130        self.fill_correct_values() # fill other fields with correct values
1131        self.browser.getControl("Save").click()
1132        self.browser.getControl("Finally Submit").click()
1133        # We forgot to upload a passport picture
1134        self.assertTrue(
1135            'No passport picture uploaded' in self.browser.contents)
1136        # Use a real image file and select it to be uploaded in form
1137        image = open(SAMPLE_IMAGE, 'rb')
1138        ctrl = self.browser.getControl(name='form.passport')
1139        file_ctrl = ctrl.mech_control
1140        file_ctrl.add_file(image, filename='myphoto.jpg')
1141        self.browser.getControl("Finally Submit").click() # (finally) submit form
1142        # The picture has been uploaded but the form cannot be submitted
1143        # since the passport confirmation box was not ticked
1144        self.assertTrue(
1145            'Passport picture confirmation box not ticked'
1146            in self.browser.contents)
1147        self.browser.getControl(name="confirm_passport").value = True
1148        # If application period has expired and strict-deadline is set
1149        # applicants do notsee edit button and can't open
1150        # the edit form.
1151        self.applicantscontainer.enddate = datetime.now(pytz.utc)
1152        self.browser.open(self.view_path)
1153        self.assertFalse(
1154            'Edit application record' in self.browser.contents)
1155        self.browser.open(self.edit_path)
1156        self.assertTrue(
1157            'form is locked' in self.browser.contents)
1158        # We can either postpone the enddate ...
1159        self.applicantscontainer.enddate = datetime.now(
1160            pytz.utc) + timedelta(days=10)
1161        self.browser.open(self.edit_path)
1162        self.browser.getControl(name="confirm_passport").value = True
1163        self.browser.getControl("Finally Submit").click()
1164        self.assertTrue(
1165            'Application submitted' in self.browser.contents)
1166        # ... or allow submission after deadline.
1167        IWorkflowState(self.applicant).setState('paid')
1168        self.applicant.locked = False
1169        self.applicantscontainer.strict_deadline = False
1170        self.browser.open(self.edit_path)
1171        self.browser.getControl(name="confirm_passport").value = True
1172        self.browser.getControl("Finally Submit").click()
1173        self.assertTrue(
1174            'Application submitted' in self.browser.contents)
1175        return
1176
1177    def test_locking(self):
1178        # Make sure that locked forms can't be submitted
1179        self.login()
1180        self.browser.open(self.edit_path)
1181        self.fill_correct_values() # fill other fields with correct values
1182        # Create a pseudo image file and select it to be uploaded in form
1183        pseudo_image = StringIO('I pretend to be a graphics file')
1184        ctrl = self.browser.getControl(name='form.passport')
1185        file_ctrl = ctrl.mech_control
1186        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
1187        self.browser.getControl("Save").click()
1188        # Now we lock the form
1189        self.applicant.locked = True
1190        self.browser.open(self.edit_path)
1191        self.assertEqual(self.browser.headers['Status'], '200 Ok')
1192        self.assertTrue(
1193            'The requested form is locked' in self.browser.contents)
1194        return
1195
1196    def test_certificate_removed(self):
1197        self.login()
1198        self.browser.open(self.edit_path)
1199        self.fill_correct_values()
1200        self.browser.getControl("Save").click()
1201        self.browser.open(self.view_path)
1202        self.assertTrue(
1203            'Unnamed Certificate' in self.browser.contents)
1204        self.browser.open(self.edit_path)
1205        self.assertTrue(
1206            '<option selected="selected" value="CERT1">' in self.browser.contents)
1207        # Now we remove the certificate
1208        del self.app['faculties']['fac1']['dep1'].certificates['CERT1']
1209        # The certificate is still shown in display mode
1210        self.browser.open(self.view_path)
1211        self.assertTrue(
1212            'Unnamed Certificate' in self.browser.contents)
1213        # The certificate is still selectable in edit mode so that it won't
1214        # be automatically replaced by another (arbitrary) certificate
1215        self.browser.open(self.edit_path)
1216        self.assertTrue(
1217            '<option selected="selected" value="CERT1">' in self.browser.contents)
1218        # Consequently, the certificate is still shown after saving the form
1219        self.browser.getControl("Save").click()
1220        self.browser.open(self.view_path)
1221        self.assertTrue(
1222            'Unnamed Certificate' in self.browser.contents)
1223        # Even if we add a new certificate the previous (removed)
1224        # certificate is shown
1225        certificate = createObject('waeup.Certificate')
1226        certificate.code = 'CERT2'
1227        certificate.title = 'New Certificate'
1228        certificate.application_category = 'basic'
1229        self.app['faculties']['fac1']['dep1'].certificates.addCertificate(
1230            certificate)
1231        self.browser.open(self.edit_path)
1232        self.assertTrue(
1233            '<option selected="selected" value="CERT1">'
1234            in self.browser.contents)
1235
1236class ApplicantRegisterTests(ApplicantsFullSetup):
1237    # Tests for applicant registration
1238
1239    layer = FunctionalLayer
1240
1241    def test_register_applicant_create(self):
1242        config = grok.getSite()['configuration']
1243        config.maintmode_enabled_by = u'any_user'
1244        self.assertEqual(len(self.app['applicants'][container_name_1]), 1)
1245        # An applicant can register himself.
1246        self.browser.open(self.container_path)
1247        self.browser.getLink("Register for application").click()
1248        self.assertTrue(
1249            'The portal is in maintenance mode' in self.browser.contents)
1250        config.maintmode_enabled_by = None
1251        self.browser.getLink("Register for application").click()
1252        # The edit form now opens and can be filled with suitable values
1253        self.browser.getControl(name="form.firstname").value = 'Anna'
1254        self.browser.getControl(name="form.lastname").value = 'Kurios'
1255        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
1256        self.browser.getControl(name="form.phone.country").value = ['+234']
1257        self.browser.getControl(name="form.phone.area").value = '555'
1258        self.browser.getControl(name="form.phone.ext").value = '6666666'
1259        self.browser.getControl("Send login credentials").click()
1260        self.assertEqual(self.browser.url,
1261            self.container_path + '/registration_complete?email=xx%40yy.zz')
1262        # A new applicant has been created
1263        self.assertEqual(len(self.app['applicants'][container_name_1]), 2)
1264        # The new applicant can be found in the catalog via the email address
1265        cat = getUtility(ICatalog, name='applicants_catalog')
1266        results = list(
1267            cat.searchResults(email=('xx@yy.zz', 'xx@yy.zz')))
1268        applicant = results[0]
1269        self.assertEqual(applicant.lastname,'Kurios')
1270        # The application_id has been copied to the reg_number
1271        self.assertEqual(applicant.applicant_id, applicant.reg_number)
1272        # The applicant can be found in the catalog via the reg_number
1273        results = list(
1274            cat.searchResults(
1275            reg_number=(applicant.reg_number, applicant.reg_number)))
1276        self.assertEqual(applicant,results[0])
1277        return
1278
1279    def test_register_applicant_take_unused_record(self):
1280        # Create an unused record
1281        uu_applicant = createObject('waeup.Applicant')
1282        self.app['applicants'][container_name_1].addApplicant(uu_applicant)
1283        self.assertEqual(uu_applicant.container_code, container_name_1 + '-')
1284        self.assertEqual(len(self.app['applicants'][container_name_1]), 2)
1285        self.browser.open(self.container_path)
1286        self.browser.getLink("Register for application").click()
1287        # Fill the edit form with suitable values
1288        self.browser.getControl(name="form.firstname").value = 'Anna'
1289        self.browser.getControl(name="form.lastname").value = 'Kurios'
1290        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
1291        self.browser.getControl(name="form.phone.country").value = ['+234']
1292        self.browser.getControl(name="form.phone.area").value = '555'
1293        self.browser.getControl(name="form.phone.ext").value = '6666666'
1294        self.browser.getControl("Send login credentials").click()
1295        # No applicant has been created ...
1296        self.assertEqual(len(self.app['applicants'][container_name_1]), 2)
1297        # ... and the existing, formerly unused record has been used instead
1298        self.assertEqual(uu_applicant.lastname, 'Kurios')
1299        self.assertEqual(uu_applicant.container_code, container_name_1 + '+')
1300        return
1301
1302    def test_register_applicant_update(self):
1303        # We change the application mode and check if applicants
1304        # can find and update imported records instead of creating new records.
1305        # First we check what happens if record does not exist.
1306        self.applicantscontainer.mode = 'update'
1307        self.browser.open(self.container_path + '/register')
1308        self.browser.getControl(name="form.lastname").value = 'Better'
1309        self.browser.getControl(name="form.reg_number").value = 'anynumber'
1310        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
1311        self.browser.getControl("Send login credentials").click()
1312        self.assertTrue('No application record found.'
1313            in self.browser.contents)
1314        # Even with the correct reg_number we can't register
1315        # because lastname attribute is not set.
1316        self.applicantscontainer.mode = 'update'
1317        self.browser.open(self.container_path + '/register')
1318        self.browser.getControl(name="form.lastname").value = 'Better'
1319        self.browser.getControl(name="form.reg_number").value = '1234'
1320        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
1321        self.browser.getControl("Send login credentials").click()
1322        self.assertTrue('An error occurred.' in self.browser.contents)
1323        # Let's set this attribute manually
1324        # and try to register with a wrong name.
1325        self.applicant.lastname = u'Better'
1326        self.browser.open(self.container_path + '/register')
1327        self.browser.getControl(name="form.lastname").value = 'Worse'
1328        self.browser.getControl(name="form.reg_number").value = '1234'
1329        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
1330        self.browser.getControl("Send login credentials").click()
1331        # Anonymous is not informed that lastname verification failed.
1332        # It seems that the record doesn't exist.
1333        self.assertTrue('No application record found.'
1334            in self.browser.contents)
1335        # Even with the correct lastname we can't register if a
1336        # password has been set and used.
1337        IWorkflowState(self.applicant).setState('started')
1338        self.browser.getControl(name="form.lastname").value = 'Better'
1339        self.browser.getControl(name="form.reg_number").value = '1234'
1340        self.browser.getControl("Send login credentials").click()
1341        self.assertTrue('Your password has already been set and used.'
1342            in self.browser.contents)
1343        #IUserAccount(
1344        #    self.app['applicants'][container_name_1][
1345        #    self.applicant.application_number]).context.password = None
1346        # Even without unsetting the password we can re-register if state
1347        # is 'initialized'
1348        IWorkflowState(self.applicant).setState('initialized')
1349        self.browser.open(self.container_path + '/register')
1350        # The lastname field, used for verification, is not case-sensitive.
1351        self.browser.getControl(name="form.lastname").value = 'bEtter'
1352        self.browser.getControl(name="form.reg_number").value = '1234'
1353        self.browser.getControl(name="form.email").value = 'new@yy.zz'
1354        self.browser.getControl("Send login credentials").click()
1355        # Yeah, we succeded ...
1356        self.assertTrue('Your registration was successful.'
1357            in self.browser.contents)
1358        # ... and  applicant can be found in the catalog via the email address
1359        cat = getUtility(ICatalog, name='applicants_catalog')
1360        results = list(
1361            cat.searchResults(
1362            email=('new@yy.zz', 'new@yy.zz')))
1363        self.assertEqual(self.applicant,results[0])
1364        return
1365
1366    def test_change_password_request(self):
1367        self.browser.open('http://localhost/app/changepw')
1368        self.browser.getControl(name="form.identifier").value = '1234'
1369        self.browser.getControl(name="form.email").value = 'aa@aa.ng'
1370        self.browser.getControl("Send login credentials").click()
1371        self.assertTrue('No record found' in self.browser.contents)
1372        self.applicant.email = 'aa@aa.ng'
1373        # Update the catalog
1374        notify(grok.ObjectModifiedEvent(self.applicant))
1375        self.browser.open('http://localhost/app/changepw')
1376        self.browser.getControl(name="form.identifier").value = '1234'
1377        self.browser.getControl(name="form.email").value = 'aa@aa.ng'
1378        self.browser.getControl("Send login credentials").click()
1379        self.assertTrue(
1380            'An email with your user name and password has been sent'
1381            in self.browser.contents)
1382
1383    def test_check_status(self):
1384        self.applicant.lastname = u'Lion '
1385        self.browser.open('http://localhost/app/applicants/checkstatus')
1386        self.browser.getControl(name="unique_id").value = 'nonsense'
1387        self.browser.getControl(name="lastname").value = 'Lion'
1388        self.browser.getControl("Submit").click()
1389        self.assertTrue('No application record found' in self.browser.contents)
1390        self.browser.getControl(
1391          name="unique_id").value = self.applicant.applicant_id
1392        self.browser.getControl(name="lastname").value = 'nonsense'
1393        self.browser.getControl("Submit").click()
1394        self.assertTrue('No application record found' in self.browser.contents)
1395        self.browser.getControl(
1396          name="unique_id").value = self.applicant.applicant_id
1397        self.browser.getControl(name="lastname").value = 'Lion'
1398        self.browser.getControl("Submit").click()
1399        self.assertTrue('Admission status of' in self.browser.contents)
1400        self.assertTrue(
1401          'You have not yet submitted your application' in self.browser.contents)
1402        IWorkflowState(self.applicant).setState('admitted')
1403        self.browser.open('http://localhost/app/applicants/checkstatus')
1404        self.browser.getControl(
1405          name="unique_id").value = self.applicant.applicant_id
1406        # Whitespaces are ignored.
1407        self.browser.getControl(name="lastname").value = 'Lion'
1408        self.browser.getControl("Submit").click()
1409        self.assertTrue('Congratulations!' in self.browser.contents)
1410        self.assertFalse('Study Course' in self.browser.contents)
1411        self.applicant.course_admitted = self.certificate
1412        self.browser.open('http://localhost/app/applicants/checkstatus')
1413        self.browser.getControl(
1414          name="unique_id").value = self.applicant.applicant_id
1415        self.browser.getControl(name="lastname").value = 'Lion'
1416        self.browser.getControl("Submit").click()
1417        self.assertTrue('Congratulations!' in self.browser.contents)
1418        self.assertTrue('Unnamed Certificate (CERT1)' in self.browser.contents)
1419        self.assertTrue(
1420          'Department of Unnamed Department (dep1)' in self.browser.contents)
1421        self.assertTrue(
1422          'Faculty of Unnamed Faculty (NA)' in self.browser.contents)
1423        # Also the reg_number can be used and page shows student id and password
1424        # if applicant is in state created.
1425        IWorkflowState(self.applicant).setState('created')
1426        self.applicant.student_id = u'my id'
1427        self.browser.open('http://localhost/app/applicants/checkstatus')
1428        self.browser.getControl(
1429          name="unique_id").value = self.applicant.reg_number
1430        self.browser.getControl(name="lastname").value = 'Lion'
1431        self.browser.getControl("Submit").click()
1432        self.assertTrue('Congratulations!' in self.browser.contents)
1433        self.assertTrue('Unnamed Certificate (CERT1)' in self.browser.contents)
1434        self.assertTrue('Department of Unnamed Department (dep1)'
1435            in self.browser.contents)
1436        self.assertTrue(
1437          'Faculty of Unnamed Faculty (NA)' in self.browser.contents)
1438        self.assertTrue('user name (= student id) is: <strong>my id</strong>'
1439            in self.browser.contents)
1440        self.assertTrue(
1441          'password is: <strong>%s</strong>' % self.applicant.application_number
1442          in self.browser.contents)
1443       
1444
1445class ApplicantsExportTests(ApplicantsFullSetup, FunctionalAsyncTestCase):
1446    # Tests for StudentsContainer class views and pages
1447
1448    layer = FunctionalLayer
1449
1450    def wait_for_export_jobs_completed(self):
1451        # helper function waiting until the current export job is completed
1452        manager = getUtility(IJobManager)
1453        job_ids = [i[0] for i in self.app['datacenter'].running_exports]
1454        jobs = [manager.get(job_id) for job_id in job_ids]
1455        for job in jobs:
1456            wait_for_result(job)
1457        return job_ids
1458
1459    def test_applicants_in_container_export(self):
1460        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
1461        container_path = 'http://localhost/app/applicants/%s' % container_name_1
1462        self.browser.open(container_path)
1463        self.browser.getLink("Export application data").click()
1464        self.browser.getControl("Start new exports").click()
1465        job_ids = self.wait_for_export_jobs_completed()
1466        # Two exports were created
1467        self.assertEqual(len(self.app['datacenter'].running_exports), 2)
1468       # When the jobs are finished and we reload the page...
1469        self.browser.open(container_path + '/exports')
1470        # ... the both csv files can be downloaded ...
1471        self.browser.getLink("Download", index=0).click()
1472        self.assertEqual(self.browser.headers['content-type'],
1473            'text/csv; charset=UTF-8')
1474        self.assertTrue(
1475            'filename="WAeUP.Kofa_applicants_%s.csv' % job_ids[0] in
1476            self.browser.headers['content-disposition'])
1477        self.browser.open(container_path + '/exports')
1478        self.browser.getLink("Download", index=1).click()
1479        self.assertEqual(self.browser.headers['content-type'],
1480            'text/csv; charset=UTF-8')
1481        self.assertTrue(
1482            'filename="WAeUP.Kofa_applicantpayments_%s.csv' % job_ids[1] in
1483            self.browser.headers['content-disposition'])
1484        # ... and discarded
1485        self.browser.open(container_path + '/exports')
1486        self.browser.getControl("Discard", index=0).click()
1487        self.assertEqual(len(self.app['datacenter'].running_exports), 1)
1488        self.browser.getControl("Discard").click()
1489        self.assertEqual(len(self.app['datacenter'].running_exports), 0)
1490        # Creation, downloading and discarding are logged
1491        logfile = os.path.join(
1492            self.app['datacenter'].storage, 'logs', 'datacenter.log')
1493        logcontent = open(logfile).read()
1494        self.assertTrue(
1495            'zope.mgr - applicants.browser.ExportJobContainerJobStart - '
1496            'exported: applicants (%s), job_id=%s'
1497            % (container_name_1, job_ids[0]) in logcontent
1498            )
1499        self.assertTrue(
1500            'zope.mgr - applicants.browser.ExportJobContainerDownload '
1501            '- downloaded: WAeUP.Kofa_applicants_%s.csv, job_id=%s'
1502            % (job_ids[0], job_ids[0]) in logcontent
1503            )
1504        self.assertTrue(
1505            'zope.mgr - applicants.browser.ExportJobContainerOverview '
1506            '- discarded: job_id=%s' % job_ids[0] in logcontent
1507            )
1508        self.assertTrue(
1509            'zope.mgr - applicants.browser.ExportJobContainerJobStart - '
1510            'exported: applicantpayments (%s), job_id=%s'
1511            % (container_name_1, job_ids[1]) in logcontent
1512            )
1513        self.assertTrue(
1514            'zope.mgr - applicants.browser.ExportJobContainerDownload '
1515            '- downloaded: WAeUP.Kofa_applicantpayments_%s.csv, job_id=%s'
1516            % (job_ids[1], job_ids[1]) in logcontent
1517            )
1518        self.assertTrue(
1519            'zope.mgr - applicants.browser.ExportJobContainerOverview '
1520            '- discarded: job_id=%s' % job_ids[1] in logcontent
1521            )
1522
1523class ApplicantRefereeReportTests(ApplicantsFullSetup, FunctionalAsyncTestCase):
1524    # Tests for ApplicantRefereeReport class views and pages
1525
1526    layer = FunctionalLayer
1527
1528    def test_refereereport_mandate(self):
1529        mandate = RefereeReportMandate()
1530        mandate.params['name'] = u'John Referee'
1531        mandate.params['email'] = 'aa@aa.aa'
1532        mandate.params[
1533            'redirect_path'] = '/applicants/%s/%s/addrefereereport' % (
1534                container_name_1, self.applicant.application_number)
1535        self.app['mandates'].addMandate(mandate)
1536        # Let's open the add form page via the mandate view
1537        self.browser.open('http://localhost/app/mandate?mandate_id=%s'
1538            % mandate.mandate_id)
1539        # Form page opens and is prefilled
1540        self.assertEqual(
1541            self.browser.url,
1542            'http://localhost/app/applicants/%s/%s/addrefereereport?mandate_id=%s'
1543            % (container_name_1, self.applicant.application_number,
1544            mandate.mandate_id))
1545        self.assertTrue('value="John Referee"' in self.browser.contents)
1546        # Let's open the page directly with an invalid mandate
1547        self.browser.open(
1548            'http://localhost/app/applicants/%s/%s/addrefereereport?mandate_id=wrongmadate'
1549            % (container_name_1, self.applicant.application_number))
1550        self.assertTrue('<div class="alert alert-warning">No mandate.</div>'
1551            in self.browser.contents)
1552        self.assertEqual(self.browser.url, 'http://localhost/app')
1553        # Page is also blocked in maintenance mode
1554        grok.getSite()['configuration'].maintmode_enabled_by = u'anybody'
1555        self.browser.open(
1556            'http://localhost/app/applicants/%s/%s/addrefereereport?mandate_id=%s'
1557            % (container_name_1, self.applicant.application_number,
1558            mandate.mandate_id))
1559        self.assertTrue('<div class="alert alert-warning">The portal is '
1560                        'in maintenance mode'
1561            in self.browser.contents)
1562        self.assertEqual(self.browser.url, 'http://localhost/app')
1563
1564    def test_add_and_view_reports(self):
1565        mandate = RefereeReportMandate()
1566        mandate.params['name'] = u'John Referee'
1567        mandate.params['email'] = 'aa@aa.aa'
1568        mandate.params[
1569            'redirect_path'] = '/applicants/%s/%s/addrefereereport' % (
1570                container_name_1, self.applicant.application_number)
1571        self.app['mandates'].addMandate(mandate)
1572        self.assertEqual(len(self.app['mandates'].keys()), 1)
1573        # Let's open the add form page via the mandate view
1574        self.browser.open('http://localhost/app/mandate?mandate_id=%s'
1575            % mandate.mandate_id)
1576        self.assertTrue('Joan None' in self.browser.contents)
1577        # Report can't be saved without required fields
1578        self.browser.getControl(name="form.email").value = ''
1579        self.browser.getControl("Submit").click()
1580        self.assertTrue('Required input is missing' in self.browser.contents)
1581        self.browser.getControl(name="form.email").value = 'bb@bb.bb'
1582        self.browser.getControl("Submit").click()
1583        self.assertTrue('Referee report has been saved' in self.browser.contents)
1584        self.assertEqual(self.browser.url, 'http://localhost/app')
1585        # Report has been created
1586        self.assertEqual(len(self.applicant.refereereports), 1)
1587        report = self.applicant.refereereports[0]
1588        # Managers can view the report
1589        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
1590        self.browser.open(self.manage_path)
1591        self.browser.getLink("%s" % report.r_id).click()
1592        self.assertEqual(
1593            self.browser.url, self.view_path  + '/%s' % report.r_id)
1594        self.assertTrue('John Referee' in self.browser.contents)
1595        # Report creation is logged
1596        logfile = os.path.join(
1597            self.app['datacenter'].storage, 'logs', 'applicants.log')
1598        logcontent = open(logfile).read()
1599        self.assertTrue(
1600            'zope.anybody - applicants.browser.RefereeReportAddFormPage - '
1601            '%s - added: %s\n' % (self.applicant.applicant_id, report.r_id)
1602            in logcontent
1603            )
1604        # Mandate is deleted
1605        self.assertEqual(len(self.app['mandates'].keys()), 0)
Note: See TracBrowser for help on using the repository browser.