# -*- coding: utf-8 -*-
## $Id: test_browser.py 16030 2020-03-06 21:20:29Z 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
import pytz
import base64
from datetime import datetime, timedelta, date
from StringIO import StringIO
import os
import grok
from zc.async.testing import wait_for_result
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 zope.interface import implementedBy
from zope.schema.fieldproperty import FieldProperty
from hurry.workflow.interfaces import IWorkflowInfo, IWorkflowState
from waeup.kofa.testing import FunctionalLayer, FunctionalTestCase
from waeup.kofa.app import University
from waeup.kofa.interfaces import IFileStoreNameChooser, IExtFileStore
from waeup.kofa.payments.interfaces import IPayer
from waeup.kofa.students.payments import StudentOnlinePayment
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, IJobManager, VALIDATED, CREATED
from waeup.kofa.authentication import LocalRoleSetEvent
from waeup.kofa.hostels.hostel import Hostel, Bed, NOT_OCCUPIED
from waeup.kofa.tests.test_async import FunctionalAsyncTestCase
from waeup.kofa.browser.tests.test_pdf import samples_dir
from waeup.kofa.tests.test_authentication import SECRET
PH_LEN = 15911 # Length of placeholder file
SAMPLE_IMAGE = os.path.join(os.path.dirname(__file__), 'test_image.jpg')
SAMPLE_IMAGE_BMP = os.path.join(os.path.dirname(__file__), 'test_image.bmp')
URL_LECTURER_LANDING = 'http://localhost/app/my_courses'
curr_year = datetime.now().year
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'
student.date_of_birth = date(1981, 2, 4)
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.trigtrans_path = self.student_path + '/trigtrans'
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.manage_personal_path = self.student_path + '/manage_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.certificate.school_fee_1 = 40000.0
self.certificate.school_fee_2 = 20000.0
self.app['faculties']['fac1'] = Faculty(code=u'fac1')
self.app['faculties']['fac1']['dep1'] = Department(code=u'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'].addCertCourse(self.course, level=100)
# Configure university and hostels
self.app['hostels'].accommodation_states = ['admitted']
self.app['hostels'].accommodation_session = 2004
delta = timedelta(days=10)
self.app['hostels'].startdate = datetime.now(pytz.utc) - delta
self.app['hostels'].enddate = datetime.now(pytz.utc) + delta
self.app['configuration'].carry_over = True
configuration = createObject('waeup.SessionConfiguration')
configuration.academic_session = 2004
configuration.clearance_fee = 3456.0
configuration.transcript_fee = 4567.0
configuration.booking_fee = 123.4
configuration.maint_fee = 987.0
configuration.transfer_fee = 456.0
configuration.late_registration_fee = 345.0
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'
hostel.maint_fee = 876.0
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 students 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 = '123'
self.browser.getControl("Create student").click()
self.assertTrue(
'Registration number exists already' in self.browser.contents)
self.browser.getControl(name="form.reg_number").value = '1234'
self.browser.getControl("Create student").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("Find student(s)").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("Find student(s)").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("Find student(s)").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("Find student(s)").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("Find student(s)").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("Find student(s)").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("Find student(s)").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("Find student(s)").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("Find student(s)").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("Find student(s)").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("Find student(s)").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("Find student(s)").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("Find student(s)").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("Find student(s)").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("Find student(s)").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("Find student(s)").click()
self.assertTrue('Anna Tester' in self.browser.contents)
# The old searchterm will be used again
self.browser.getControl("Find student(s)").click()
self.assertTrue('Anna Tester' in self.browser.contents)
# We can find suspended students
self.student.suspended = True
notify(grok.ObjectModifiedEvent(self.student))
self.browser.open(self.manage_container_path)
self.browser.getControl(name="searchtype").value = ['suspended']
self.browser.getControl("Find student(s)").click()
self.assertTrue('Anna Tester' in self.browser.contents)
self.browser.open(self.container_path)
self.browser.getControl(name="searchtype").value = ['suspended']
self.browser.getControl("Find student(s)").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("Find student(s)").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("Find student(s)").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("Find student(s)").click()
self.assertTrue('No student found' in self.browser.contents)
return
def test_add_graduated_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 graduated student").click()
self.assertTrue('Graduated student record created' in self.browser.contents)
self.assertEqual(self.app['students']['K1000001'].state, 'graduated')
self.browser.open("http://localhost/app/students/K1000001/history")
self.assertTrue("State 'graduated' set by Manager" in self.browser.contents)
return
class OfficerUITests(StudentsFullSetup):
# Tests for Student class views and pages
def test_student_properties(self):
self.student['studycourse'].current_level = 100
self.assertEqual(self.student.current_level, 100)
self.student['studycourse'].current_session = 2011
self.assertEqual(self.student.current_session, 2011)
self.student['studycourse'].current_verdict = 'A'
self.assertEqual(self.student.current_verdict, 'A')
return
def test_studylevelmanagepage(self):
studylevel = StudentStudyLevel()
studylevel.level = 100
cert = self.app['faculties']['fac1']['dep1'].certificates['CERT1']
self.student['studycourse'].addStudentStudyLevel(cert, studylevel)
self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
self.browser.open(self.studycourse_path + '/100/manage')
self.assertEqual(
self.browser.url, self.studycourse_path + '/100/manage')
self.assertEqual(self.browser.headers['Status'], '200 Ok')
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_basic_auth_base64(self):
auth_token = base64.b64encode('mgr:mgrpw')
self.browser.addHeader('Authorization', 'Basic %s' % auth_token)
self.browser.open(self.manage_container_path)
self.assertEqual(self.browser.headers['Status'], '200 Ok')
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("Trigger").click()
self.assertEqual(self.browser.headers['Status'], '200 Ok')
# Managers can trigger transitions
self.browser.getControl(name="transition").value = ['admit']
self.browser.getControl("Save").click()
# Managers can edit base
self.browser.open(self.student_path)
self.browser.getLink("Manage").click()
self.assertEqual(self.browser.url, self.manage_student_path)
self.assertEqual(self.browser.headers['Status'], '200 Ok')
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("Manage").click()
self.assertEqual(self.browser.headers['Status'], '200 Ok')
self.assertEqual(self.browser.url, self.manage_personal_path)
self.browser.open(self.personal_path)
self.assertTrue('Updated' in self.browser.contents)
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()
# perm_address is required in IStudentPersonalEdit
self.assertMatches('...Required input is missing...',
self.browser.contents)
self.browser.getControl(name="form.perm_address").value = 'My address!'
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')
# We have been redirected to the manage page
self.assertEqual(self.browser.url, self.acco_path + '/manage')
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('...Admitted by Manager...',
self.browser.contents)
# Only the Application Slip does not exist
self.assertFalse('Application Slip' in self.browser.contents)
return
def test_flash_notice(self):
self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
self.browser.open(self.student_path)
self.assertFalse('alert alert-warning' in self.browser.contents)
self.student.flash_notice = u'Happy Birthday!'
self.browser.open(self.student_path)
self.assertTrue(
'
Happy Birthday!
'
in self.browser.contents)
return
def test_manage_contact_student(self):
# Managers can contact student
self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
# Remove required FieldProperty attribute first ...
delattr(Student, 'email')
# ... and replace by None
self.student.email = None
# Now we have to add the FieldProperty attribute again. Otherwise
# many other tests below will fail.
iface = list(implementedBy(Student))[0]
field_property = FieldProperty(iface['email'])
setattr(Student, 'email', field_property)
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(
'An smtp server error occurred' in self.browser.contents)
self.student.email = 'xx@yy.zz'
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('...
...'''
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]
self.assertEqual(ac.owner, self.student_id)
self.assertEqual(ac.cost, 3456.0)
# Managers can add online transcript payment tickets
self.browser.open(self.payments_path + '/addop')
self.browser.getControl(name="form.p_category").value = ['transcript']
self.browser.getControl("Create ticket").click()
self.assertMatches('...ticket created...',
self.browser.contents)
# Managers can approve the payment
self.assertEqual(len(self.app['accesscodes']['TSC-0']),0)
ctrl = self.browser.getControl(name='val_id')
value = ctrl.options[2] # The clearance payment is the third in the table
self.browser.getLink(value).click()
self.browser.open(self.browser.url + '/approve')
self.assertMatches('...Payment approved...',
self.browser.contents)
expected = '''...
Paid
...'''
self.assertMatches(expected,self.browser.contents)
# The new CLR-0 pin has been created
self.assertEqual(len(self.app['accesscodes']['TSC-0']),1)
pin = self.app['accesscodes']['TSC-0'].keys()[0]
ac = self.app['accesscodes']['TSC-0'][pin]
self.assertEqual(ac.owner, self.student_id)
self.assertEqual(ac.cost, 4567.0)
return
def test_add_transfer_payment(self):
self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
self.browser.open(self.payments_path)
self.browser.getLink("Add current session payment ticket").click()
self.browser.getControl(name="form.p_category").value = ['transfer']
self.browser.getControl(name="new_programme").value = 'my new study course'
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('...my new study course...',
self.browser.contents)
self.assertEqual(self.student['payments'][value].p_item, u'my new study course')
def test_manage_payments_bypass_ac_creation(self):
self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
self.browser.open(self.payments_path)
IWorkflowState(self.student).setState('cleared')
self.browser.getLink("Add current session payment ticket").click()
self.browser.getControl(name="form.p_category").value = ['schoolfee']
self.browser.getControl("Create ticket").click()
ctrl = self.browser.getControl(name='val_id')
value = ctrl.options[0]
self.browser.getLink(value).click()
payment_url = self.browser.url
logfile = os.path.join(
self.app['datacenter'].storage, 'logs', 'students.log')
# The ticket can be found in the payments_catalog
cat = queryUtility(ICatalog, name='payments_catalog')
results = list(cat.searchResults(p_state=('unpaid', 'unpaid')))
self.assertTrue(len(results), 1)
self.assertTrue(results[0] is self.student['payments'][value])
# Managers can approve the payment
self.browser.open(payment_url)
self.browser.getLink("Approve payment").click()
self.assertMatches('...Payment approved...',
self.browser.contents)
# Approval is logged in students.log ...
logcontent = open(logfile).read()
self.assertTrue(
'zope.mgr - students.browser.OnlinePaymentApproveView '
'- K1000000 - schoolfee payment approved'
in logcontent)
# ... and in payments.log
logfile = os.path.join(
self.app['datacenter'].storage, 'logs', 'payments.log')
logcontent = open(logfile).read()
self.assertTrue(
'"zope.mgr",K1000000,%s,schoolfee,40000.0,AP,,,,,,\n' % value
in logcontent)
# Student is in state school fee paid, no activation
# code was necessary.
self.assertEqual(self.student.state, 'school fee paid')
self.assertEqual(len(self.app['accesscodes']['SFE-0']),0)
return
def test_payment_disabled(self):
self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
self.browser.open(self.payments_path)
IWorkflowState(self.student).setState('cleared')
self.browser.getLink("Add current session 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)
self.app['configuration']['2004'].payment_disabled = ['sf_all']
self.browser.getLink("Add current session payment ticket").click()
self.browser.getControl(name="form.p_category").value = ['schoolfee']
self.browser.getControl("Create ticket").click()
self.assertMatches('...This category of payments has been disabled...',
self.browser.contents)
return
def test_manage_balance_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()
self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
self.browser.open(self.payments_path)
# Managers can add balance school fee payment tickets in any state.
IWorkflowState(self.student).setState('courses registered')
self.browser.open(self.payments_path)
self.browser.getLink("Add balance payment ticket").click()
# Balance payment form is provided
self.assertEqual(self.student.current_session, 2004)
self.browser.getControl(name="form.p_category").value = ['schoolfee']
self.browser.getControl(name="form.balance_session").value = ['2004']
self.browser.getControl(name="form.balance_level").value = ['300']
self.browser.getControl(name="form.balance_amount").value = '-567.8'
self.browser.getControl("Create ticket").click()
self.assertMatches('...Amount must be greater than 0...',
self.browser.contents)
self.browser.getControl(name="form.balance_amount").value = '0'
self.browser.getControl("Create ticket").click()
self.assertMatches('...Amount must be greater than 0...',
self.browser.contents)
self.browser.getControl(name="form.balance_amount").value = '567.8'
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)
self.assertEqual(self.student['payments'][value].amount_auth, 567.8)
# Payment attributes are properly set
self.assertEqual(self.student['payments'][value].p_session, 2004)
self.assertEqual(self.student['payments'][value].p_level, 300)
self.assertEqual(self.student['payments'][value].p_item, u'Balance')
self.assertEqual(self.student['payments'][value].p_category, 'schoolfee')
# Adding payment tickets is logged.
logfile = os.path.join(
self.app['datacenter'].storage, 'logs', 'students.log')
logcontent = open(logfile).read()
self.assertTrue('zope.mgr - students.browser.BalancePaymentAddFormPage '
'- K1000000 - added: %s' % value in logcontent)
def test_manage_accommodation(self):
logfile = os.path.join(
self.app['datacenter'].storage, 'logs', 'students.log')
# 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.getLink("Add current session 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['hostels'].accommodation_session = 2011
self.browser.getControl("Create ticket").click()
self.assertMatches('...Your current session does not match...',
self.browser.contents)
self.app['hostels'].accommodation_session = 2004
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 + '/approve')
# 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]
self.assertEqual(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.getControl("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.getControl("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.getControl("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.getControl("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)
# Booking is properly logged
logcontent = open(logfile).read()
self.assertTrue('zope.mgr - students.browser.BedTicketAddPage '
'- K1000000 - booked: hall-1_A_101_A' in logcontent)
# 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')
# Relocation is properly logged
logcontent = open(logfile).read()
self.assertTrue('zope.mgr - students.accommodation.BedTicket '
'- K1000000 - relocated: hall-1_A_101_B' in logcontent)
# 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_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.trigtrans_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()
# Managers approve payment, they do not pay
self.assertFalse('pay_first_school_fee' in self.browser.contents)
self.browser.getControl(
name="transition").value = ['approve_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 = ['approve_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 = Zero = 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_pg_workflow(self):
# Managers can pass through the whole workflow
IWorkflowState(self.student).setState('school fee paid')
self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
self.browser.open(self.trigtrans_path)
self.assertTrue(''
in self.browser.contents)
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()
self.browser.getControl(name="form.current_level").value = ['100']
self.browser.getControl("Save").click()
self.browser.getControl(name="addlevel").value = ['100']
self.browser.getControl(name="level_session").value = ['2004']
self.browser.getControl("Add study level").click()
self.browser.getLink("100").click()
self.browser.getLink("Manage").click()
self.browser.getControl(name="form.level_session").value = ['2002']
self.browser.getControl("Save").click()
self.browser.getLink("COURSE1").click()
self.browser.getLink("Manage").click()
self.browser.getControl("Save").click()
self.assertTrue('Form has been saved' in self.browser.contents)
# Officer can edit transcript remarks and validate the transcript
self.browser.open(self.studycourse_path + '/transcript')
self.browser.getLink("Validate transcript").click()
self.browser.getLink("Edit").click()
self.assertEqual(
self.browser.url, self.studycourse_path + '/100/remark')
self.browser.getControl(
name="form.transcript_remark").value = 'Oh, the student failed'
self.browser.getControl(
"Save remark and go and back to transcript validation page").click()
self.assertEqual(
self.browser.url,
self.studycourse_path + '/validate_transcript#tab4')
self.assertEqual(self.student['studycourse']['100'].transcript_remark,
'Oh, the student failed')
self.browser.getControl("Save comment and validate transcript").click()
# After validation all manage forms are locked.
self.browser.open(self.studycourse_path + '/manage')
self.assertTrue('The requested form is locked' in self.browser.contents)
self.assertFalse('Undergraduate Full-Time'
in self.browser.contents)
self.browser.open(self.studycourse_path + '/100/manage')
self.assertTrue('The requested form is locked' in self.browser.contents)
self.browser.open(self.studycourse_path + '/100/COURSE1/manage')
self.assertTrue('The requested form is locked' in self.browser.contents)
self.browser.open(self.studycourse_path + '/100/remark')
self.assertTrue('The requested form is locked' in self.browser.contents)
# Transcript can be signed if officer has the permission to sign
#self.browser.open(self.studycourse_path + '/transcript')
#self.assertFalse('Sign transcript' in self.browser.contents)
#prmglobal = IPrincipalRoleManager(self.app)
#prmglobal.assignRoleToPrincipal('waeup.TranscriptSignee', 'mrtranscript')
self.browser.open(self.studycourse_path + '/transcript')
self.browser.getLink("Sign transcript electronically").click()
# Transcript signing has been logged ...
logfile = os.path.join(
self.app['datacenter'].storage, 'logs', 'students.log')
logcontent = open(logfile).read()
self.assertTrue(
'mrtranscript - students.browser.StudentTranscriptSignView - '
'K1000000 - Transcript signed' in logcontent)
# ... appears in the student's history ...
self.browser.open(self.history_path)
self.assertTrue('Transcript signed by Ruth Gordon'
in self.browser.contents)
# ... and is also stored in the transcript_signee attribute.
self.assertTrue(
u'Electronically signed by Ruth Gordon (mrtranscript) on '
in self.student['studycourse'].transcript_signees)
# Officer can release the transcript
self.browser.open(self.studycourse_path + '/transcript')
self.browser.getLink("Release transcript").click()
self.assertTrue(' UTC K1000000 wrote:
Comment line 1 '
'Comment line2
Dispatch Address: Address line 1 '
'Address line2
' in self.browser.contents)
self.browser.getControl(name="comment").value = (
'Hello,\nYour transcript has been sent to the address provided.')
self.browser.getControl("Save comment and release transcript").click()
self.assertTrue(
'UTC mrtranscript wrote:\n\nHello,\nYour transcript has '
'been sent to the address provided.\n\n'
in self.student['studycourse'].transcript_comment)
# The comment has been logged
logfile = os.path.join(
self.app['datacenter'].storage, 'logs', 'students.log')
logcontent = open(logfile).read()
self.assertTrue(
'mrtranscript - students.browser.StudentTranscriptReleaseFormPage - '
'K1000000 - comment: Hello, '
'Your transcript has been sent to the address provided'
in logcontent)
# File has been stored in the file system
# Check if transcript exists in the file system and is a PDF file
storage = getUtility(IExtFileStore)
file_id = IFileStoreNameChooser(
self.student).chooseName(attr='final_transcript.pdf')
pdf = storage.getFile(file_id).read()
self.assertTrue(len(pdf) > 0)
self.assertEqual(pdf[:8], '%PDF-1.4')
# Copy the file to samples_dir
path = os.path.join(samples_dir(), 'final_transcript.pdf')
open(path, 'wb').write(pdf)
print "Sample PDF final_transcript.pdf written to %s" % path
# Check if there is an transcript pdf link in UI
self.browser.open(self.student_path)
self.assertTrue('Final Transcript' in self.browser.contents)
self.browser.getLink("Final Transcript").click()
self.assertEqual(self.browser.headers['Status'], '200 Ok')
self.assertEqual(self.browser.headers['Content-Type'],
'application/pdf')
# Transcript views are no longer accessible
self.browser.open(self.studycourse_path)
self.assertFalse('studycourse/transcript' in self.browser.contents)
self.browser.open(self.studycourse_path + '/transcript')
self.assertTrue('Forbidden!' in self.browser.contents)
self.browser.open(self.studycourse_path + '/transcript.pdf')
self.assertTrue('Forbidden!' in self.browser.contents)
# If we reset the transcript process
# (can't be done by transcript officer), the file will be deleted
IWorkflowInfo(self.student).fireTransition('reset11')
self.browser.open(self.student_path)
self.assertFalse('Final Transcript' in self.browser.contents)
# ... and transcript process information has been removed
self.assertEqual(self.student['studycourse'].transcript_comment, None)
self.assertEqual(self.student['studycourse'].transcript_signees, None)
def test_landingpage_transcript_officer(self):
IWorkflowState(self.student).setState('transcript requested')
notify(grok.ObjectModifiedEvent(self.student))
# Create transcript officer
self.app['users'].addUser('mrtranscript', SECRET)
self.app['users']['mrtranscript'].email = 'mrtranscript@foo.ng'
self.app['users']['mrtranscript'].title = 'Ruth Gordon'
# We assign transcript officer role at faculty level
fac = self.app['faculties']['fac1']
prmlocal = IPrincipalRoleManager(fac)
prmlocal.assignRoleToPrincipal(
'waeup.local.TranscriptOfficer', 'mrtranscript')
notify(LocalRoleSetEvent(
fac, 'waeup.local.TranscriptOfficer', 'mrtranscript', granted=True))
# Login as transcript officer
self.browser.open(self.login_path)
self.browser.getControl(name="form.login").value = 'mrtranscript'
self.browser.getControl(name="form.password").value = SECRET
self.browser.getControl("Login").click()
self.assertMatches('...You logged in...', self.browser.contents)
# Officer is on landing page and does see the transcript link
self.assertTrue(
'http://localhost/app/students/K1000000/studycourse/transcript'
in self.browser.contents)
self.browser.getLink("K1000000").click()
self.assertTrue(
'Anna Tester: Transcript Data' in self.browser.contents)
# Officer is on transcript page and can validate the transcript
self.browser.getLink("Validate transcript").click()
self.browser.getControl("Save comment and validate transcript").click()
self.assertTrue(
'
Transcript validated.
'
in self.browser.contents)
# Officer is still on transcript page and can release the transcript
self.browser.getLink("Release transcript").click()
self.browser.getControl("Save comment and release transcript").click()
self.assertTrue(
'
'
'Transcript released and final transcript file saved.
'
in self.browser.contents)
def test_landingpage_transcript_signee(self):
IWorkflowState(self.student).setState('transcript validated')
notify(grok.ObjectModifiedEvent(self.student))
# Create transcript signee
self.app['users'].addUser('mrtranscript', SECRET)
self.app['users']['mrtranscript'].email = 'mrtranscript@foo.ng'
self.app['users']['mrtranscript'].title = 'Ruth Gordon'
# We assign transcript officer role at faculty level
fac = self.app['faculties']['fac1']
prmlocal = IPrincipalRoleManager(fac)
prmlocal.assignRoleToPrincipal(
'waeup.local.TranscriptSignee', 'mrtranscript')
notify(LocalRoleSetEvent(
fac, 'waeup.local.TranscriptSignee', 'mrtranscript', granted=True))
# Login as transcript officer
self.browser.open(self.login_path)
self.browser.getControl(name="form.login").value = 'mrtranscript'
self.browser.getControl(name="form.password").value = SECRET
self.browser.getControl("Login").click()
self.assertMatches('...You logged in...', self.browser.contents)
# Officer is on landing page and does see the transcript link
self.assertTrue(
'http://localhost/app/students/K1000000/studycourse/transcript'
in self.browser.contents)
self.browser.getLink("K1000000").click()
self.assertTrue(
'Anna Tester: Transcript Data' in self.browser.contents)
# Officer is on transcript page and can sign the transcript
self.browser.getLink("Sign transcript").click()
self.assertTrue(
'
Transcript signed.
'
in self.browser.contents)
# Officer is still on transcript page
self.assertTrue(
'Anna Tester: Transcript Data' in self.browser.contents)
# Officer can sign the transcript only once
self.browser.getLink("Sign transcript").click()
self.assertTrue(
'
'
'You have already signed this transcript.
'
in self.browser.contents)
# Signature can be seen on transcript page
self.assertTrue(
'Electronically signed by Ruth Gordon (mrtranscript) on'
in self.browser.contents)
def test_update_coursetickets(self):
IWorkflowState(self.student).setState('school fee paid')
studylevel = createObject(u'waeup.StudentStudyLevel')
studylevel.level = 100
studylevel.level_session = 2015
self.student['studycourse'].entry_mode = 'ug_ft'
self.student['studycourse'].addStudentStudyLevel(
self.certificate, studylevel)
self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
self.browser.open(
'http://localhost/app/faculties/fac1/dep1/courses/COURSE1/')
self.assertFalse(
'Update session 2015/2016 credits' in self.browser.contents)
self.app['configuration'].current_academic_session = 2015
self.browser.open(
'http://localhost/app/faculties/fac1/dep1/courses/COURSE1/')
self.browser.getLink("Update session 2015/2016 credits").click()
self.assertTrue(
'No course ticket found.' in self.browser.contents)
logfile = os.path.join(
self.app['datacenter'].storage, 'logs', 'main.log')
logcontent = open(logfile).read()
self.assertTrue(
'zope.mgr - browser.pages.UpdateCourseTicketsView - '
'course tickets updated: COURSE1' in logcontent)
studylevel['COURSE1'].credits = 12
self.browser.getLink("Update session 2015/2016 credits").click()
self.assertTrue(
'No course ticket found.' in self.browser.contents)
studylevel.level_session = 2015
self.student['studycourse'].current_session = 2015
self.browser.getLink("Update session 2015/2016 credits").click()
self.assertTrue(
'1 course ticket(s) updated.' in self.browser.contents)
logfile = os.path.join(
self.app['datacenter'].storage, 'logs', 'students.log')
logcontent = open(logfile).read()
self.assertTrue(
'zope.mgr - students.utils.StudentsUtils - '
'K1000000 100/COURSE1 credits updated (10->12)' in logcontent)
return
class StudentUITests(StudentsFullSetup):
# Tests for Student class views and pages
def test_student_change_password(self):
# Students can change the password
self.student.personal_updated = datetime.utcnow()
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/index')
# 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_forbidden_name(self):
self.student.lastname = u'Tester'
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.assertTrue('XXX: Base Data' in self.browser.contents)
self.assertTrue('<TAG>Tester</TAG>' in self.browser.contents)
self.assertFalse('Tester' 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_login(self):
# Student cant login if their password is not set
self.student.password = None
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.assertTrue(
'You entered invalid credentials.' in self.browser.contents)
# We set the password again
IUserAccount(
self.app['students'][self.student_id]).setPassword('spwd')
# Students can't login if their account is suspended/deactivated
self.student.suspended = True
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.assertMatches(
'...
'
'Your account has been deactivated.
...', self.browser.contents)
# If suspended_comment is set this message will be flashed instead
self.student.suspended_comment = u'Aetsch baetsch!'
self.browser.getControl(name="form.login").value = self.student_id
self.browser.getControl(name="form.password").value = 'spwd'
self.browser.getControl("Login").click()
self.assertMatches(
'...
Aetsch baetsch!
...',
self.browser.contents)
self.student.suspended = False
# Students can't login if a temporary password has been set and
# is not expired
self.app['students'][self.student_id].setTempPassword(
'anybody', 'temp_spwd')
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.assertMatches(
'...Your account has been temporarily deactivated...',
self.browser.contents)
# The student can login with the temporary password
self.browser.open(self.login_path)
self.browser.getControl(name="form.login").value = self.student_id
self.browser.getControl(name="form.password").value = 'temp_spwd'
self.browser.getControl("Login").click()
self.assertMatches(
'...You logged in...', self.browser.contents)
# Student can view the base data
self.browser.open(self.student_path)
self.assertEqual(self.browser.headers['Status'], '200 Ok')
self.assertEqual(self.browser.url, self.student_path)
# When the password expires ...
delta = timedelta(minutes=11)
self.app['students'][self.student_id].temp_password[
'timestamp'] = datetime.utcnow() - delta
self.app['students'][self.student_id]._p_changed = True
# ... the student will be automatically logged out
self.assertRaises(
Unauthorized, self.browser.open, self.student_path)
# Then the student can login with the original 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.assertMatches(
'...You logged in...', self.browser.contents)
def test_maintenance_mode(self):
config = grok.getSite()['configuration']
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 logged in.
self.assertTrue('You logged in' in self.browser.contents)
self.assertTrue("Anna Tester" in self.browser.contents)
# If maintenance mode is enabled, student is immediately logged out.
config.maintmode_enabled_by = u'any_user'
self.assertRaises(
Unauthorized, self.browser.open, 'http://localhost/app/faculties')
self.browser.open('http://localhost/app/login')
self.assertTrue('The portal is in maintenance mode' in self.browser.contents)
# Student really can't login if maintenance mode is enabled.
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()
# A second warning is raised.
self.assertTrue(
'The portal is in maintenance mode. You can\'t login!'
in self.browser.contents)
return
def test_student_clearance(self):
# Student cant login if their password is not set
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()
self.assertMatches(
'...You logged in...', self.browser.contents)
# Admitted student can upload a passport picture
self.browser.open(self.student_path + '/change_portrait')
ctrl = self.browser.getControl(name='passportuploadedit')
file_obj = open(SAMPLE_IMAGE, '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(
'src="http://localhost/app/students/K1000000/passport.jpg"'
in self.browser.contents)
# Students can open admission letter
self.browser.getLink("Base Data").click()
self.browser.getLink("Download admission letter").click()
self.assertEqual(self.browser.headers['Status'], '200 Ok')
self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
path = os.path.join(samples_dir(), 'admission_slip.pdf')
open(path, 'wb').write(self.browser.contents)
print "Sample PDF admission_slip.pdf written to %s" % path
# Student can view the clearance data
self.browser.open(self.student_path)
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.phone = None
# Uups, we forgot to fill the phone fields
self.browser.getControl("Start clearance").click()
self.assertMatches('...Phone number is missing...',
self.browser.contents)
self.browser.open(self.student_path + '/edit_base')
self.browser.getControl(name="form.phone.ext").value = '12345'
self.browser.getControl("Save").click()
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
# clr_code might be set (and thus returns None) due importing
# an empty clr_code column.
self.student.clr_code = None
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(SAMPLE_IMAGE, '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(
'href="http://localhost/app/students/K1000000/birth_certificate"'
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)
def test_student_course_registration(self):
# Student cant login if their password is not set
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'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
IWorkflowState(self.student).setState('school fee paid')
# Now students can add the current study level
self.browser.getLink("Study Course").click()
self.student['studycourse'].current_level = None
self.browser.getLink("Add course list").click()
self.assertMatches('...Your data are incomplete...',
self.browser.contents)
self.student['studycourse'].current_level = 100
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()
# A level with one course ticket was created
self.assertEqual(self.student['studycourse']['100'].number_of_tickets, 1)
self.browser.getLink("100").click()
self.browser.getLink("Edit course list").click()
self.browser.getLink("here").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("Edit course list").click()
self.browser.getLink("here").click()
self.browser.getControl(name="form.course").value = ['COURSE1']
self.course.credits = 100
self.browser.getControl("Add course ticket").click()
self.assertMatches(
'...Maximum credits exceeded...', self.browser.contents)
self.course.credits = 10
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)
self.assertTrue(
self.student['studycourse']['200']['COURSE1'].course_category is None)
# 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')
path = os.path.join(samples_dir(), 'course_registration_slip.pdf')
open(path, 'wb').write(self.browser.contents)
print "Sample PDF course_registration_slip.pdf written to %s" % path
# 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')
# Course list can't be registered if total_credits exceeds max_credits
self.student['studycourse']['200']['COURSE1'].credits = 60
self.browser.getControl("Register course list").click()
self.assertTrue('Maximum credits exceeded' in self.browser.contents)
# Student can now 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)
# Removing course tickets is properly logged
logfile = os.path.join(
self.app['datacenter'].storage, 'logs', 'students.log')
logcontent = open(logfile).read()
self.assertTrue('K1000000 - students.browser.StudyLevelEditFormPage '
'- K1000000 - level 200 - removed: COURSE1' in logcontent)
# They can add the same ticket using the edit page directly.
# We can do the same by adding the course on the manage page directly
self.browser.getControl(name="course").value = 'COURSE1'
self.browser.getControl("Add course ticket").click()
# Adding course tickets is logged
logfile = os.path.join(
self.app['datacenter'].storage, 'logs', 'students.log')
logcontent = open(logfile).read()
self.assertTrue('K1000000 - students.browser.StudyLevelEditFormPage - '
'K1000000 - level 200 - added: COURSE1|200|2004' in logcontent)
# Course list can be registered
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')
# Course list can be unregistered
self.browser.getLink("Unregister courses").click()
self.assertEqual(self.student.state, 'school fee paid')
self.assertTrue('Course list has been unregistered' in self.browser.contents)
self.browser.open(self.student_path + '/studycourse/200/unregister_courses')
self.assertTrue('You are in the wrong state' in self.browser.contents)
# Students can view the transcript
#self.browser.open(self.studycourse_path)
#self.browser.getLink("Transcript").click()
#self.browser.getLink("Academic Transcript").click()
#self.assertEqual(self.browser.headers['Status'], '200 Ok')
#self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
return
def test_student_ticket_update(self):
IWorkflowState(self.student).setState('school fee paid')
self.student['studycourse'].current_level = 100
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()
# 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()
# A level with one course ticket was created
self.assertEqual(
self.student['studycourse']['100'].number_of_tickets, 1)
self.browser.getLink("100").click()
self.assertTrue('
Unnamed Course
' in self.browser.contents)
self.browser.getLink("Edit course list").click()
self.browser.getControl("Update all tickets").click()
self.assertTrue('All course tickets updated.' in self.browser.contents)
# ... nothing has changed
self.assertTrue('
Unnamed Course
' in self.browser.contents)
# We change the title of the course
self.course.title = u'New Title'
self.browser.getControl("Update all tickets").click()
self.assertTrue('
New Title
' in self.browser.contents)
# We remove the course
del self.app['faculties']['fac1']['dep1'].courses['COURSE1']
self.browser.getControl("Update all tickets").click()
self.assertTrue('
New Title (course cancelled)
'
in self.browser.contents)
# Course ticket invalidation has been logged
logfile = os.path.join(
self.app['datacenter'].storage, 'logs', 'students.log')
logcontent = open(logfile).read()
self.assertTrue(
'K1000000 - students.browser.StudyLevelEditFormPage - '
'K1000000 - level 100 - course tickets invalidated: COURSE1'
in logcontent)
return
def test_student_course_already_passed(self):
IWorkflowState(self.student).setState('school fee paid')
self.student['studycourse'].current_level = 100
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()
# 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()
# A level with one course ticket was created
self.assertEqual(self.student['studycourse']['100'].number_of_tickets, 1)
# We set the score above the passmark
self.student['studycourse']['100'][
'COURSE1'].score = self.student['studycourse']['100'][
'COURSE1'].passmark + 1
# We add a second level
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("Edit course list").click()
self.browser.getLink("here").click()
self.browser.getControl(name="form.course").value = ['COURSE1']
self.browser.getControl("Add course ticket").click()
self.assertTrue(
'Course has already been passed at previous level'
in self.browser.contents)
self.assertEqual(self.student['studycourse']['200'].number_of_tickets, 0)
# We set the score below the passmark
self.student['studycourse']['100'][
'COURSE1'].score = self.student['studycourse']['100'][
'COURSE1'].passmark - 1
self.browser.getControl("Add course ticket").click()
self.assertTrue(
'Successfully added COURSE1' in self.browser.contents)
self.assertEqual(self.student['studycourse']['200'].number_of_tickets, 1)
return
def test_student_course_registration_outstanding(self):
self.course = createObject('waeup.Course')
self.course.code = 'COURSE2'
self.course.semester = 1
self.course.credits = 45
self.course.passmark = 40
self.app['faculties']['fac1']['dep1'].courses.addCourse(
self.course)
IWorkflowState(self.student).setState('school fee paid')
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.browser.open(self.student_path + '/studycourse/add')
self.browser.getControl("Create course list now").click()
self.assertEqual(self.student['studycourse']['100'].number_of_tickets, 1)
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("Edit course list").click()
self.browser.getLink("here").click()
self.browser.getControl(name="form.course").value = ['COURSE2']
self.browser.getControl("Add course ticket").click()
# Carryover COURSE1 in level 200 already has 10 credits
self.assertMatches(
'...Maximum credits exceeded...', self.browser.contents)
# If COURSE1 is outstanding, its credits won't be considered
self.student['studycourse']['200']['COURSE1'].outstanding = True
self.browser.getControl("Add course ticket").click()
self.assertMatches(
'...Successfully added COURSE2...', self.browser.contents)
return
def test_postgraduate_student_access(self):
self.certificate.study_mode = 'pg_ft'
self.certificate.start_level = 999
self.certificate.end_level = 999
self.student['studycourse'].current_level = 999
IWorkflowState(self.student).setState('school fee paid')
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.assertTrue(
'You logged in.' in self.browser.contents)
# 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 Postgraduate Level...',
self.browser.contents)
self.browser.getControl("Create course list now").click()
self.assertTrue("You successfully created a new course list"
in self.browser.contents)
# A level with one course ticket was created
self.assertEqual(self.student['studycourse']['999'].number_of_tickets, 0)
self.browser.getLink("Edit course list").click()
self.browser.getLink("here").click()
self.browser.getControl(name="form.course").value = ['COURSE1']
self.browser.getControl("Add course ticket").click()
self.assertMatches('...Successfully added COURSE1...',
self.browser.contents)
# Postgraduate students can't register course lists
self.browser.getControl("Register course list").click()
self.assertTrue("your course list can't bee registered"
in self.browser.contents)
self.assertEqual(self.student.state, 'school fee paid')
return
def test_student_clearance_wo_clrcode(self):
IWorkflowState(self.student).setState('clearance started')
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.browser.open(self.edit_clearance_path)
self.browser.getControl(name="form.date_of_birth").value = '09/10/1961'
self.browser.getControl("Save and request clearance").click()
self.assertMatches('...Clearance has been requested...',
self.browser.contents)
def test_student_clearance_payment(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't approve the payment
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.assertRaises(
Unauthorized, self.browser.open, payment_url + '/approve')
# In the base package they can 'use' a fake approval view.
# XXX: I tried to use
# self.student['payments'][value].approveStudentPayment() instead.
# But this function fails in
# w.k.accesscodes.accesscode.create_accesscode.
# grok.getSite returns None in tests.
self.browser.open(payment_url + '/fake_approve')
self.assertMatches('...Payment approved...',
self.browser.contents)
expected = '''...
Paid
...'''
expected = '''...
Paid
...'''
self.assertMatches(expected,self.browser.contents)
payment_id = self.student['payments'].keys()[0]
payment = self.student['payments'][payment_id]
self.assertEqual(payment.p_state, 'paid')
self.assertEqual(payment.r_amount_approved, 3456.0)
self.assertEqual(payment.r_code, 'AP')
self.assertEqual(payment.r_desc, u'Payment approved by Anna Tester')
# 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]
self.assertEqual(ac.owner, self.student_id)
self.assertEqual(ac.cost, 3456.0)
# 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')
image = open(SAMPLE_IMAGE, 'rb')
ctrl = self.browser.getControl(name='passportuploadedit')
file_ctrl = ctrl.mech_control
file_ctrl.add_file(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)
def test_student_schoolfee_payment(self):
configuration = createObject('waeup.SessionConfiguration')
configuration.academic_session = 2005
self.app['configuration'].addSessionConfiguration(configuration)
# 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 school fee payment tickets.
IWorkflowState(self.student).setState('returning')
self.browser.open(self.payments_path)
self.assertRaises(
LookupError, self.browser.getControl, name='val_id')
self.browser.getLink("Add current session 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)
self.assertEqual(self.student['payments'][value].amount_auth, 20000.0)
# Payment session and will be calculated as defined
# in w.k.students.utils because we set changed the state
# to returning
self.assertEqual(self.student['payments'][value].p_session, 2005)
self.assertEqual(self.student['payments'][value].p_level, 200)
# Student is the payer of the payment ticket.
payer = IPayer(self.student['payments'][value])
self.assertEqual(payer.display_fullname, 'Anna Tester')
self.assertEqual(payer.id, self.student_id)
self.assertEqual(payer.faculty, 'fac1')
self.assertEqual(payer.department, 'dep1')
# We simulate the approval
self.assertEqual(len(self.app['accesscodes']['SFE-0']),0)
self.browser.open(self.browser.url + '/fake_approve')
self.assertMatches('...Payment approved...',
self.browser.contents)
## The new SFE-0 pin can be used for starting new session
#self.browser.open(self.studycourse_path)
#self.browser.getLink('Start new session').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 now").click()
#self.assertMatches('...Session started...',
# self.browser.contents)
self.assertTrue(self.student.state == 'school fee paid')
return
def test_student_bedallocation_payment(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()
self.browser.open(self.payments_path)
self.browser.open(self.payments_path + '/addop')
self.browser.getControl(name="form.p_category").value = ['bed_allocation']
self.browser.getControl("Create ticket").click()
self.assertMatches('...ticket created...',
self.browser.contents)
# Students can remove only online payment tickets which have
# not received a valid callback
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)
def test_student_maintenance_payment(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()
self.browser.open(self.payments_path)
self.browser.open(self.payments_path + '/addop')
self.browser.getControl(name="form.p_category").value = ['hostel_maintenance']
self.browser.getControl("Create ticket").click()
self.assertMatches('...You have not yet booked accommodation...',
self.browser.contents)
# We continue this test in test_student_accommodation
def test_student_previous_payments(self):
configuration = createObject('waeup.SessionConfiguration')
configuration.academic_session = 2000
configuration.clearance_fee = 3456.0
configuration.booking_fee = 123.4
self.app['configuration'].addSessionConfiguration(configuration)
configuration2 = createObject('waeup.SessionConfiguration')
configuration2.academic_session = 2003
configuration2.clearance_fee = 3456.0
configuration2.booking_fee = 123.4
self.app['configuration'].addSessionConfiguration(configuration2)
configuration3 = createObject('waeup.SessionConfiguration')
configuration3.academic_session = 2005
configuration3.clearance_fee = 3456.0
configuration3.booking_fee = 123.4
self.app['configuration'].addSessionConfiguration(configuration3)
self.student['studycourse'].entry_session = 2002
# 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 previous school fee payment tickets in any state.
IWorkflowState(self.student).setState('courses registered')
self.browser.open(self.payments_path)
self.browser.getLink("Add previous session payment ticket").click()
# Previous session payment form is provided
self.assertEqual(self.student.current_session, 2004)
self.browser.getControl(name="form.p_category").value = ['schoolfee']
self.browser.getControl(name="form.p_session").value = ['2000']
self.browser.getControl(name="form.p_level").value = ['300']
self.browser.getControl("Create ticket").click()
self.assertMatches('...The previous session must not fall below...',
self.browser.contents)
self.browser.getControl(name="form.p_category").value = ['schoolfee']
self.browser.getControl(name="form.p_session").value = ['2005']
self.browser.getControl(name="form.p_level").value = ['300']
self.browser.getControl("Create ticket").click()
self.assertMatches('...This is not a previous session...',
self.browser.contents)
# Students can pay current session school fee.
self.browser.getControl(name="form.p_category").value = ['schoolfee']
self.browser.getControl(name="form.p_session").value = ['2004']
self.browser.getControl(name="form.p_level").value = ['300']
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)
self.assertEqual(self.student['payments'][value].amount_auth, 20000.0)
# Ticket creation is logged.
logfile = os.path.join(
self.app['datacenter'].storage, 'logs', 'students.log')
logcontent = open(logfile).read()
self.assertTrue(
'K1000000 - students.browser.PreviousPaymentAddFormPage - '
'K1000000 - added: %s' % value
in logcontent)
# Payment session is properly set
self.assertEqual(self.student['payments'][value].p_session, 2004)
self.assertEqual(self.student['payments'][value].p_level, 300)
# We simulate the approval
self.browser.open(self.browser.url + '/fake_approve')
self.assertMatches('...Payment approved...',
self.browser.contents)
# No AC has been created
self.assertEqual(len(self.app['accesscodes']['SFE-0'].keys()), 0)
self.assertTrue(self.student['payments'][value].ac is None)
# Current payment flag is set False
self.assertFalse(self.student['payments'][value].p_current)
# Button and form are not available for students who are in
# states up to cleared
self.student['studycourse'].entry_session = 2004
IWorkflowState(self.student).setState('cleared')
self.browser.open(self.payments_path)
self.assertFalse(
"Add previous session payment ticket" in self.browser.contents)
self.browser.open(self.payments_path + '/addpp')
self.assertTrue(
"No previous payment to be made" in self.browser.contents)
return
def test_postgraduate_student_payments(self):
configuration = createObject('waeup.SessionConfiguration')
configuration.academic_session = 2005
self.app['configuration'].addSessionConfiguration(configuration)
self.certificate.study_mode = 'pg_ft'
self.certificate.start_level = 999
self.certificate.end_level = 999
self.student['studycourse'].current_level = 999
# 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 school fee payment tickets.
IWorkflowState(self.student).setState('cleared')
self.browser.open(self.payments_path)
self.browser.getLink("Add current session 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 are current ones.
# Postgrads have to pay school_fee_1.
self.assertEqual(self.student['payments'][value].amount_auth, 40000.0)
self.assertEqual(self.student['payments'][value].p_session, 2004)
self.assertEqual(self.student['payments'][value].p_level, 999)
# We simulate the approval
self.assertEqual(len(self.app['accesscodes']['SFE-0']),0)
self.browser.open(self.browser.url + '/fake_approve')
self.assertMatches('...Payment approved...',
self.browser.contents)
## The new SFE-0 pin can be used for starting session
#self.browser.open(self.studycourse_path)
#self.browser.getLink('Start new session').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 now").click()
#self.assertMatches('...Session started...',
# self.browser.contents)
self.assertTrue(self.student.state == 'school fee paid')
# Postgrad students do not need to register courses the
# can just pay for the next session.
self.browser.open(self.payments_path)
# Remove first payment to be sure that we access the right ticket
del self.student['payments'][value]
self.browser.getLink("Add current session payment ticket").click()
self.browser.getControl(name="form.p_category").value = ['schoolfee']
self.browser.getControl("Create ticket").click()
ctrl = self.browser.getControl(name='val_id')
value = ctrl.options[0]
self.browser.getLink(value).click()
# Payment session has increased by one, payment level remains the same.
# Returning Postgraduates have to pay school_fee_2.
self.assertEqual(self.student['payments'][value].amount_auth, 20000.0)
self.assertEqual(self.student['payments'][value].p_session, 2005)
self.assertEqual(self.student['payments'][value].p_level, 999)
# Student is still in old session
self.assertEqual(self.student.current_session, 2004)
# We do not need to pay the ticket if any other
# SFE pin is provided
pin_container = self.app['accesscodes']
pin_container.createBatch(
datetime.utcnow(), 'some_userid', 'SFE', 9.99, 1)
pin = pin_container['SFE-1'].values()[0].representation
sfeseries, sfenumber = pin.split('-')[1:]
# The new SFE-1 pin can be used for starting new session
self.browser.open(self.studycourse_path)
self.browser.getLink('Start new session').click()
self.browser.getControl(name="ac_series").value = sfeseries
self.browser.getControl(name="ac_number").value = sfenumber
self.browser.getControl("Start now").click()
self.assertMatches('...Session started...',
self.browser.contents)
self.assertTrue(self.student.state == 'school fee paid')
# Student is in new session
self.assertEqual(self.student.current_session, 2005)
self.assertEqual(self.student['studycourse'].current_level, 999)
return
def test_student_accommodation(self):
# Create a second hostel with one bed
hostel = Hostel()
hostel.hostel_id = u'hall-2'
hostel.hostel_name = u'Hall 2'
self.app['hostels'].addHostel(hostel)
bed = Bed()
bed.bed_id = u'hall-2_A_101_A'
bed.bed_number = 1
bed.owner = NOT_OCCUPIED
bed.bed_type = u'regular_female_fr'
self.app['hostels'][hostel.hostel_id].addBed(bed)
self.app['hostels'].allocation_expiration = 7
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.getLink("Add current session 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 + '/fake_approve')
# 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]
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)
# ... but not if booking period has expired ...
self.app['hostels'].enddate = datetime.now(pytz.utc)
self.browser.getControl("Book accommodation").click()
self.assertMatches('...Outside booking period: ...',
self.browser.contents)
self.app['hostels'].enddate = datetime.now(pytz.utc) + timedelta(days=10)
# ... or student data are incomplete ...
self.student['studycourse'].current_level = None
self.browser.getControl("Book accommodation").click()
self.assertMatches('...Your data are incomplete...',
self.browser.contents)
self.student['studycourse'].current_level = 100
# ... or student is not the an allowed state ...
self.browser.getControl("Book accommodation").click()
self.assertMatches('...You are in the wrong...',
self.browser.contents)
# Students can still not see the disired hostel selector.
self.assertFalse('desired hostel' in self.browser.contents)
IWorkflowInfo(self.student).fireTransition('admit')
# Students can now see the disired hostel selector.
self.browser.reload()
self.browser.open(self.acco_path)
self.assertTrue('desired hostel' in self.browser.contents)
self.browser.getControl(name="hostel").value = ['hall-2']
self.browser.getControl("Save").click()
self.assertTrue('selection has been saved' in self.browser.contents)
self.assertTrue('