## $Id: test_browser.py 11488 2014-03-13 06:49:36Z 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 applicant-related UI components.
"""

import os
import pytz
import grok
from datetime import datetime
from datetime import datetime, date, timedelta
from zope.event import notify
from StringIO import StringIO
from zope.component import createObject, getUtility
from waeup.kofa.applicants.container import ApplicantsContainer
from waeup.kofa.applicants.tests.test_browser import ApplicantsFullSetup
from waeup.kofa.interfaces import (
    IExtFileStore, IFileStoreNameChooser)

from waeup.futminna.testing import FunctionalLayer

PH_LEN = 15911  # Length of placeholder file

session = datetime.now().year - 2
container_name = u'app%s' % session


class ApplicantUITests(ApplicantsFullSetup):
    # Tests for uploading/browsing the passport image of appplicants

    layer = FunctionalLayer

    def test_upload_image_by_student(self):
        self.login()
        self.browser.open(self.edit_path)
        # Create a pseudo image file and select it to be uploaded in form
        photo_content = 'A' * 1024 * 21  # A string of 21 KB size
        pseudo_image = StringIO(photo_content)
        ctrl = self.browser.getControl(name='form.passport')
        file_ctrl = ctrl.mech_control
        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
        self.browser.getControl("Save").click() # submit form
        # There is a correct <img> link included
        self.assertTrue(
            '<img src="passport.jpg" height="180px" />' in self.browser.contents)
        # We get a warning message
        self.assertTrue(
            'Uploaded image is too big' in self.browser.contents)
        # Browsing the image gives us the default image, not the
        # uploaded one.
        image_url = self.edit_path.replace('edit', 'passport.jpg')
        self.browser.open(image_url)
        self.assertEqual(
            self.browser.headers['content-type'], 'image/jpeg')
        self.assertEqual(len(self.browser.contents), PH_LEN)
        # There is really no file stored for the applicant
        img = getUtility(IExtFileStore).getFile(
            IFileStoreNameChooser(self.applicant).chooseName())
        self.assertTrue(img is None)

    def test_upload_extraform_by_student(self):
        self.login()
        self.browser.open(self.edit_path)
        # Create a pseudo file and select it to be uploaded in form
        pdf_content = 'A' * 1024 * 600  # A string of 600 KB size
        pseudo_pdf = StringIO(pdf_content)
        ctrl = self.browser.getControl(name='form.extraform')
        file_ctrl = ctrl.mech_control
        file_ctrl.add_file(pseudo_pdf, filename='myform.pdf')
        self.browser.getControl("Save").click() # submit form
        # We get a warning message
        self.assertTrue(
            'Uploaded file is too big' in self.browser.contents)
        # Create a pseudo file with acceptable size
        pdf_content = 'A' * 1024 * 300  # A string of 300 KB size
        pseudo_pdf = StringIO(pdf_content)
        ctrl = self.browser.getControl(name='form.extraform')
        file_ctrl = ctrl.mech_control
        file_ctrl.add_file(pseudo_pdf, filename='myform.pdf')
        self.browser.getControl("Save").click() # submit form
        # Even though the form could not be saved ...
        self.assertTrue('Required input is missing' in self.browser.contents)
        # ... the file has been successfully uploaded
        pdf_url = self.edit_path.replace('edit', 'extraform.pdf')
        self.browser.open(pdf_url)
        self.assertEqual(
            self.browser.headers['content-type'], 'application/pdf')
        self.assertEqual(len(self.browser.contents), 307200)
        # There is rally a file stored for the applicant
        storage = getUtility(IExtFileStore)
        file_id = IFileStoreNameChooser(self.applicant).chooseName(
            attr='extraform.pdf')
        # The stored file can be fetched
        fd = storage.getFile(file_id)
        file_len = len(fd.read())
        self.assertEqual(file_len, 307200)
        # A file link is displayed on the edit view ...
        self.browser.open(self.edit_path)
        self.assertTrue('<a href="extraform.pdf">' in self.browser.contents)
        # ... and on the dislay view
        self.browser.open(self.view_path)
        self.assertTrue('<a href="extraform.pdf">Extra Applicant Information Form</a>'
            in self.browser.contents)

    def test_upload_extraform_by_manager(self):
        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
        self.browser.open(self.manage_path)
        # Create a pseudo file with acceptable size
        pdf_content = 'A' * 1024 * 300  # A string of 300 KB size
        pseudo_pdf = StringIO(pdf_content)
        ctrl = self.browser.getControl(name='form.extraform')
        file_ctrl = ctrl.mech_control
        file_ctrl.add_file(pseudo_pdf, filename='myform.pdf')
        self.browser.getControl("Save").click() # submit form
        # Even though the form could not be saved ...
        self.assertTrue('Required input is missing' in self.browser.contents)
        # ... the file has been successfully uploaded
        pdf_url = self.manage_path.replace('manage', 'extraform.pdf')
        self.browser.open(pdf_url)
        self.assertEqual(
            self.browser.headers['content-type'], 'application/pdf')
        self.assertEqual(len(self.browser.contents), 307200)
        # There is rally a file stored for the applicant
        storage = getUtility(IExtFileStore)
        file_id = IFileStoreNameChooser(self.applicant).chooseName(
            attr='extraform.pdf')
        # The stored file can be fetched
        fd = storage.getFile(file_id)
        file_len = len(fd.read())
        self.assertEqual(file_len, 307200)
        # A file link is displayed on the edit view ...
        self.browser.open(self.manage_path)
        self.assertTrue('<a href="extraform.pdf">' in self.browser.contents)
        # ... and on the dislay view
        self.browser.open(self.view_path)
        self.assertTrue('<a href="extraform.pdf">Extra Applicant Information Form</a>'
            in self.browser.contents)
        # Adding file is properly logged
        logfile = os.path.join(
            self.app['datacenter'].storage, 'logs', 'applicants.log')
        logcontent = open(logfile).read()
        self.assertTrue(
            'zope.mgr - waeup.futminna.applicants.browser.CustomApplicantManageFormPage'
            ' - %s - saved: extraform'
            % (self.applicant.applicant_id)
            in logcontent)
        # When an applicant is removed, also the pdf files are gone.
        del self.app['applicants'][container_name][self.applicant.application_number]
        fd = storage.getFile(file_id)
        self.assertTrue(fd is None)

    def test_upload_refereeform_by_student(self):
        self.login()
        self.browser.open(self.edit_path)
        # Create a pseudo file and select it to be uploaded in form
        pdf_content = 'A' * 1024 * 600  # A string of 600 KB size
        pseudo_pdf = StringIO(pdf_content)
        ctrl = self.browser.getControl(name='form.refereeform')
        file_ctrl = ctrl.mech_control
        file_ctrl.add_file(pseudo_pdf, filename='myform.pdf')
        self.browser.getControl("Save").click() # submit form
        # We get a warning message
        self.assertTrue(
            'Uploaded file is too big' in self.browser.contents)
        # Create a pseudo file with acceptable size
        pdf_content = 'A' * 1024 * 300  # A string of 300 KB size
        pseudo_pdf = StringIO(pdf_content)
        ctrl = self.browser.getControl(name='form.refereeform')
        file_ctrl = ctrl.mech_control
        file_ctrl.add_file(pseudo_pdf, filename='myform.pdf')
        self.browser.getControl("Save").click() # submit form
        # Even though the form could not be saved ...
        self.assertTrue('Required input is missing' in self.browser.contents)
        # ... the file has been successfully uploaded
        pdf_url = self.edit_path.replace('edit', 'refereeform.pdf')
        self.browser.open(pdf_url)
        self.assertEqual(
            self.browser.headers['content-type'], 'application/pdf')
        self.assertEqual(len(self.browser.contents), 307200)
        # There is really a file stored for the applicant
        storage = getUtility(IExtFileStore)
        file_id = IFileStoreNameChooser(self.applicant).chooseName(
            attr='refereeform.pdf')
        # The stored file can be fetched
        fd = storage.getFile(file_id)
        file_len = len(fd.read())
        self.assertEqual(file_len, 307200)
        # A file link is displayed on the edit view ...
        self.browser.open(self.edit_path)
        self.assertTrue('<a href="refereeform.pdf">' in self.browser.contents)
        # ... and on the dislay view
        self.browser.open(self.view_path)
        self.assertTrue('<a href="refereeform.pdf">Referee\'s Form</a>'
            in self.browser.contents)

    def test_upload_refereeform_by_manager(self):
        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
        self.browser.open(self.manage_path)
        # Create a pseudo file with acceptable size
        pdf_content = 'A' * 1024 * 300  # A string of 300 KB size
        pseudo_pdf = StringIO(pdf_content)
        ctrl = self.browser.getControl(name='form.refereeform')
        file_ctrl = ctrl.mech_control
        file_ctrl.add_file(pseudo_pdf, filename='myform.pdf')
        self.browser.getControl("Save").click() # submit form
        # Even though the form could not be saved ...
        self.assertTrue('Required input is missing' in self.browser.contents)
        # ... the file has been successfully uploaded
        pdf_url = self.manage_path.replace('manage', 'refereeform.pdf')
        self.browser.open(pdf_url)
        self.assertEqual(
            self.browser.headers['content-type'], 'application/pdf')
        self.assertEqual(len(self.browser.contents), 307200)
        # There is rally a file stored for the applicant
        storage = getUtility(IExtFileStore)
        file_id = IFileStoreNameChooser(self.applicant).chooseName(
            attr='refereeform.pdf')
        # The stored file can be fetched
        fd = storage.getFile(file_id)
        file_len = len(fd.read())
        self.assertEqual(file_len, 307200)
        # A file link is displayed on the edit view ...
        self.browser.open(self.manage_path)
        self.assertTrue('<a href="refereeform.pdf">' in self.browser.contents)
        # ... and on the dislay view
        self.browser.open(self.view_path)
        self.assertTrue('<a href="refereeform.pdf">Referee\'s Form</a>'
            in self.browser.contents)
        # Adding file is properly logged
        logfile = os.path.join(
            self.app['datacenter'].storage, 'logs', 'applicants.log')
        logcontent = open(logfile).read()
        self.assertTrue(
            'zope.mgr - waeup.futminna.applicants.browser.CustomApplicantManageFormPage'
            ' - %s - saved: refereeform'
            % (self.applicant.applicant_id)
            in logcontent)
        # When an applicant is removed, also the pdf files are gone.
        del self.app['applicants'][container_name][self.applicant.application_number]
        fd = storage.getFile(file_id)
        self.assertTrue(fd is None)

    def test_upload_credentials_by_manager(self):
        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
        self.browser.open(self.manage_path)
        # Create a pseudo file with acceptable size
        pdf_content = 'A' * 1024 * 300  # A string of 300 KB size
        pseudo_pdf = StringIO(pdf_content)
        # This is a ug applicant, thus the credentials is not
        # required
        self.assertFalse('credentials">' in self.browser.contents)

        # We have to add a pg applicants container
        container_name = u'pg%s' % (datetime.now().year - 1)
        applicantscontainer = ApplicantsContainer()
        applicantscontainer.code = container_name
        applicantscontainer.prefix = 'pgft'
        applicantscontainer.year = datetime.now().year - 1
        applicantscontainer.title = u'This is the %s container' % container_name
        applicantscontainer.application_category = 'pg_ft'
        applicantscontainer.mode = 'create'
        applicantscontainer.strict_deadline = True
        delta = timedelta(days=10)
        applicantscontainer.startdate = datetime.now(pytz.utc) - delta
        applicantscontainer.enddate = datetime.now(pytz.utc) + delta
        self.app['applicants'][container_name] = applicantscontainer
        applicant = createObject('waeup.Applicant')
        # reg_number is the only field which has to be preset here
        # because managers are allowed to edit this required field
        applicant.reg_number = u'2345'
        applicant.course1 = self.certificate
        self.app['applicants'][container_name].addApplicant(applicant)
        self.manage_path_pg = 'http://localhost/app/applicants/%s/%s/%s' % (
            container_name, applicant.application_number, 'manage')
        self.view_path_pg = 'http://localhost/app/applicants/%s/%s' % (
            container_name, applicant.application_number)

        self.browser.open(self.manage_path_pg)
        ctrl = self.browser.getControl(name='form.credentials')
        file_ctrl = ctrl.mech_control
        file_ctrl.add_file(pseudo_pdf, filename='myform.pdf')
        self.browser.getControl("Save").click() # submit form
        # Even though the form could not be saved ...
        self.assertTrue('Required input is missing' in self.browser.contents)
        # ... the file has been successfully uploaded
        pdf_url = self.manage_path_pg.replace('manage', 'credentials.pdf')
        self.browser.open(pdf_url)
        self.assertEqual(
            self.browser.headers['content-type'], 'application/pdf')
        self.assertEqual(len(self.browser.contents), 307200)
        # There is rally a file stored for the applicant
        storage = getUtility(IExtFileStore)
        file_id = IFileStoreNameChooser(applicant).chooseName(
            attr='credentials.pdf')
        # The stored file can be fetched
        fd = storage.getFile(file_id)
        file_len = len(fd.read())
        self.assertEqual(file_len, 307200)
        # A file link is displayed on the edit view ...
        self.browser.open(self.manage_path_pg)
        self.assertTrue('<a href="credentials.pdf">' in self.browser.contents)
        # ... and on the dislay view
        self.browser.open(self.view_path_pg)
        self.assertTrue('<a href="credentials.pdf">Credentials</a>'
            in self.browser.contents)
        # Adding file is properly logged
        logfile = os.path.join(
            self.app['datacenter'].storage, 'logs', 'applicants.log')
        logcontent = open(logfile).read()
        self.assertTrue(
            'zope.mgr - waeup.futminna.applicants.browser.CustomApplicantManageFormPage'
            ' - %s - saved: credentials'
            % (applicant.applicant_id)
            in logcontent)
        # When an applicant is removed, also the pdf files are gone.
        del self.app['applicants'][container_name][applicant.application_number]
        fd = storage.getFile(file_id)
        self.assertTrue(fd is None)

    def test_certificate_source(self):
        # We add a second 'alternative' certificate
        certificate = createObject('waeup.Certificate')
        certificate.code = 'CERT2'
        certificate.title = 'New Certificate'
        certificate.application_category = 'basic'
        self.app['faculties']['fac1']['dep1'].certificates.addCertificate(
            certificate)
        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
        self.browser.open(self.edit_path)
        self.assertFalse('course2' in self.browser.contents)
        self.certificate.custom_textline_1 = u'Maths, Physics'
        self.certificate.custom_float_1 = 50.0
        certificate.custom_textline_1 = u'German, Physics'
        certificate.custom_float_1 = 30.0
        notify(grok.ObjectModifiedEvent(certificate))
        self.browser.open(self.edit_path)
        # Score must be set and below the limit
        # of course1 to see course2 field
        self.applicant.jamb_score = 20
        self.browser.open(self.edit_path)
        self.assertTrue('course2' in self.browser.contents)
        # But 20 is not enough to select the alternative CERT2
        self.assertFalse(
            'value="CERT2">CERT2 - New Certificate'
            in self.browser.contents)
        self.applicant.jamb_score = 30
        self.browser.open(self.edit_path)
        # 30 is enough
        self.assertTrue('course2' in self.browser.contents)
        self.assertTrue(
            'value="CERT2">CERT2 - New Certificate [German, Physics, 30]</option>'
            in self.browser.contents)

    def test_low_jamb_score(self):
        self.login()
        self.assertFalse('<select id="form.course2" name="form.course2" size="1" >'
            in self.browser.contents)
        self.certificate.custom_textline_1 = u'Maths, Physics'
        self.certificate.custom_float_1 = 50.0
        self.applicant.jamb_score = 40
        self.browser.open(self.edit_path)
        self.assertTrue('<select id="form.course2" name="form.course2" size="1" >'
            in self.browser.contents)
