## $Id: test_browser.py 8268 2012-04-25 06:02:54Z henrik $
## 
## Copyright (C) 2011 Uli Fouquet & Henrik Bettermann
## This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 2 of the License, or
## (at your option) any later version.
## 
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU General Public License for more details.
## 
## You should have received a copy of the GNU General Public License
## along with this program; if not, write to the Free Software
## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
##
"""
Test the student-related UI components.
"""
import shutil
import tempfile
from StringIO import StringIO
from datetime import datetime
import os
import grok
from zope.event import notify
from zope.component import createObject, queryUtility, getUtility
from zope.component.hooks import setSite, clearSite
from zope.catalog.interfaces import ICatalog
from zope.security.interfaces import Unauthorized
from zope.securitypolicy.interfaces import IPrincipalRoleManager
from zope.testbrowser.testing import Browser
from hurry.workflow.interfaces import IWorkflowInfo, IWorkflowState
from waeup.kofa.testing import FunctionalLayer, FunctionalTestCase
from waeup.kofa.app import University
from waeup.kofa.configuration import SessionConfiguration
from waeup.kofa.students.student import Student
from waeup.kofa.students.studylevel import StudentStudyLevel
from waeup.kofa.university.faculty import Faculty
from waeup.kofa.university.department import Department
from waeup.kofa.interfaces import IUserAccount, IKofaUtils
from waeup.kofa.authentication import LocalRoleSetEvent
from waeup.kofa.hostels.hostel import Hostel, Bed, NOT_OCCUPIED

PH_LEN = 2059  # Length of placeholder file

def lookup_submit_value(name, value, browser):
    """Find a button with a certain value."""
    for num in range(0, 100):
        try:
            button = browser.getControl(name=name, index=num)
            if button.value.endswith(value):
                return button
        except IndexError:
            break
    return None

class StudentsFullSetup(FunctionalTestCase):
    # A test case that only contains a setup and teardown
    #
    # Complete setup for students handlings is rather complex and
    # requires lots of things created before we can start. This is a
    # setup that does all this, creates a university, creates PINs,
    # etc.  so that we do not have to bother with that in different
    # test cases.

    layer = FunctionalLayer

    def setUp(self):
        super(StudentsFullSetup, self).setUp()

        # Setup a sample site for each test
        app = University()
        self.dc_root = tempfile.mkdtemp()
        app['datacenter'].setStoragePath(self.dc_root)

        # Prepopulate the ZODB...
        self.getRootFolder()['app'] = app
        # we add the site immediately after creation to the
        # ZODB. Catalogs and other local utilities are not setup
        # before that step.
        self.app = self.getRootFolder()['app']
        # Set site here. Some of the following setup code might need
        # to access grok.getSite() and should get our new app then
        setSite(app)

        # Add student with subobjects
        student = createObject('waeup.Student')
        student.firstname = u'Anna'
        student.lastname = u'Tester'
        student.reg_number = u'123'
        student.matric_number = u'234'
        student.sex = u'm'
        student.email = 'aa@aa.ng'
        student.phone = u'1234'
        self.app['students'].addStudent(student)
        self.student_id = student.student_id
        self.student = self.app['students'][self.student_id]

        # Set password
        IUserAccount(
            self.app['students'][self.student_id]).setPassword('spwd')

        self.login_path = 'http://localhost/app/login'
        self.container_path = 'http://localhost/app/students'
        self.manage_container_path = self.container_path + '/@@manage'
        self.add_student_path = self.container_path + '/addstudent'
        self.student_path = self.container_path + '/' + self.student_id
        self.manage_student_path = self.student_path + '/manage_base'
        self.clearance_path = self.student_path + '/view_clearance'
        self.personal_path = self.student_path + '/view_personal'
        self.edit_clearance_path = self.student_path + '/cedit'
        self.manage_clearance_path = self.student_path + '/manage_clearance'
        self.edit_personal_path = self.student_path + '/edit_personal'
        self.studycourse_path = self.student_path + '/studycourse'
        self.payments_path = self.student_path + '/payments'
        self.acco_path = self.student_path + '/accommodation'
        self.history_path = self.student_path + '/history'

        # Create 5 access codes with prefix'PWD'
        pin_container = self.app['accesscodes']
        pin_container.createBatch(
            datetime.utcnow(), 'some_userid', 'PWD', 9.99, 5)
        pins = pin_container['PWD-1'].values()
        self.pwdpins = [x.representation for x in pins]
        self.existing_pwdpin = self.pwdpins[0]
        parts = self.existing_pwdpin.split('-')[1:]
        self.existing_pwdseries, self.existing_pwdnumber = parts
        # Create 5 access codes with prefix 'CLR'
        pin_container.createBatch(
            datetime.now(), 'some_userid', 'CLR', 9.99, 5)
        pins = pin_container['CLR-1'].values()
        pins[0].owner = u'Hans Wurst'
        self.existing_clrac = pins[0]
        self.existing_clrpin = pins[0].representation
        parts = self.existing_clrpin.split('-')[1:]
        self.existing_clrseries, self.existing_clrnumber = parts
        # Create 2 access codes with prefix 'HOS'
        pin_container.createBatch(
            datetime.now(), 'some_userid', 'HOS', 9.99, 2)
        pins = pin_container['HOS-1'].values()
        self.existing_hosac = pins[0]
        self.existing_hospin = pins[0].representation
        parts = self.existing_hospin.split('-')[1:]
        self.existing_hosseries, self.existing_hosnumber = parts

        # Populate university
        self.certificate = createObject('waeup.Certificate')
        self.certificate.code = u'CERT1'
        self.certificate.application_category = 'basic'
        self.certificate.study_mode = 'ug_ft'
        self.certificate.start_level = 100
        self.certificate.end_level = 500
        self.app['faculties']['fac1'] = Faculty()
        self.app['faculties']['fac1']['dep1'] = Department(code='dep1')
        self.app['faculties']['fac1']['dep1'].certificates.addCertificate(
            self.certificate)
        self.course = createObject('waeup.Course')
        self.course.code = 'COURSE1'
        self.course.semester = 1
        self.course.credits = 10
        self.course.passmark = 40
        self.app['faculties']['fac1']['dep1'].courses.addCourse(
            self.course)
        self.app['faculties']['fac1']['dep1'].certificates['CERT1'].addCourseRef(
            self.course, level=100)

        # Configure university
        self.app['configuration'].accommodation_states = ['admitted']
        self.app['configuration'].accommodation_session = 2004
        self.app['configuration'].carry_over = True
        configuration = createObject('waeup.SessionConfiguration')
        configuration.academic_session = 2004
        self.app['configuration'].addSessionConfiguration(configuration)

        # Create a hostel with two beds
        hostel = Hostel()
        hostel.hostel_id = u'hall-1'
        hostel.hostel_name = u'Hall 1'
        self.app['hostels'].addHostel(hostel)
        bed = Bed()
        bed.bed_id = u'hall-1_A_101_A'
        bed.bed_number = 1
        bed.owner = NOT_OCCUPIED
        bed.bed_type = u'regular_male_fr'
        self.app['hostels'][hostel.hostel_id].addBed(bed)
        bed = Bed()
        bed.bed_id = u'hall-1_A_101_B'
        bed.bed_number = 2
        bed.owner = NOT_OCCUPIED
        bed.bed_type = u'regular_female_fr'
        self.app['hostels'][hostel.hostel_id].addBed(bed)

        # Set study course attributes of test student
        self.student['studycourse'].certificate = self.certificate
        self.student['studycourse'].current_session = 2004
        self.student['studycourse'].entry_session = 2004
        self.student['studycourse'].current_verdict = 'A'
        self.student['studycourse'].current_level = 100
        # Update the catalog
        notify(grok.ObjectModifiedEvent(self.student))

        # Put the prepopulated site into test ZODB and prepare test
        # browser
        self.browser = Browser()
        self.browser.handleErrors = False

    def tearDown(self):
        super(StudentsFullSetup, self).tearDown()
        clearSite()
        shutil.rmtree(self.dc_root)



class StudentsContainerUITests(StudentsFullSetup):
    # Tests for StudentsContainer class views and pages

    layer = FunctionalLayer

    def test_anonymous_access(self):
        # Anonymous users can't access students containers
        self.assertRaises(
            Unauthorized, self.browser.open, self.container_path)
        self.assertRaises(
            Unauthorized, self.browser.open, self.manage_container_path)
        return

    def test_manage_access(self):
        # Managers can access the view page of students
        # containers and can perform actions
        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
        self.browser.open(self.container_path)
        self.assertEqual(self.browser.headers['Status'], '200 Ok')
        self.assertEqual(self.browser.url, self.container_path)
        self.browser.getLink("Manage student section").click()
        self.assertEqual(self.browser.headers['Status'], '200 Ok')
        self.assertEqual(self.browser.url, self.manage_container_path)
        return

    def test_add_search_delete_students(self):
        # Managers can add search and remove students
        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
        self.browser.open(self.manage_container_path)
        self.browser.getLink("Add student").click()
        self.assertEqual(self.browser.headers['Status'], '200 Ok')
        self.assertEqual(self.browser.url, self.add_student_path)
        self.browser.getControl(name="form.firstname").value = 'Bob'
        self.browser.getControl(name="form.lastname").value = 'Tester'
        self.browser.getControl(name="form.reg_number").value = '1234'
        self.browser.getControl("Create student record").click()
        self.assertTrue('Student record created' in self.browser.contents)

        # Registration and matric numbers must be unique
        self.browser.getLink("Manage").click()
        self.browser.getControl(name="form.reg_number").value = '123'
        self.browser.getControl("Save").click()
        self.assertMatches('...Registration number exists...',
                           self.browser.contents)
        self.browser.getControl(name="form.reg_number").value = '789'
        self.browser.getControl(name="form.matric_number").value = '234'
        self.browser.getControl("Save").click()
        self.assertMatches('...Matriculation number exists...',
                           self.browser.contents)

        # We can find a student with a certain student_id
        self.browser.open(self.container_path)
        self.browser.getControl("Search").click()
        self.assertTrue('Empty search string' in self.browser.contents)
        self.browser.getControl(name="searchtype").value = ['student_id']
        self.browser.getControl(name="searchterm").value = self.student_id
        self.browser.getControl("Search").click()
        self.assertTrue('Anna Tester' in self.browser.contents)

        # We can find a student in a certain session
        self.browser.open(self.container_path)
        self.browser.getControl(name="searchtype").value = ['current_session']
        self.browser.getControl(name="searchterm").value = '2004'
        self.browser.getControl("Search").click()
        self.assertTrue('Anna Tester' in self.browser.contents)
        # Session fileds require integer values
        self.browser.open(self.container_path)
        self.browser.getControl(name="searchtype").value = ['current_session']
        self.browser.getControl(name="searchterm").value = '2004/2005'
        self.browser.getControl("Search").click()
        self.assertTrue('Only year dates allowed' in self.browser.contents)
        self.browser.open(self.manage_container_path)
        self.browser.getControl(name="searchtype").value = ['current_session']
        self.browser.getControl(name="searchterm").value = '2004/2005'
        self.browser.getControl("Search").click()
        self.assertTrue('Only year dates allowed' in self.browser.contents)

        # We can find a student in a certain study_mode
        self.browser.open(self.container_path)
        self.browser.getControl(name="searchtype").value = ['current_mode']
        self.browser.getControl(name="searchterm").value = 'ug_ft'
        self.browser.getControl("Search").click()
        self.assertTrue('Anna Tester' in self.browser.contents)

        # We can find a student in a certain department
        self.browser.open(self.container_path)
        self.browser.getControl(name="searchtype").value = ['depcode']
        self.browser.getControl(name="searchterm").value = 'dep1'
        self.browser.getControl("Search").click()
        self.assertTrue('Anna Tester' in self.browser.contents)

        # We can find a student by searching for all kind of name parts
        self.browser.open(self.manage_container_path)
        self.browser.getControl("Search").click()
        self.assertTrue('Empty search string' in self.browser.contents)
        self.browser.getControl(name="searchtype").value = ['fullname']
        self.browser.getControl(name="searchterm").value = 'Anna Tester'
        self.browser.getControl("Search").click()
        self.assertTrue('Anna Tester' in self.browser.contents)
        self.browser.open(self.manage_container_path)
        self.browser.getControl(name="searchtype").value = ['fullname']
        self.browser.getControl(name="searchterm").value = 'Anna'
        self.browser.getControl("Search").click()
        self.assertTrue('Anna Tester' in self.browser.contents)
        self.browser.open(self.manage_container_path)
        self.browser.getControl(name="searchtype").value = ['fullname']
        self.browser.getControl(name="searchterm").value = 'Tester'
        self.browser.getControl("Search").click()
        self.assertTrue('Anna Tester' in self.browser.contents)
        self.browser.open(self.manage_container_path)
        self.browser.getControl(name="searchtype").value = ['fullname']
        self.browser.getControl(name="searchterm").value = 'An'
        self.browser.getControl("Search").click()
        self.assertFalse('Anna Tester' in self.browser.contents)
        self.browser.open(self.manage_container_path)
        self.browser.getControl(name="searchtype").value = ['fullname']
        self.browser.getControl(name="searchterm").value = 'An*'
        self.browser.getControl("Search").click()
        self.assertTrue('Anna Tester' in self.browser.contents)
        self.browser.open(self.manage_container_path)
        self.browser.getControl(name="searchtype").value = ['fullname']
        self.browser.getControl(name="searchterm").value = 'tester'
        self.browser.getControl("Search").click()
        self.assertTrue('Anna Tester' in self.browser.contents)
        self.browser.open(self.manage_container_path)
        self.browser.getControl(name="searchtype").value = ['fullname']
        self.browser.getControl(name="searchterm").value = 'Tester Ana'
        self.browser.getControl("Search").click()
        self.assertFalse('Anna Tester' in self.browser.contents)
        self.browser.open(self.manage_container_path)
        self.browser.getControl(name="searchtype").value = ['fullname']
        self.browser.getControl(name="searchterm").value = 'Tester Anna'
        self.browser.getControl("Search").click()
        self.assertTrue('Anna Tester' in self.browser.contents)
        # The old searchterm will be used again
        self.browser.getControl("Search").click()
        self.assertTrue('Anna Tester' in self.browser.contents)

        # The catalog is informed when studycourse objects have been
        # edited
        self.browser.open(self.studycourse_path + '/manage')
        self.browser.getControl(name="form.current_session").value = ['2010']
        self.browser.getControl(name="form.entry_session").value = ['2010']
        self.browser.getControl(name="form.entry_mode").value = ['ug_ft']
        self.browser.getControl("Save").click()

        # We can find the student in the new session
        self.browser.open(self.manage_container_path)
        self.browser.getControl(name="searchtype").value = ['current_session']
        self.browser.getControl(name="searchterm").value = '2010'
        self.browser.getControl("Search").click()
        self.assertTrue('Anna Tester' in self.browser.contents)

        ctrl = self.browser.getControl(name='entries')
        ctrl.getControl(value=self.student_id).selected = True
        self.browser.getControl("Remove selected", index=0).click()
        self.assertTrue('Successfully removed' in self.browser.contents)
        self.browser.getControl(name="searchtype").value = ['student_id']
        self.browser.getControl(name="searchterm").value = self.student_id
        self.browser.getControl("Search").click()
        self.assertTrue('No student found' in self.browser.contents)

        self.browser.open(self.container_path)
        self.browser.getControl(name="searchtype").value = ['student_id']
        self.browser.getControl(name="searchterm").value = self.student_id
        self.browser.getControl("Search").click()
        self.assertTrue('No student found' in self.browser.contents)
        return

class StudentUITests(StudentsFullSetup):
    # Tests for Student class views and pages

    layer = FunctionalLayer

    def test_basic_auth(self):
        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
        self.browser.open('http://localhost/app')
        self.browser.getLink("Logout").click()
        self.assertTrue('You have been logged out' in self.browser.contents)
        # But we are still logged in since we've used basic authentication here.
        # Wikipedia says: Existing browsers retain authentication information
        # until the tab or browser is closed or the user clears the history.
        # HTTP does not provide a method for a server to direct clients to
        # discard these cached credentials. This means that there is no
        # effective way for a server to "log out" the user without closing
        # the browser. This is a significant defect that requires browser
        # manufacturers to support a "logout" user interface element ...
        self.assertTrue('Manager' in self.browser.contents)

    def test_manage_access(self):
        # Managers can access the pages of students
        # and can perform actions
        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
        self.browser.open(self.student_path)
        self.assertEqual(self.browser.headers['Status'], '200 Ok')
        self.assertEqual(self.browser.url, self.student_path)
        self.browser.getLink("Manage").click()
        self.assertEqual(self.browser.headers['Status'], '200 Ok')
        self.assertEqual(self.browser.url, self.manage_student_path)
        # Managers can edit base data and fire transitions
        self.browser.getControl(name="transition").value = ['admit']
        self.browser.getControl(name="form.firstname").value = 'John'
        self.browser.getControl(name="form.lastname").value = 'Tester'
        self.browser.getControl(name="form.reg_number").value = '345'
        self.browser.getControl(name="password").value = 'secret'
        self.browser.getControl(name="control_password").value = 'secret'
        self.browser.getControl("Save").click()
        self.assertMatches('...Form has been saved...',
                           self.browser.contents)
        self.browser.open(self.student_path)
        self.browser.getLink("Clearance Data").click()
        self.assertEqual(self.browser.headers['Status'], '200 Ok')
        self.assertEqual(self.browser.url, self.clearance_path)
        self.browser.getLink("Manage").click()
        self.assertEqual(self.browser.headers['Status'], '200 Ok')
        self.assertEqual(self.browser.url, self.manage_clearance_path)
        self.browser.getControl(name="form.date_of_birth").value = '09/10/1961'
        self.browser.getControl("Save").click()
        self.assertMatches('...Form has been saved...',
                           self.browser.contents)

        self.browser.open(self.student_path)
        self.browser.getLink("Personal Data").click()
        self.assertEqual(self.browser.headers['Status'], '200 Ok')
        self.assertEqual(self.browser.url, self.personal_path)
        self.browser.getLink("Edit").click()
        self.assertEqual(self.browser.headers['Status'], '200 Ok')
        self.assertEqual(self.browser.url, self.edit_personal_path)
        self.browser.getControl("Save").click()
        self.assertMatches('...Form has been saved...',
                           self.browser.contents)

        # Managers can browse all subobjects
        self.browser.open(self.student_path)
        self.browser.getLink("Payments").click()
        self.assertEqual(self.browser.headers['Status'], '200 Ok')
        self.assertEqual(self.browser.url, self.payments_path)
        self.browser.open(self.student_path)
        self.browser.getLink("Accommodation").click()
        self.assertEqual(self.browser.headers['Status'], '200 Ok')
        self.assertEqual(self.browser.url, self.acco_path)
        self.browser.open(self.student_path)
        self.browser.getLink("History").click()
        self.assertEqual(self.browser.headers['Status'], '200 Ok')
        self.assertEqual(self.browser.url, self.history_path)
        self.assertMatches('...Student admitted by Manager...',
                           self.browser.contents)
        # Only the Application Slip does not exist
        self.assertFalse('Application Slip' in self.browser.contents)
        return

    def test_manage_contact_student(self):
        # Managers can contact student
        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
        self.browser.open(self.student_path)
        self.browser.getLink("Send email").click()
        self.browser.getControl(name="form.subject").value = 'Important subject'
        self.browser.getControl(name="form.body").value = 'Hello!'
        self.browser.getControl("Send message now").click()
        self.assertTrue('Your message has been sent' in self.browser.contents)
        return

    def test_manage_remove_department(self):
        # Lazy student is studying CERT1
        lazystudent = Student()
        lazystudent.firstname = u'Lazy'
        lazystudent.lastname = u'Student'
        self.app['students'].addStudent(lazystudent)
        student_id = lazystudent.student_id
        student_path = self.container_path + '/' + student_id
        lazystudent['studycourse'].certificate = self.certificate
        notify(grok.ObjectModifiedEvent(lazystudent))
        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
        self.browser.open(student_path + '/studycourse')
        self.assertTrue('CERT1' in self.browser.contents)
        # After some years the department is removed
        del self.app['faculties']['fac1']['dep1']
        # So CERT1 does no longer exist and lazy student's
        # certificate reference is removed too
        self.browser.open(student_path + '/studycourse')
        self.assertEqual(self.browser.headers['Status'], '200 Ok')
        self.assertEqual(self.browser.url, student_path + '/studycourse')
        self.assertFalse('CERT1' in self.browser.contents)
        self.assertMatches('...<div>--</div>...',
                           self.browser.contents)

    def test_manage_upload_file(self):
        # Managers can upload a file via the StudentClearanceManageFormPage
        # The image is stored even if form has errors
        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
        self.browser.open(self.manage_clearance_path)
        # No birth certificate has been uploaded yet
        # Browsing the link shows a placerholder image
        self.browser.open('birth_certificate')
        self.assertEqual(
            self.browser.headers['content-type'], 'image/jpeg')
        self.assertEqual(len(self.browser.contents), PH_LEN)
        # Create a pseudo image file and select it to be uploaded in form
        # as birth certificate
        self.browser.open(self.manage_clearance_path)
        pseudo_image = StringIO('I pretend to be a graphics file')
        ctrl = self.browser.getControl(name='birthcertificateupload')
        file_ctrl = ctrl.mech_control
        file_ctrl.add_file(pseudo_image, filename='my_birth_certificate.jpg')
        # The Save action does not upload files
        self.browser.getControl("Save").click() # submit form
        self.assertFalse(
            '<a target="image" href="birth_certificate">'
            in self.browser.contents)
        # ... but the correct upload submit button does
        pseudo_image = StringIO('I pretend to be a graphics file')
        ctrl = self.browser.getControl(name='birthcertificateupload')
        file_ctrl = ctrl.mech_control
        file_ctrl.add_file(pseudo_image, filename='my_birth_certificate.jpg')
        self.browser.getControl(
            name='upload_birthcertificateupload').click()
        # There is a correct <img> link included
        self.assertTrue(
            '<a target="image" href="birth_certificate">'
            in self.browser.contents)
        # Browsing the link shows a real image
        self.browser.open('birth_certificate')
        self.assertEqual(
            self.browser.headers['content-type'], 'image/jpeg')
        self.assertEqual(len(self.browser.contents), 31)
        # Reuploading a file which is bigger than 150k will raise an error
        self.browser.open(self.manage_clearance_path)
        photo_content = 'A' * 1024 * 151  # A string of 21 KB size
        pseudo_image = StringIO(photo_content)
        ctrl = self.browser.getControl(name='birthcertificateupload')
        file_ctrl = ctrl.mech_control
        file_ctrl.add_file(pseudo_image, filename='my_birth_certificate.jpg')
        self.browser.getControl(
            name='upload_birthcertificateupload').click()
        self.assertTrue(
            'Uploaded file is too big' in self.browser.contents)
        # File names must meet several conditions
        pseudo_image = StringIO('I pretend to be a graphics file')
        ctrl = self.browser.getControl(name='birthcertificateupload')
        file_ctrl = ctrl.mech_control
        file_ctrl.add_file(pseudo_image, filename='my.photo.jpg')
        self.browser.getControl(
            name='upload_birthcertificateupload').click()
        self.assertTrue('File name contains more than one dot'
            in self.browser.contents)
        ctrl = self.browser.getControl(name='birthcertificateupload')
        file_ctrl = ctrl.mech_control
        file_ctrl.add_file(pseudo_image, filename='my_birth_certificate')
        self.browser.getControl(
            name='upload_birthcertificateupload').click()
        self.assertTrue('File name has no extension' in self.browser.contents)
        ctrl = self.browser.getControl(name='birthcertificateupload')
        file_ctrl = ctrl.mech_control
        file_ctrl.add_file(pseudo_image, filename='my_birth_certificate.bmp')
        self.browser.getControl(
            name='upload_birthcertificateupload').click()
        self.assertTrue('Only the following extension are allowed'
            in self.browser.contents)
        # Managers can delete files
        self.browser.getControl(name='delete_birthcertificateupload').click()
        self.assertTrue(
            'birth_certificate deleted' in self.browser.contents)
        # Managers can add and delete second file
        self.browser.open(self.manage_clearance_path)
        pseudo_image = StringIO('I pretend to be a graphics file')
        ctrl = self.browser.getControl(name='birthcertificateupload')
        file_ctrl = ctrl.mech_control
        file_ctrl.add_file(pseudo_image, filename='my_acceptance_letter.jpg')
        self.browser.getControl(
            name='upload_acceptanceletterupload').click()
        self.assertFalse(
            '<a target="image" href="acc_let">'
            in self.browser.contents)
        ctrl = self.browser.getControl(name='acceptanceletterupload')
        file_ctrl = ctrl.mech_control
        file_ctrl.add_file(pseudo_image, filename='my_acceptance_letter.jpg')
        self.browser.getControl(
            name='upload_acceptanceletterupload').click()
        self.assertTrue(
            '<a target="image" href="acc_let">'
            in self.browser.contents)
        self.browser.getControl(
            name='delete_acceptanceletterupload').click()
        self.assertTrue(
            'acc_let deleted'
            in self.browser.contents)
        # Managers can upload a file via the StudentBaseManageFormPage
        self.browser.open(self.manage_student_path)
        pseudo_image = StringIO('I pretend to be a graphics file')
        ctrl = self.browser.getControl(name='passportuploadmanage')
        file_ctrl = ctrl.mech_control
        file_ctrl.add_file(pseudo_image, filename='my_photo.bmp')
        self.browser.getControl(
            name='upload_passportuploadmanage').click()
        self.assertTrue('jpg file extension expected'
            in self.browser.contents)
        ctrl = self.browser.getControl(name='passportuploadmanage')
        file_ctrl = ctrl.mech_control
        file_ctrl.add_file(pseudo_image, filename='my_photo.jpg')
        self.browser.getControl(
            name='upload_passportuploadmanage').click()
        self.assertTrue(
            '<img align="middle" height="125px" src="passport.jpg" />'
            in self.browser.contents)
        # We remove the passport file again
        self.browser.open(self.manage_student_path)
        self.browser.getControl('Delete').click()
        self.browser.open(self.student_path + '/clearance.pdf')
        self.assertEqual(self.browser.headers['Status'], '200 Ok')
        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')

    def test_manage_course_lists(self):
        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
        self.browser.open(self.student_path)
        self.browser.getLink("Study Course").click()
        self.assertEqual(self.browser.headers['Status'], '200 Ok')
        self.assertEqual(self.browser.url, self.studycourse_path)
        self.assertTrue('Undergraduate Full-Time' in self.browser.contents)
        self.browser.getLink("Manage").click()
        self.assertTrue('Manage study course' in self.browser.contents)
        # Before we can select a level, the certificate must
        # be selected and saved
        self.browser.getControl(name="form.certificate").value = ['CERT1']
        self.browser.getControl(name="form.current_session").value = ['2004']
        self.browser.getControl(name="form.current_verdict").value = ['A']
        self.browser.getControl(name="form.entry_mode").value = ['ug_ft']
        self.browser.getControl("Save").click()
        # Now we can save also the current level which depends on start and end
        # level of the certificate
        self.browser.getControl(name="form.current_level").value = ['100']
        self.browser.getControl("Save").click()
        # Managers can add and remove any study level (course list)
        self.browser.getControl(name="addlevel").value = ['100']
        self.browser.getControl("Add study level").click()
        self.assertMatches('...<span>100</span>...', self.browser.contents)
        self.browser.getControl("Add study level").click()
        self.assertMatches('...This level exists...', self.browser.contents)
        self.browser.getControl("Remove selected").click()
        self.assertMatches(
            '...No study level selected...', self.browser.contents)
        self.browser.getControl(name="val_id").value = ['100']
        self.browser.getControl("Remove selected").click()
        self.assertMatches('...Successfully removed...', self.browser.contents)
        # Add level again
        self.browser.getControl(name="addlevel").value = ['100']
        self.browser.getControl("Add study level").click()

        # Managers can view and manage course lists
        self.browser.getLink("100").click()
        self.assertMatches(
            '...: Study Level 100 (Year 1)...', self.browser.contents)
        self.browser.getLink("Manage").click()
        self.browser.getControl(name="form.level_session").value = ['2002']
        self.browser.getControl("Save").click()
        self.browser.getControl("Remove selected").click()
        self.assertMatches('...No ticket selected...', self.browser.contents)
        ctrl = self.browser.getControl(name='val_id')
        ctrl.getControl(value='COURSE1').selected = True
        self.browser.getControl("Remove selected", index=0).click()
        self.assertTrue('Successfully removed' in self.browser.contents)
        self.browser.getControl("Add course ticket").click()
        self.browser.getControl(name="form.course").value = ['COURSE1']
        self.browser.getControl("Add course ticket").click()
        self.assertTrue('Successfully added' in self.browser.contents)
        self.browser.getControl("Add course ticket").click()
        self.browser.getControl(name="form.course").value = ['COURSE1']
        self.browser.getControl("Add course ticket").click()
        self.assertTrue('The ticket exists' in self.browser.contents)
        self.browser.getControl("Cancel").click()
        self.browser.getLink("COURSE1").click()
        self.browser.getLink("Manage").click()
        self.browser.getControl(name="form.score").value = '10'
        self.browser.getControl("Save").click()
        self.assertTrue('Form has been saved' in self.browser.contents)
        # Carry-over courses will be collected when next level is created
        self.browser.open(self.student_path + '/studycourse/manage')
        # Add next level
        self.browser.getControl(name="addlevel").value = ['200']
        self.browser.getControl("Add study level").click()
        self.browser.getLink("200").click()
        self.assertMatches(
            '...: Study Level 200 (Year 2)...', self.browser.contents)
        # COURSE1 has score 0 and thus will become a carry-over course
        # in level 200
        self.assertEqual(
            sorted(self.student['studycourse']['200'].keys()), [u'COURSE1'])
        self.assertTrue(
            self.student['studycourse']['200']['COURSE1'].carry_over)
        return

    def test_manage_workflow(self):
        # Managers can pass through the whole workflow
        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
        student = self.app['students'][self.student_id]
        self.browser.open(self.manage_student_path)
        self.assertTrue(student.clearance_locked)
        self.browser.getControl(name="transition").value = ['admit']
        self.browser.getControl("Save").click()
        self.assertTrue(student.clearance_locked)
        self.browser.getControl(name="transition").value = ['start_clearance']
        self.browser.getControl("Save").click()
        self.assertFalse(student.clearance_locked)
        self.browser.getControl(name="transition").value = ['request_clearance']
        self.browser.getControl("Save").click()
        self.assertTrue(student.clearance_locked)
        self.browser.getControl(name="transition").value = ['clear']
        self.browser.getControl("Save").click()
        self.browser.getControl(
            name="transition").value = ['pay_first_school_fee']
        self.browser.getControl("Save").click()
        self.browser.getControl(name="transition").value = ['reset6']
        self.browser.getControl("Save").click()
        # In state returning the pay_school_fee transition triggers some 
        # changes of attributes
        self.browser.getControl(name="transition").value = ['pay_school_fee']
        self.browser.getControl("Save").click()
        self.assertEqual(student['studycourse'].current_session, 2005) # +1
        self.assertEqual(student['studycourse'].current_level, 200) # +100
        self.assertEqual(student['studycourse'].current_verdict, '0') # 0 = not set
        self.assertEqual(student['studycourse'].previous_verdict, 'A')
        self.browser.getControl(name="transition").value = ['register_courses']
        self.browser.getControl("Save").click()
        self.browser.getControl(name="transition").value = ['validate_courses']
        self.browser.getControl("Save").click()
        self.browser.getControl(name="transition").value = ['return']
        self.browser.getControl("Save").click()
        return

    def test_manage_import(self):
        # Managers can import student data files
        datacenter_path = 'http://localhost/app/datacenter'
        # Prepare a csv file for students
        open('students.csv', 'wb').write(
"""firstname,lastname,reg_number,date_of_birth,matric_number,email,phone,sex,password
Aaren,Pieri,1,1990-01-02,100000,aa@aa.ng,1234,m,mypwd1
Claus,Finau,2,1990-01-03,100001,aa@aa.ng,1234,m,mypwd1
Brit,Berson,3,1990-01-04,100001,aa@aa.ng,1234,m,mypwd1
""")
        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
        self.browser.open(datacenter_path)
        self.browser.getLink('Upload CSV file').click()
        filecontents = StringIO(open('students.csv', 'rb').read())
        filewidget = self.browser.getControl(name='uploadfile:file')
        filewidget.add_file(filecontents, 'text/plain', 'students.csv')
        self.browser.getControl(name='SUBMIT').click()
        self.browser.getLink('Batch processing').click()
        button = lookup_submit_value(
            'select', 'students_zope.mgr.csv', self.browser)
        button.click()
        importerselect = self.browser.getControl(name='importer')
        modeselect = self.browser.getControl(name='mode')
        importerselect.getControl('Student Processor').selected = True
        modeselect.getControl(value='create').selected = True
        self.browser.getControl('Proceed to step 3').click()
        self.assertTrue('Header fields OK' in self.browser.contents)
        self.browser.getControl('Perform import').click()
        self.assertTrue('Processing of 1 rows failed' in self.browser.contents)
        self.assertTrue('Successfully processed 2 rows' in self.browser.contents)
        self.assertTrue('Batch processing finished' in self.browser.contents)
        open('studycourses.csv', 'wb').write(
"""reg_number,matric_number,certificate,current_session,current_level
1,,CERT1,2008,100
,100001,CERT1,2008,100
,100002,CERT1,2008,100
""")
        self.browser.open(datacenter_path)
        self.browser.getLink('Upload CSV file').click()
        filecontents = StringIO(open('studycourses.csv', 'rb').read())
        filewidget = self.browser.getControl(name='uploadfile:file')
        filewidget.add_file(filecontents, 'text/plain', 'studycourses.csv')
        self.browser.getControl(name='SUBMIT').click()
        self.browser.getLink('Batch processing').click()
        button = lookup_submit_value(
            'select', 'studycourses_zope.mgr.csv', self.browser)
        button.click()
        importerselect = self.browser.getControl(name='importer')
        modeselect = self.browser.getControl(name='mode')
        importerselect.getControl(
            'StudentStudyCourse Processor (update only)').selected = True
        modeselect.getControl(value='create').selected = True
        self.browser.getControl('Proceed to step 3').click()
        self.assertTrue('Update mode only' in self.browser.contents)
        self.browser.getControl('Proceed to step 3').click()
        self.assertTrue('Header fields OK' in self.browser.contents)
        self.browser.getControl('Perform import').click()
        self.assertTrue('Processing of 1 rows failed' in self.browser.contents)
        self.assertTrue('Successfully processed 2 rows'
                        in self.browser.contents)
        # The students are properly indexed and we can
        # thus find a student in  the department
        self.browser.open(self.manage_container_path)
        self.browser.getControl(name="searchtype").value = ['depcode']
        self.browser.getControl(name="searchterm").value = 'dep1'
        self.browser.getControl("Search").click()
        self.assertTrue('Aaren Pieri' in self.browser.contents)
        # We can search for a new student by name ...
        self.browser.getControl(name="searchtype").value = ['fullname']
        self.browser.getControl(name="searchterm").value = 'Claus'
        self.browser.getControl("Search").click()
        self.assertTrue('Claus Finau' in self.browser.contents)
        # ... and check if the imported password has been properly set
        ctrl = self.browser.getControl(name='entries')
        value = ctrl.options[0]
        claus = self.app['students'][value]
        self.assertTrue(IUserAccount(claus).checkPassword('mypwd1'))
        return

    def test_handle_clearance_by_co(self):
        # Create clearance officer
        self.app['users'].addUser('mrclear', 'mrclearsecret')
        self.app['users']['mrclear'].email = 'mrclear@foo.ng'
        self.app['users']['mrclear'].title = 'Carlo Pitter'
        # Clearance officers need not necessarily to get
        # the StudentsOfficer site role
        #prmglobal = IPrincipalRoleManager(self.app)
        #prmglobal.assignRoleToPrincipal('waeup.StudentsOfficer', 'mrclear')
        # Assign local ClearanceOfficer role
        department = self.app['faculties']['fac1']['dep1']
        prmlocal = IPrincipalRoleManager(department)
        prmlocal.assignRoleToPrincipal('waeup.local.ClearanceOfficer', 'mrclear')
        IWorkflowState(self.student).setState('clearance started')
        # Login as clearance officer
        self.browser.open(self.login_path)
        self.browser.getControl(name="form.login").value = 'mrclear'
        self.browser.getControl(name="form.password").value = 'mrclearsecret'
        self.browser.getControl("Login").click()
        self.assertMatches('...You logged in...', self.browser.contents)
        # CO can see his roles
        self.browser.getLink("My Roles").click()
        self.assertMatches(
            '...<div>Academics Officer (view only)</div>...',
            self.browser.contents)
        #self.assertMatches(
        #    '...<div>Students Officer (view only)</div>...',
        #    self.browser.contents)
        # But not his local role ...
        self.assertFalse('Clearance Officer' in self.browser.contents)
        # ... because we forgot to notify the department that the local role
        # has changed
        notify(LocalRoleSetEvent(
            department, 'waeup.local.ClearanceOfficer', 'mrclear', granted=True))
        self.browser.open('http://localhost/app/users/mrclear/my_roles')
        self.assertTrue('Clearance Officer' in self.browser.contents)
        self.assertMatches(
            '...<a href="http://localhost/app/faculties/fac1/dep1">...',
            self.browser.contents)
        # CO can view the student ...
        self.browser.open(self.clearance_path)
        self.assertEqual(self.browser.headers['Status'], '200 Ok')
        self.assertEqual(self.browser.url, self.clearance_path)
        # ... but not other students
        other_student = Student()
        other_student.firstname = u'Dep2'
        other_student.lastname = u'Student'
        self.app['students'].addStudent(other_student)
        other_student_path = (
            'http://localhost/app/students/%s' % other_student.student_id)
        self.assertRaises(
            Unauthorized, self.browser.open, other_student_path)
        # Only in state clearance requested the CO does see the 'Clear' button
        self.browser.open(self.clearance_path)
        self.assertFalse('Clear student' in self.browser.contents)
        IWorkflowInfo(self.student).fireTransition('request_clearance')
        self.browser.open(self.clearance_path)
        self.assertTrue('Clear student' in self.browser.contents)
        self.browser.getLink("Clear student").click()
        self.assertTrue('Student has been cleared' in self.browser.contents)
        self.assertTrue('cleared' in self.browser.contents)
        self.browser.getLink("Reject clearance").click()
        self.assertTrue('Clearance has been annulled' in self.browser.contents)
        urlmessage = 'Clearance+has+been+annulled.'
        # CO does now see the contact form
        self.assertEqual(self.browser.url, self.student_path +
            '/contactstudent?subject=%s' % urlmessage)
        self.assertTrue('clearance started' in self.browser.contents)
        IWorkflowInfo(self.student).fireTransition('request_clearance')
        self.browser.open(self.clearance_path)
        self.browser.getLink("Reject clearance").click()
        self.assertTrue('Clearance request has been rejected'
            in self.browser.contents)
        self.assertTrue('clearance started' in self.browser.contents)
        # CO does now also see the contact form and can send a message
        self.browser.getControl(name="form.subject").value = 'Important subject'
        self.browser.getControl(name="form.body").value = 'Clearance rejected'
        self.browser.getControl("Send message now").click()
        self.assertTrue('Your message has been sent' in self.browser.contents)
        # The CO can't clear students if not in state
        # clearance requested
        self.browser.open(self.student_path + '/clear')
        self.assertTrue('Student is in wrong state'
            in self.browser.contents)
        # The CO can go to his department throug the my_roles page
        self.browser.open('http://localhost/app/users/mrclear/my_roles')
        self.browser.getLink("http://localhost/app/faculties/fac1/dep1").click()
        # and view the list of students
        self.browser.getLink("Show students").click()
        self.assertTrue(self.student_id in self.browser.contents)

    def test_handle_courses_by_ca(self):
        # Create course adviser
        self.app['users'].addUser('mrsadvise', 'mrsadvisesecret')
        self.app['users']['mrsadvise'].email = 'mradvise@foo.ng'
        self.app['users']['mrsadvise'].title = 'Helen Procter'
        # Assign local CourseAdviser100 role for a certificate
        cert = self.app['faculties']['fac1']['dep1'].certificates['CERT1']
        prmlocal = IPrincipalRoleManager(cert)
        prmlocal.assignRoleToPrincipal('waeup.local.CourseAdviser100', 'mrsadvise')
        IWorkflowState(self.student).setState('school fee paid')
        # Login as course adviser
        self.browser.open(self.login_path)
        self.browser.getControl(name="form.login").value = 'mrsadvise'
        self.browser.getControl(name="form.password").value = 'mrsadvisesecret'
        self.browser.getControl("Login").click()
        self.assertMatches('...You logged in...', self.browser.contents)
        # CO can see his roles
        self.browser.getLink("My Roles").click()
        self.assertMatches(
            '...<div>Academics Officer (view only)</div>...',
            self.browser.contents)
        # But not his local role ...
        self.assertFalse('Course Adviser' in self.browser.contents)
        # ... because we forgot to notify the certificate that the local role
        # has changed
        notify(LocalRoleSetEvent(
            cert, 'waeup.local.CourseAdviser100', 'mrsadvise', granted=True))
        self.browser.open('http://localhost/app/users/mrsadvise/my_roles')
        self.assertTrue('Course Adviser 100L' in self.browser.contents)
        self.assertMatches(
            '...<a href="http://localhost/app/faculties/fac1/dep1/certificates/CERT1">...',
            self.browser.contents)
        # CA can view the student ...
        self.browser.open(self.student_path)
        self.assertEqual(self.browser.headers['Status'], '200 Ok')
        self.assertEqual(self.browser.url, self.student_path)
        # ... but not other students
        other_student = Student()
        other_student.firstname = u'Dep2'
        other_student.lastname = u'Student'
        self.app['students'].addStudent(other_student)
        other_student_path = (
            'http://localhost/app/students/%s' % other_student.student_id)
        self.assertRaises(
            Unauthorized, self.browser.open, other_student_path)
        # We add study level 110 to the student's studycourse
        studylevel = StudentStudyLevel()
        studylevel.level = 110
        self.student['studycourse'].addStudentStudyLevel(
            cert,studylevel)
        L110_student_path = self.studycourse_path + '/110'
        # Only in state courses registered and only if the current level
        # corresponds with the name of the study level object
        # the 100L CA does see the 'Validate' button
        self.browser.open(L110_student_path)
        self.assertFalse('Validate' in self.browser.contents)
        IWorkflowInfo(self.student).fireTransition('register_courses')
        self.browser.open(L110_student_path)
        self.assertFalse('Validate' in self.browser.contents)
        self.student['studycourse'].current_level = 110
        self.browser.open(L110_student_path)
        self.assertTrue('Validate' in self.browser.contents)
        # ... but a 100L CA does not see the button on other levels
        studylevel2 = StudentStudyLevel()
        studylevel2.level = 200
        self.student['studycourse'].addStudentStudyLevel(
            cert,studylevel2)
        L200_student_path = self.studycourse_path + '/200'
        self.browser.open(L200_student_path)
        self.assertFalse('Validate' in self.browser.contents)
        self.browser.open(L110_student_path)
        self.browser.getLink("Validate courses").click()
        self.assertTrue('Course list has been validated' in self.browser.contents)
        self.assertTrue('courses validated' in self.browser.contents)
        self.browser.getLink("Reject courses").click()
        self.assertTrue('Course list request has been annulled.'
            in self.browser.contents)
        urlmessage = 'Course+list+request+has+been+annulled.'
        self.assertEqual(self.browser.url, self.student_path +
            '/contactstudent?subject=%s' % urlmessage)
        self.assertTrue('school fee paid' in self.browser.contents)
        IWorkflowInfo(self.student).fireTransition('register_courses')
        self.browser.open(L110_student_path)
        self.browser.getLink("Reject courses").click()
        self.assertTrue('Course list request has been rejected'
            in self.browser.contents)
        self.assertTrue('school fee paid' in self.browser.contents)
        # CA does now see the contact form and can send a message
        self.browser.getControl(name="form.subject").value = 'Important subject'
        self.browser.getControl(name="form.body").value = 'Course list rejected'
        self.browser.getControl("Send message now").click()
        self.assertTrue('Your message has been sent' in self.browser.contents)
        # The CA can't validate courses if not in state
        # courses registered
        self.browser.open(L110_student_path + '/validate_courses')
        self.assertTrue('Student is in the wrong state'
            in self.browser.contents)
        # The CA can go to his certificate throug the my_roles page
        self.browser.open('http://localhost/app/users/mrsadvise/my_roles')
        self.browser.getLink(
            "http://localhost/app/faculties/fac1/dep1/certificates/CERT1").click()
        # and view the list of students
        self.browser.getLink("Show students").click()
        self.assertTrue(self.student_id in self.browser.contents)

    def test_student_change_password(self):
        # Students can change the password
        self.browser.open(self.login_path)
        self.browser.getControl(name="form.login").value = self.student_id
        self.browser.getControl(name="form.password").value = 'spwd'
        self.browser.getControl("Login").click()
        self.assertEqual(self.browser.url, self.student_path)
        self.assertTrue('You logged in' in self.browser.contents)
        # Change password
        self.browser.getLink("Change password").click()
        self.browser.getControl(name="change_password").value = 'pw'
        self.browser.getControl(
            name="change_password_repeat").value = 'pw'
        self.browser.getControl("Save").click()
        self.assertTrue('Password must have at least' in self.browser.contents)
        self.browser.getControl(name="change_password").value = 'new_password'
        self.browser.getControl(
            name="change_password_repeat").value = 'new_passssword'
        self.browser.getControl("Save").click()
        self.assertTrue('Passwords do not match' in self.browser.contents)
        self.browser.getControl(name="change_password").value = 'new_password'
        self.browser.getControl(
            name="change_password_repeat").value = 'new_password'
        self.browser.getControl("Save").click()
        self.assertTrue('Password changed' in self.browser.contents)
        # We are still logged in. Changing the password hasn't thrown us out.
        self.browser.getLink("Base Data").click()
        self.assertEqual(self.browser.url, self.student_path)
        # We can logout
        self.browser.getLink("Logout").click()
        self.assertTrue('You have been logged out' in self.browser.contents)
        self.assertEqual(self.browser.url, 'http://localhost/app')
        # We can login again with the new password
        self.browser.getLink("Login").click()
        self.browser.open(self.login_path)
        self.browser.getControl(name="form.login").value = self.student_id
        self.browser.getControl(name="form.password").value = 'new_password'
        self.browser.getControl("Login").click()
        self.assertEqual(self.browser.url, self.student_path)
        self.assertTrue('You logged in' in self.browser.contents)
        return

    def test_setpassword(self):
        # Set password for first-time access
        student = Student()
        student.reg_number = u'123456'
        student.firstname = u'Klaus'
        student.lastname = u'Tester'
        self.app['students'].addStudent(student)
        setpassword_path = 'http://localhost/app/setpassword'
        student_path = 'http://localhost/app/students/%s' % student.student_id
        self.browser.open(setpassword_path)
        self.browser.getControl(name="ac_series").value = self.existing_pwdseries
        self.browser.getControl(name="ac_number").value = self.existing_pwdnumber
        self.browser.getControl(name="reg_number").value = '223456'
        self.browser.getControl("Set").click()
        self.assertMatches('...No student found...',
                           self.browser.contents)
        self.browser.getControl(name="reg_number").value = '123456'
        self.browser.getControl(name="ac_number").value = '999999'
        self.browser.getControl("Set").click()
        self.assertMatches('...Access code is invalid...',
                           self.browser.contents)
        self.browser.getControl(name="ac_number").value = self.existing_pwdnumber
        self.browser.getControl("Set").click()
        self.assertMatches('...Password has been set. Your Student Id is...',
                           self.browser.contents)
        self.browser.getControl("Set").click()
        self.assertMatches(
            '...Password has already been set. Your Student Id is...',
            self.browser.contents)
        existing_pwdpin = self.pwdpins[1]
        parts = existing_pwdpin.split('-')[1:]
        existing_pwdseries, existing_pwdnumber = parts
        self.browser.getControl(name="ac_series").value = existing_pwdseries
        self.browser.getControl(name="ac_number").value = existing_pwdnumber
        self.browser.getControl(name="reg_number").value = '123456'
        self.browser.getControl("Set").click()
        self.assertMatches(
            '...You are using the wrong Access Code...',
            self.browser.contents)
        # The student can login with the new credentials
        self.browser.open(self.login_path)
        self.browser.getControl(name="form.login").value = student.student_id
        self.browser.getControl(
            name="form.password").value = self.existing_pwdnumber
        self.browser.getControl("Login").click()
        self.assertEqual(self.browser.url, student_path)
        self.assertTrue('You logged in' in self.browser.contents)
        return

    def test_student_access(self):
        # Students can access their own objects
        # and can perform actions
        IWorkflowInfo(self.student).fireTransition('admit')
        self.browser.open(self.login_path)
        self.browser.getControl(name="form.login").value = self.student_id
        self.browser.getControl(name="form.password").value = 'spwd'
        self.browser.getControl("Login").click()
        # Student can upload a passport picture
        self.browser.open(self.student_path + '/change_portrait')
        ctrl = self.browser.getControl(name='passportuploadedit')
        file_obj = open(
            os.path.join(os.path.dirname(__file__), 'test_image.jpg'),'rb')
        file_ctrl = ctrl.mech_control
        file_ctrl.add_file(file_obj, filename='my_photo.jpg')
        self.browser.getControl(
            name='upload_passportuploadedit').click()
        self.assertTrue(
            '<img align="middle" height="125px" src="passport.jpg" />'
            in self.browser.contents)
        # Student can view the clearance data
        self.browser.getLink("Clearance Data").click()
        # Student can't open clearance edit form before starting clearance
        self.browser.open(self.student_path + '/cedit')
        self.assertMatches('...The requested form is locked...',
                           self.browser.contents)
        self.browser.getLink("Clearance Data").click()
        self.browser.getLink("Start clearance").click()
        self.student.email = None
        # Uups, we forgot to fill the email fields
        self.browser.getControl("Start clearance").click()
        self.assertMatches('...Not all required fields filled...',
                           self.browser.contents)
        self.student.email = 'aa@aa.ng'
        self.browser.open(self.student_path + '/start_clearance')
        self.browser.getControl(name="ac_series").value = '3'
        self.browser.getControl(name="ac_number").value = '4444444'
        self.browser.getControl("Start clearance now").click()
        self.assertMatches('...Activation code is invalid...',
                           self.browser.contents)
        self.browser.getControl(name="ac_series").value = self.existing_clrseries
        self.browser.getControl(name="ac_number").value = self.existing_clrnumber
        # Owner is Hans Wurst, AC can't be invalidated
        self.browser.getControl("Start clearance now").click()
        self.assertMatches('...You are not the owner of this access code...',
                           self.browser.contents)
        # Set the correct owner
        self.existing_clrac.owner = self.student_id
        self.browser.getControl("Start clearance now").click()
        self.assertMatches('...Clearance process has been started...',
                           self.browser.contents)
        self.browser.getControl(name="form.date_of_birth").value = '09/10/1961'
        self.browser.getControl("Save", index=0).click()
        # Student can view the clearance data
        self.browser.getLink("Clearance Data").click()
        # and go back to the edit form
        self.browser.getLink("Edit").click()
        # Students can upload documents
        ctrl = self.browser.getControl(name='birthcertificateupload')
        file_obj = open(
            os.path.join(os.path.dirname(__file__), 'test_image.jpg'),'rb')
        file_ctrl = ctrl.mech_control
        file_ctrl.add_file(file_obj, filename='my_birth_certificate.jpg')
        self.browser.getControl(
            name='upload_birthcertificateupload').click()
        self.assertTrue(
            '<a target="image" href="birth_certificate">Birth Certificate Scan</a>'
            in self.browser.contents)
        # Students can open clearance slip
        self.browser.getLink("View").click()
        self.browser.getLink("Download clearance slip").click()
        self.assertEqual(self.browser.headers['Status'], '200 Ok')
        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
        # Students can request clearance
        self.browser.open(self.edit_clearance_path)
        self.browser.getControl("Save and request clearance").click()
        self.browser.getControl(name="ac_series").value = self.existing_clrseries
        self.browser.getControl(name="ac_number").value = self.existing_clrnumber
        self.browser.getControl("Request clearance now").click()
        self.assertMatches('...Clearance has been requested...',
                           self.browser.contents)
        # Student can't reopen clearance form after requesting clearance
        self.browser.open(self.student_path + '/cedit')
        self.assertMatches('...The requested form is locked...',
                           self.browser.contents)
        # Student can't add study level if not in state 'school fee paid'
        self.browser.open(self.student_path + '/studycourse/add')
        self.assertMatches('...The requested form is locked...',
                           self.browser.contents)
        # ... and must be transferred first
        IWorkflowInfo(self.student).fireTransition('clear')
        IWorkflowInfo(self.student).fireTransition('pay_first_school_fee')
        # Now students can add the current study level
        self.browser.getLink("Study Course").click()
        self.browser.getLink("Add course list").click()
        self.assertMatches('...Add current level 100 (Year 1)...',
                           self.browser.contents)
        self.browser.getControl("Create course list now").click()
        self.browser.getLink("100").click()
        self.browser.getLink("Add and remove courses").click()
        self.browser.getControl("Add course ticket").click()
        self.browser.getControl(name="form.course").value = ['COURSE1']
        self.browser.getControl("Add course ticket").click()
        self.assertMatches('...The ticket exists...',
                           self.browser.contents)
        self.student['studycourse'].current_level = 200
        self.browser.getLink("Study Course").click()
        self.browser.getLink("Add course list").click()
        self.assertMatches('...Add current level 200 (Year 2)...',
                           self.browser.contents)
        self.browser.getControl("Create course list now").click()
        self.browser.getLink("200").click()
        self.browser.getLink("Add and remove courses").click()
        self.browser.getControl("Add course ticket").click()
        self.browser.getControl(name="form.course").value = ['COURSE1']
        self.browser.getControl("Add course ticket").click()
        self.assertMatches('...The ticket exists...',
                           self.browser.contents)
        # Indeed the ticket exists as carry-over course from level 100
        # since its score was 0
        self.assertTrue(
            self.student['studycourse']['200']['COURSE1'].carry_over is True)
        # Students can open the pdf course registration slip
        self.browser.open(self.student_path + '/studycourse/200')
        self.browser.getLink("Download course registration slip").click()
        self.assertEqual(self.browser.headers['Status'], '200 Ok')
        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
        # Students can remove course tickets
        self.browser.open(self.student_path + '/studycourse/200/edit')
        self.browser.getControl("Remove selected", index=0).click()
        self.assertTrue('No ticket selected' in self.browser.contents)
        # No ticket can be selected since the carry-over course is a core course
        self.assertRaises(
            LookupError, self.browser.getControl, name='val_id')
        self.student['studycourse']['200']['COURSE1'].mandatory = False
        self.browser.open(self.student_path + '/studycourse/200/edit')
        # Now the student can remove the ticket
        ctrl = self.browser.getControl(name='val_id')
        ctrl.getControl(value='COURSE1').selected = True
        self.browser.getControl("Remove selected", index=0).click()
        self.assertTrue('Successfully removed' in self.browser.contents)
        self.browser.getControl("Register course list").click()
        self.assertTrue('Course list has been registered' in self.browser.contents)
        self.assertEqual(self.student.state, 'courses registered')
        return

    def test_manage_payments(self):
        # Managers can add online school fee payment tickets
        # if certain requirements are met
        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
        self.browser.open(self.payments_path)
        self.browser.getControl("Add online payment ticket").click()
        self.browser.getControl(name="form.p_category").value = ['schoolfee']
        self.browser.getControl("Create ticket").click()
        self.assertMatches('...ticket created...',
                           self.browser.contents)
        ctrl = self.browser.getControl(name='val_id')
        value = ctrl.options[0]
        self.browser.getLink(value).click()
        self.assertMatches('...Amount Authorized...',
                           self.browser.contents)
        payment_url = self.browser.url

        # The pdf payment slip can't yet be opened
        #self.browser.open(payment_url + '/payment_slip.pdf')
        #self.assertMatches('...Ticket not yet paid...',
        #                   self.browser.contents)

        # The same payment (with same p_item, p_session and p_category)
        # can be initialized a second time if the former ticket is not yet paid.
        self.browser.open(self.payments_path)
        self.browser.getControl("Add online payment ticket").click()
        self.browser.getControl(name="form.p_category").value = ['schoolfee']
        self.browser.getControl("Create ticket").click()
        self.assertMatches('...Payment ticket created...',
                           self.browser.contents)

        # Managers can open the callback view which simulates a valid callback
        self.assertEqual(len(self.app['accesscodes']['SFE-0']),0)
        self.browser.open(payment_url)
        self.browser.getLink("Request callback").click()
        self.assertMatches('...Valid callback received...',
                          self.browser.contents)

        # Callback can't be applied twice
        self.browser.open(payment_url + '/simulate_callback')
        self.assertMatches('...This ticket has already been paid...',
                          self.browser.contents)

        # Now the first ticket is paid and no more ticket of same type
        # (with same p_item, p_session and p_category) can be added
        self.browser.open(self.payments_path)
        self.browser.getControl("Add online payment ticket").click()
        self.browser.getControl(name="form.p_category").value = ['schoolfee']
        self.browser.getControl("Create ticket").click()
        self.assertMatches(
            '...This type of payment has already been made...',
            self.browser.contents)

        # Managers can open the pdf payment slip
        self.browser.open(payment_url)
        self.browser.getLink("Download payment slip").click()
        self.assertEqual(self.browser.headers['Status'], '200 Ok')
        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')

        # Managers can remove online school fee payment tickets
        self.browser.open(self.payments_path)
        self.browser.getControl("Remove selected").click()
        self.assertMatches('...No payment selected...', self.browser.contents)
        ctrl = self.browser.getControl(name='val_id')
        value = ctrl.options[0]
        ctrl.getControl(value=value).selected = True
        self.browser.getControl("Remove selected", index=0).click()
        self.assertTrue('Successfully removed' in self.browser.contents)

        # Managers can add online clearance payment tickets
        self.browser.open(self.payments_path + '/addop')
        self.browser.getControl(name="form.p_category").value = ['clearance']
        self.browser.getControl("Create ticket").click()
        self.assertMatches('...ticket created...',
                           self.browser.contents)

        # Managers can open the callback view which simulates a valid callback
        self.assertEqual(len(self.app['accesscodes']['CLR-0']),0)
        ctrl = self.browser.getControl(name='val_id')
        value = ctrl.options[1] # The clearance payment is the second in the table
        self.browser.getLink(value).click()
        self.browser.open(self.browser.url + '/simulate_callback')
        self.assertMatches('...Valid callback received...',
                          self.browser.contents)
        expected = '''...
        <td>
          <span>Paid</span>
        </td>...'''
        self.assertMatches(expected,self.browser.contents)
        # The new CLR-0 pin has been created
        self.assertEqual(len(self.app['accesscodes']['CLR-0']),1)
        pin = self.app['accesscodes']['CLR-0'].keys()[0]
        ac = self.app['accesscodes']['CLR-0'][pin]
        ac.owner = self.student_id
        return

    def test_student_payments(self):
        # Login
        self.browser.open(self.login_path)
        self.browser.getControl(name="form.login").value = self.student_id
        self.browser.getControl(name="form.password").value = 'spwd'
        self.browser.getControl("Login").click()

        # Students can add online clearance payment tickets
        self.browser.open(self.payments_path + '/addop')
        self.browser.getControl(name="form.p_category").value = ['clearance']
        self.browser.getControl("Create ticket").click()
        self.assertMatches('...ticket created...',
                           self.browser.contents)

        # Students can open the callback view which simulates a valid callback
        self.assertEqual(len(self.app['accesscodes']['CLR-0']),0)
        ctrl = self.browser.getControl(name='val_id')
        value = ctrl.options[0]
        self.browser.getLink(value).click()
        payment_url = self.browser.url
        self.browser.open(payment_url + '/simulate_callback')
        self.assertMatches('...Valid callback received...',
                          self.browser.contents)
        expected = '''...
        <td>
          <span>Paid</span>
        </td>...'''
        self.assertMatches(expected,self.browser.contents)
        # The new CLR-0 pin has been created
        self.assertEqual(len(self.app['accesscodes']['CLR-0']),1)
        pin = self.app['accesscodes']['CLR-0'].keys()[0]
        ac = self.app['accesscodes']['CLR-0'][pin]
        ac.owner = self.student_id

        # Students can open the pdf payment slip
        self.browser.open(payment_url + '/payment_slip.pdf')
        self.assertEqual(self.browser.headers['Status'], '200 Ok')
        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')

        # The new CLR-0 pin can be used for starting clearance
        # but they have to upload a passport picture first
        # which is only possible in state admitted
        self.browser.open(self.student_path + '/change_portrait')
        self.assertMatches('...form is locked...',
                          self.browser.contents)
        IWorkflowInfo(self.student).fireTransition('admit')
        self.browser.open(self.student_path + '/change_portrait')
        pseudo_image = StringIO('I pretend to be a graphics file')
        ctrl = self.browser.getControl(name='passportuploadedit')
        file_ctrl = ctrl.mech_control
        file_ctrl.add_file(pseudo_image, filename='my_photo.jpg')
        self.browser.getControl(
            name='upload_passportuploadedit').click()
        self.browser.open(self.student_path + '/start_clearance')
        parts = pin.split('-')[1:]
        clrseries, clrnumber = parts
        self.browser.getControl(name="ac_series").value = clrseries
        self.browser.getControl(name="ac_number").value = clrnumber
        self.browser.getControl("Start clearance now").click()
        self.assertMatches('...Clearance process has been started...',
                           self.browser.contents)

        # Students can add online school fee payment tickets
        self.browser.open(self.payments_path)
        self.browser.getControl("Add online payment ticket").click()
        self.browser.getControl(name="form.p_category").value = ['schoolfee']
        self.browser.getControl("Create ticket").click()
        self.assertMatches('...ticket created...',
                           self.browser.contents)
        ctrl = self.browser.getControl(name='val_id')
        value = ctrl.options[0]
        self.browser.getLink(value).click()
        self.assertMatches('...Amount Authorized...',
                           self.browser.contents)
        # Payment session and level have been calculated as defined
        # in w.k.students.utils
        self.assertEqual(self.student['payments'][value].p_session, 2005)
        self.assertEqual(self.student['payments'][value].p_level, 200)

        # Students can open the callback view which simulates a valid callback
        self.assertEqual(len(self.app['accesscodes']['SFE-0']),0)
        self.browser.open(self.browser.url + '/simulate_callback')
        self.assertMatches('...Valid callback received...',
                          self.browser.contents)

        # Students can remove only online payment tickets which have
        # not received a valid callback
        self.browser.open(self.payments_path)
        self.assertRaises(
            LookupError, self.browser.getControl, name='val_id')
        self.browser.open(self.payments_path + '/addop')
        self.browser.getControl(name="form.p_category").value = ['gown']
        self.browser.getControl("Create ticket").click()
        self.browser.open(self.payments_path)
        ctrl = self.browser.getControl(name='val_id')
        value = ctrl.options[0]
        ctrl.getControl(value=value).selected = True
        self.browser.getControl("Remove selected", index=0).click()
        self.assertTrue('Successfully removed' in self.browser.contents)

        # The new SFE-0 pin can be used for starting course registration
        IWorkflowInfo(self.student).fireTransition('request_clearance')
        IWorkflowInfo(self.student).fireTransition('clear')
        self.browser.open(self.studycourse_path)
        self.browser.getLink('Start course registration').click()
        pin = self.app['accesscodes']['SFE-0'].keys()[0]
        parts = pin.split('-')[1:]
        sfeseries, sfenumber = parts
        self.browser.getControl(name="ac_series").value = sfeseries
        self.browser.getControl(name="ac_number").value = sfenumber
        self.browser.getControl("Start course registration now").click()
        self.assertMatches('...Course registration has been started...',
                           self.browser.contents)
        self.assertTrue(self.student.state == 'school fee paid')
        return

    def test_manage_accommodation(self):
        # Managers can add online booking fee payment tickets and open the
        # callback view (see test_manage_payments)
        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
        self.browser.open(self.payments_path)
        self.browser.getControl("Add online payment ticket").click()
        self.browser.getControl(name="form.p_category").value = ['bed_allocation']
        # If student is not in accommodation session, payment cannot be processed
        self.app['configuration'].accommodation_session = 2011
        self.browser.getControl("Create ticket").click()
        self.assertMatches('...Your current session does not match...',
                           self.browser.contents)
        self.app['configuration'].accommodation_session = 2004
        self.browser.getControl("Add online payment ticket").click()
        self.browser.getControl(name="form.p_category").value = ['bed_allocation']
        self.browser.getControl("Create ticket").click()
        ctrl = self.browser.getControl(name='val_id')
        value = ctrl.options[0]
        self.browser.getLink(value).click()
        self.browser.open(self.browser.url + '/simulate_callback')
        # The new HOS-0 pin has been created
        self.assertEqual(len(self.app['accesscodes']['HOS-0']),1)
        pin = self.app['accesscodes']['HOS-0'].keys()[0]
        ac = self.app['accesscodes']['HOS-0'][pin]
        ac.owner = self.student_id
        parts = pin.split('-')[1:]
        sfeseries, sfenumber = parts
        # Managers can use HOS code and book a bed space with it
        self.browser.open(self.acco_path)
        self.browser.getLink("Book accommodation").click()
        self.assertMatches('...You are in the wrong...',
                           self.browser.contents)
        IWorkflowInfo(self.student).fireTransition('admit')
        # An existing HOS code can only be used if students
        # are in accommodation session
        self.student['studycourse'].current_session = 2003
        self.browser.getLink("Book accommodation").click()
        self.assertMatches('...Your current session does not match...',
                           self.browser.contents)
        self.student['studycourse'].current_session = 2004
        # All requirements are met and ticket can be created
        self.browser.getLink("Book accommodation").click()
        self.assertMatches('...Activation Code:...',
                           self.browser.contents)
        self.browser.getControl(name="ac_series").value = sfeseries
        self.browser.getControl(name="ac_number").value = sfenumber
        self.browser.getControl("Create bed ticket").click()
        self.assertMatches('...Hall 1, Block A, Room 101, Bed A...',
                           self.browser.contents)
        # Bed has been allocated
        bed1 = self.app['hostels']['hall-1']['hall-1_A_101_A']
        self.assertTrue(bed1.owner == self.student_id)
        # BedTicketAddPage is now blocked
        self.browser.getLink("Book accommodation").click()
        self.assertMatches('...You already booked a bed space...',
            self.browser.contents)
        # The bed ticket displays the data correctly
        self.browser.open(self.acco_path + '/2004')
        self.assertMatches('...Hall 1, Block A, Room 101, Bed A...',
                           self.browser.contents)
        self.assertMatches('...2004/2005...', self.browser.contents)
        self.assertMatches('...regular_male_fr...', self.browser.contents)
        self.assertMatches('...%s...' % pin, self.browser.contents)
        # Managers can relocate students if the student's bed_type has changed
        self.browser.getLink("Relocate student").click()
        self.assertMatches(
            "...Student can't be relocated...", self.browser.contents)
        self.student.sex = u'f'
        self.browser.getLink("Relocate student").click()
        self.assertMatches(
            "...Hall 1, Block A, Room 101, Bed B...", self.browser.contents)
        self.assertTrue(bed1.owner == NOT_OCCUPIED)
        bed2 = self.app['hostels']['hall-1']['hall-1_A_101_B']
        self.assertTrue(bed2.owner == self.student_id)
        self.assertTrue(self.student['accommodation'][
            '2004'].bed_type == u'regular_female_fr')
        # The payment object still shows the original payment item
        payment_id = self.student['payments'].keys()[0]
        payment = self.student['payments'][payment_id]
        self.assertTrue(payment.p_item == u'regular_male_fr')
        # Managers can relocate students if the bed's bed_type has changed
        bed1.bed_type = u'regular_female_fr'
        bed2.bed_type = u'regular_male_fr'
        notify(grok.ObjectModifiedEvent(bed1))
        notify(grok.ObjectModifiedEvent(bed2))
        self.browser.getLink("Relocate student").click()
        self.assertMatches(
            "...Student relocated...", self.browser.contents)
        self.assertMatches(
            "... Hall 1, Block A, Room 101, Bed A...", self.browser.contents)
        self.assertMatches(bed1.owner, self.student_id)
        self.assertMatches(bed2.owner, NOT_OCCUPIED)
        # Managers can't relocate students if bed is reserved
        self.student.sex = u'm'
        bed1.bed_type = u'regular_female_reserved'
        notify(grok.ObjectModifiedEvent(bed1))
        self.browser.getLink("Relocate student").click()
        self.assertMatches(
            "...Students in reserved beds can't be relocated...",
            self.browser.contents)
        # Managers can relocate students if booking has been cancelled but
        # other bed space has been manually allocated after cancellation
        old_owner = bed1.releaseBed()
        self.assertMatches(old_owner, self.student_id)
        bed2.owner = self.student_id
        self.browser.open(self.acco_path + '/2004')
        self.assertMatches(
            "...booking cancelled...", self.browser.contents)
        self.browser.getLink("Relocate student").click()
        # We didn't informed the catalog therefore the new owner is not found
        self.assertMatches(
            "...There is no free bed in your category regular_male_fr...",
            self.browser.contents)
        # Now we fire the event properly
        notify(grok.ObjectModifiedEvent(bed2))
        self.browser.getLink("Relocate student").click()
        self.assertMatches(
            "...Student relocated...", self.browser.contents)
        self.assertMatches(
            "... Hall 1, Block A, Room 101, Bed B...", self.browser.contents)
          # Managers can delete bed tickets
        self.browser.open(self.acco_path)
        ctrl = self.browser.getControl(name='val_id')
        value = ctrl.options[0]
        ctrl.getControl(value=value).selected = True
        self.browser.getControl("Remove selected", index=0).click()
        self.assertMatches('...Successfully removed...', self.browser.contents)
        # The bed has been properly released by the event handler
        self.assertMatches(bed1.owner, NOT_OCCUPIED)
        self.assertMatches(bed2.owner, NOT_OCCUPIED)
        return

    def test_student_accommodation(self):
        # Login
        self.browser.open(self.login_path)
        self.browser.getControl(name="form.login").value = self.student_id
        self.browser.getControl(name="form.password").value = 'spwd'
        self.browser.getControl("Login").click()

        # Students can add online booking fee payment tickets and open the
        # callback view (see test_manage_payments)
        self.browser.getLink("Payments").click()
        self.browser.getControl("Add online payment ticket").click()
        self.browser.getControl(name="form.p_category").value = ['bed_allocation']
        self.browser.getControl("Create ticket").click()
        ctrl = self.browser.getControl(name='val_id')
        value = ctrl.options[0]
        self.browser.getLink(value).click()
        self.browser.open(self.browser.url + '/simulate_callback')
        # The new HOS-0 pin has been created
        self.assertEqual(len(self.app['accesscodes']['HOS-0']),1)
        pin = self.app['accesscodes']['HOS-0'].keys()[0]
        ac = self.app['accesscodes']['HOS-0'][pin]
        ac.owner = u'Anybody'
        parts = pin.split('-')[1:]
        sfeseries, sfenumber = parts

        # Students can use HOS code and book a bed space with it
        self.browser.open(self.acco_path)
        self.browser.getLink("Book accommodation").click()
        self.assertMatches('...You are in the wrong...',
                           self.browser.contents)
        IWorkflowInfo(self.student).fireTransition('admit')
        self.browser.getLink("Book accommodation").click()
        self.assertMatches('...Activation Code:...',
                           self.browser.contents)
        self.browser.getControl(name="ac_series").value = u'nonsense'
        self.browser.getControl(name="ac_number").value = sfenumber
        self.browser.getControl("Create bed ticket").click()
        self.assertMatches('...Activation code is invalid...',
                           self.browser.contents)
        self.browser.getControl(name="ac_series").value = sfeseries
        self.browser.getControl(name="ac_number").value = sfenumber
        self.browser.getControl("Create bed ticket").click()
        self.assertMatches('...You are not the owner of this access code...',
                           self.browser.contents)
        ac.owner = self.student_id
        self.browser.getControl(name="ac_series").value = sfeseries
        self.browser.getControl(name="ac_number").value = sfenumber
        self.browser.getControl("Create bed ticket").click()
        self.assertMatches('...Hall 1, Block A, Room 101, Bed A...',
                           self.browser.contents)

        # Bed has been allocated
        bed = self.app['hostels']['hall-1']['hall-1_A_101_A']
        self.assertTrue(bed.owner == self.student_id)

        # BedTicketAddPage is now blocked
        self.browser.getLink("Book accommodation").click()
        self.assertMatches('...You already booked a bed space...',
            self.browser.contents)

        # The bed ticket displays the data correctly
        self.browser.open(self.acco_path + '/2004')
        self.assertMatches('...Hall 1, Block A, Room 101, Bed A...',
                           self.browser.contents)
        self.assertMatches('...2004/2005...', self.browser.contents)
        self.assertMatches('...regular_male_fr...', self.browser.contents)
        self.assertMatches('...%s...' % pin, self.browser.contents)

        # Students can open the pdf slip
        self.browser.open(self.browser.url + '/bed_allocation.pdf')
        self.assertEqual(self.browser.headers['Status'], '200 Ok')
        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')

        # Students can't relocate themselves
        self.assertFalse('Relocate' in self.browser.contents)
        relocate_path = self.acco_path + '/2004/relocate'
        self.assertRaises(
            Unauthorized, self.browser.open, relocate_path)

        # Students can't the Remove button and check boxes
        self.browser.open(self.acco_path)
        self.assertFalse('Remove' in self.browser.contents)
        self.assertFalse('val_id' in self.browser.contents)
        return

    def test_change_password_request(self):
        self.browser.open('http://localhost/app/sendpw')
        self.browser.getControl(name="form.reg_number").value = '123'
        self.browser.getControl(name="form.email").value = 'aa@aa.ng'
        self.browser.getControl("Get new login credentials").click()
        self.assertTrue('An email with' in self.browser.contents)

    def test_reindex(self):
        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
        self.browser.open('http://localhost/app/reindex')
        self.assertTrue('No catalog name provided' in self.browser.contents)
        self.browser.open('http://localhost/app/reindex?ctlg=xyz')
        self.assertTrue('xyz_catalog does not exist' in self.browser.contents)
        cat = queryUtility(ICatalog, name='students_catalog')
        results = cat.searchResults(student_id=(None, None))
        self.assertEqual(len(results),1)
        cat.clear()
        results = cat.searchResults(student_id=(None, None))
        self.assertEqual(len(results),0)
        self.browser.open('http://localhost/app/reindex?ctlg=students')
        self.assertTrue('1 students re-indexed' in self.browser.contents)
        results = cat.searchResults(student_id=(None, None))
        self.assertEqual(len(results),1)

    def test_change_current_mode(self):
        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
        self.browser.open(self.clearance_path)
        self.assertFalse('Employer' in self.browser.contents)
        self.browser.open(self.manage_clearance_path)
        self.assertFalse('Employer' in self.browser.contents)
        self.student.clearance_locked = False
        self.browser.open(self.edit_clearance_path)
        self.assertFalse('Employer' in self.browser.contents)
        # Now we change the study mode of the certificate and a different
        # interface is used by clearance views
        self.certificate.study_mode = 'pg_ft'
        self.browser.open(self.clearance_path)
        self.assertTrue('Employer' in self.browser.contents)
        self.browser.open(self.manage_clearance_path)
        self.assertTrue('Employer' in self.browser.contents)
        self.browser.open(self.edit_clearance_path)
        self.assertTrue('Employer' in self.browser.contents)