Ignore:
Timestamp:
21 Sep 2012, 11:21:05 (12 years ago)
Author:
uli
Message:

Merge changes from uli-async-update back into trunk.

Location:
main/waeup.kofa/trunk/src/waeup/kofa/browser
Files:
9 added
9 edited

Legend:

Unmodified
Added
Removed
  • main/waeup.kofa/trunk/src/waeup/kofa/browser/__init__.py

    r7819 r9217  
    11import os
    22
    3 from waeup.kofa.browser.layout import (
    4     KofaPage, KofaForm, KofaLayout, KofaDisplayFormPage, KofaEditFormPage,
    5     KofaAddFormPage, NullValidator)
    6 from waeup.kofa.browser.pages import ContactAdminForm
     3#from waeup.kofa.browser.layout import (
     4#    KofaPage, KofaForm, KofaLayout, KofaDisplayFormPage, KofaEditFormPage,
     5#    KofaAddFormPage, NullValidator)
     6#from waeup.kofa.browser.pages import ContactAdminForm
    77
    88IMAGE_PATH = os.path.join(
  • main/waeup.kofa/trunk/src/waeup/kofa/browser/breadcrumbs.py

    r7819 r9217  
    2626    IConfigurationContainer, ISessionConfiguration)
    2727from waeup.kofa.interfaces import MessageFactory as _
    28 from waeup.kofa.browser import interfaces
    29 from waeup.kofa.browser.interfaces import (IBreadcrumb,
    30     IBreadcrumbIgnorable, IBreadcrumbContainer)
     28from waeup.kofa.browser.interfaces import (
     29    IBreadcrumb, IBreadcrumbIgnorable, IBreadcrumbContainer, IKofaObject,
     30    IUniversity, IFacultiesContainer, IUsersContainer, IDataCenter, IFaculty,
     31    IDepartment, ICourse, ICertificate, ICoursesContainer, ICertificateCourse,
     32    ICertificatesContainer,
     33    )
    3134
    3235class Breadcrumb(grok.Adapter):
     
    3437    """
    3538    grok.provides(IBreadcrumb)
    36     grok.context(interfaces.IKofaObject)
     39    grok.context(IKofaObject)
    3740    grok.name('index')
    3841
     
    8790    """A breadcrumb for university index pages.
    8891    """
    89     grok.context(interfaces.IUniversity)
     92    grok.context(IUniversity)
    9093    title = _(u'Home')
    9194    parent = None
     
    100103    itself is bound to.
    101104    """
    102     grok.context(interfaces.IUniversity)
     105    grok.context(IUniversity)
    103106    grok.name('manage')
    104107    title = _(u'Portal Settings')
     
    113116    """A breadcrumb for faculty containers.
    114117    """
    115     grok.context(interfaces.IFacultiesContainer)
     118    grok.context(IFacultiesContainer)
    116119    title = _(u'Academics')
    117120
     
    119122    """A breadcrumb for administration areas of University instances.
    120123    """
    121     grok.context(interfaces.IUniversity)
     124    grok.context(IUniversity)
    122125    grok.name('administration')
    123126    title = _(u'Administration')
     
    145148    """A breadcrumb for user containers.
    146149    """
    147     grok.context(interfaces.IUsersContainer)
     150    grok.context(IUsersContainer)
    148151    title = _(u'Portal Users')
    149152    parent_viewname = 'administration'
     
    152155    """A breadcrumb for data centers.
    153156    """
    154     grok.context(interfaces.IDataCenter)
     157    grok.context(IDataCenter)
    155158    title = _(u'Data Center')
    156159    parent_viewname = 'administration'
     
    159162    """A breadcrumb for faculties.
    160163    """
    161     grok.context(interfaces.IFaculty)
     164    grok.context(IFaculty)
    162165
    163166    @property
     
    168171    """A breadcrumb for departments.
    169172    """
    170     grok.context(interfaces.IDepartment)
     173    grok.context(IDepartment)
    171174
    172175class CourseBreadcrumb(FacultyBreadcrumb):
    173176    """A breadcrumb for courses.
    174177    """
    175     grok.context(interfaces.ICourse)
     178    grok.context(ICourse)
    176179
    177180class CertificateBreadcrumb(FacultyBreadcrumb):
    178181    """A breadcrumb for certificates.
    179182    """
    180     grok.context(interfaces.ICertificate)
     183    grok.context(ICertificate)
    181184
    182185class CoursesContainerBreadcrumb(Breadcrumb):
    183186    """ We don't want course container breadcrumbs.
    184187    """
    185     grok.context(interfaces.ICoursesContainer)
     188    grok.context(ICoursesContainer)
    186189    grok.implements(IBreadcrumbIgnorable)
    187190
     
    189192    """ We don't want course container breadcrumbs.
    190193    """
    191     grok.context(interfaces.ICertificatesContainer)
     194    grok.context(ICertificatesContainer)
    192195    grok.implements(IBreadcrumbIgnorable)
    193196
     
    195198    """ We don't want course container breadcrumbs.
    196199    """
    197     grok.context(interfaces.ICertificateCourse)
     200    grok.context(ICertificateCourse)
    198201    @property
    199202    def title(self):
  • main/waeup.kofa/trunk/src/waeup/kofa/browser/captcha.py

    r8127 r9217  
    2828from zope.interface import Interface
    2929from zope.publisher.interfaces.http import IHTTPRequest
    30 from waeup.kofa.browser import KofaPage, resources
     30from waeup.kofa.browser import resources
     31from waeup.kofa.browser.layout import KofaPage
    3132from waeup.kofa.browser.interfaces import (
    3233    ICaptchaRequest, ICaptchaResponse, ICaptcha, ICaptchaConfig,
  • main/waeup.kofa/trunk/src/waeup/kofa/browser/interfaces.py

    r8257 r9217  
    2121from zope.interface import Interface, Attribute
    2222from waeup.kofa.interfaces import (
    23     IKofaObject, IUniversity, IUsersContainer, IDataCenter)
     23    IKofaObject, IUniversity, IUsersContainer, IDataCenter, validate_email)
     24from waeup.kofa.interfaces import MessageFactory as _
    2425from waeup.kofa.university.interfaces import (
    2526    IFacultiesContainer, IFaculty, IFacultyAdd, IDepartment, IDepartmentAdd,
     
    196197        If no `title` is given, nothing will be rendered.
    197198        """
     199
     200class IChangePassword(IKofaObject):
     201    """Interface needed for change pasword page.
     202
     203    """
     204    identifier = schema.TextLine(
     205        title = _(u'Unique Identifier'),
     206        description = _(
     207            u'User Name, Student or Applicant Id, Matriculation or '
     208            u'Registration Number'),
     209        required = True,
     210        readonly = False,
     211        )
     212
     213    email = schema.ASCIILine(
     214        title = _(u'Email Address'),
     215        required = True,
     216        constraint=validate_email,
     217        )
     218
     219class IStudentNavigationBase(IKofaObject):
     220    """Objects that provide student navigation (whatever it is) should
     221       implement this interface.
     222    """
     223    student = Attribute('''Some student object that has a '''
     224                        ''' `display_fullname` attribute.''')
     225
     226class IApplicantBase(IKofaObject):
     227    """Some Applicant.
     228    """
     229    display_fullname = Attribute('''Fullname.''')
  • main/waeup.kofa/trunk/src/waeup/kofa/browser/layout.py

    r9088 r9217  
    3636from waeup.kofa.interfaces import MessageFactory as _
    3737from waeup.kofa.utils.helpers import to_timezone
    38 from waeup.kofa.browser.interfaces import ITheme
     38from waeup.kofa.browser.interfaces import (
     39    ITheme, IStudentNavigationBase, IApplicantBase)
    3940from waeup.kofa.browser.theming import get_all_themes, KofaThemeBase
    40 from waeup.kofa.students.interfaces import IStudentNavigation
    41 from waeup.kofa.applicants.interfaces import IApplicant
    4241from waeup.kofa.authentication import get_principal_role_manager
    4342
     
    288287        """Return the student name.
    289288        """
    290         if IStudentNavigation.providedBy(self.context):
     289        if IStudentNavigationBase.providedBy(self.context):
    291290            return self.context.student.display_fullname
    292291        return
     
    295294        """Return the applicant name.
    296295        """
    297         if IApplicant.providedBy(self.context):
     296        if IApplicantBase.providedBy(self.context):
     297            # XXX: shouldn't that be `display_fullname???`
    298298            return self.context.fullname
    299299        return
  • main/waeup.kofa/trunk/src/waeup/kofa/browser/pages.py

    r9172 r9217  
    1818""" Viewing components for Kofa objects.
    1919"""
    20 import copy
    2120import csv
    2221import grok
     
    2423import re
    2524import sys
    26 import time
    27 import re
    2825from urllib import urlencode
    2926from zope import schema
     
    3532    getUtilitiesFor,
    3633    )
    37 #from zope.component.interfaces import Invalid
    3834from zope.event import notify
    39 from zope.securitypolicy.interfaces import (
    40     IPrincipalRoleManager, IPrincipalRoleMap)
     35from zope.securitypolicy.interfaces import IPrincipalRoleManager
    4136from zope.session.interfaces import ISession
    4237from zope.password.interfaces import IPasswordManager
    43 from waeup.kofa.browser import (
     38from waeup.kofa.browser.layout import (
    4439    KofaPage, KofaForm, KofaEditFormPage, KofaAddFormPage,
    4540    KofaDisplayFormPage, NullValidator)
     
    4843    IDepartment, IDepartmentAdd, ICourse, ICourseAdd, ICertificate,
    4944    ICertificateAdd, ICertificateCourse, ICertificateCourseAdd,
    50     ICaptchaManager)
     45    ICaptchaManager, IChangePassword)
    5146from waeup.kofa.browser.layout import jsaction, action, UtilityView
    52 from waeup.kofa.browser.resources import warning, datepicker, tabs, datatable
     47from waeup.kofa.browser.resources import (
     48    warning, tabs, datatable)
    5349from waeup.kofa.interfaces import MessageFactory as _
    5450from waeup.kofa.interfaces import(
     
    5652    IKofaXMLImporter, IKofaXMLExporter, IBatchProcessor,
    5753    ILocalRolesAssignable, DuplicationError, IConfigurationContainer,
    58     ISessionConfiguration, ISessionConfigurationAdd,
    59     IPasswordValidator, IContactForm, IKofaUtils, ICSVExporter,
    60     IChangePassword)
     54    ISessionConfiguration, ISessionConfigurationAdd, IJobManager,
     55    IPasswordValidator, IContactForm, IKofaUtils, ICSVExporter,)
    6156from waeup.kofa.permissions import (
    6257    get_users_with_local_roles, get_all_roles, get_all_users)
     58
    6359from waeup.kofa.students.catalog import search as searchstudents
    6460from waeup.kofa.university.catalog import search
    6561from waeup.kofa.university.vocabularies import course_levels
    6662from waeup.kofa.authentication import LocalRoleSetEvent
    67 #from waeup.kofa.widgets.restwidget import ReSTDisplayWidget
    6863from waeup.kofa.widgets.htmlwidget import HTMLDisplayWidget
    69 from waeup.kofa.authentication import get_principal_role_manager
    7064from waeup.kofa.utils.helpers import get_user_account
    7165from waeup.kofa.mandates.mandate import PasswordMandate
     
    797791    def delFiles(self, **data):
    798792        form = self.request.form
    799         logger = self.context.logger
    800793        if form.has_key('val_id'):
    801794            child_id = form['val_id']
     
    11961189        return False
    11971190
    1198     @property
    1199     def nextstep(self):
    1200         return self.url(self.context, '@@import4')
    1201 
    12021191    def update(self, headerfield=None, back2=None, cancel=None, proceed=None):
    12031192        datatable.need()
     
    13901379    label = _('Download portal data as CSV file')
    13911380    pnav = 0
    1392     export_button = _(u'Download')
     1381    export_button = _(u'Create CSV file')
     1382    _running_exports = None
    13931383
    13941384    def getExporters(self):
     
    13981388        return sorted(title_name_tuples)
    13991389
    1400     def update(self, export=None, exporter=None):
    1401         if None in (export, exporter):
    1402             return
    1403         self.redirect(
    1404             self.url(self.context, 'export.csv') + '?exporter=%s' % exporter)
     1390    def job_finished(self, status):
     1391        return status == 'completed'
     1392
     1393    def getRunningExports(self):
     1394        """Returns running exports as list of tuples.
     1395
     1396        Only exports triggered by the current user (identified by
     1397        principal.id) are returned.
     1398
     1399        Each tuple has the form (<STATUS>, <STATUS_TITLE>, <EXPORTER_NAME>).
     1400
     1401        ``STATUS``:
     1402           the status as machine readable string (something like
     1403           ``'completed'``)
     1404
     1405        ``STATUS_TITLE``:
     1406           status of export as translated string.
     1407
     1408        ``EXPORTER_NAME``:
     1409           string representing the exporter title used when triggering
     1410           the export job.
     1411        """
     1412        if self._running_exports is None:
     1413            self._running_exports = self._getRunningExports()
     1414        return self._running_exports
     1415
     1416    def _getRunningExports(self):
     1417        result = self.context.get_export_jobs_status(self.user_id)
     1418        return result
     1419
     1420    def update(self, export=None, start_export=None, exporter=None,
     1421               discard=None, download=None):
     1422        self.user_id = self.request.principal.id
     1423        if discard:
     1424            myjobs = self.context.get_running_export_jobs(self.user_id)
     1425            for entry in myjobs:
     1426                self.context.delete_export_entry(entry)
     1427                self.flash(_('Discarded export result'))
     1428            return
     1429        if download:
     1430            myjobs = self.context.get_running_export_jobs(self.user_id)
     1431            if not len(myjobs):
     1432                self.flash(_('This export was already discarded.'))
     1433                return
     1434            job_id = myjobs[0][0]
     1435            self.redirect(
     1436                self.url(self.context, 'export.csv') + '?job_id=%s' % job_id)
     1437            return
     1438        if None in (start_export, exporter):
     1439            return
     1440        job_id = self.context.start_export_job(
     1441            exporter, self.request.principal.id)
     1442        self.redirect(self.url(self.context, 'export'))
    14051443        return
    14061444
     
    14101448    grok.require('waeup.manageDataCenter')
    14111449
    1412     def render(self, exporter=None):
    1413         if exporter is None:
    1414             return
    1415         ob_class = self.__implemented__.__name__.replace('waeup.kofa.','')
    1416         self.context.logger.info(
    1417             '%s - exported: %s' % (ob_class, exporter))
    1418         exporter = getUtility(ICSVExporter, name=exporter)
    1419         csv_data = exporter.export_all(grok.getSite())
    1420         #csv_data.seek(0)
     1450    def render(self, exporter=None, job_id=None):
     1451
     1452        manager = getUtility(IJobManager)
     1453        job = manager.get(job_id)
     1454        if job is None:
     1455            return
     1456        if hasattr(job.result, 'traceback'):
     1457            # XXX: Some error happened. Do something more approriate here...
     1458            return
     1459        path = job.result
     1460        if not os.path.exists(path):
     1461            # XXX: Do something more appropriate here...
     1462            return
     1463        result = open(path, 'rb').read()
     1464        acronym = grok.getSite()['configuration'].acronym.replace(' ','')
     1465        filename = "%s_%s" % (acronym, os.path.basename(path))
    14211466        self.response.setHeader(
    14221467            'Content-Type', 'text/csv; charset=UTF-8')
    1423         acronym = grok.getSite()['configuration'].acronym.replace(' ','')
    1424         filename = "%s%s.csv" % (acronym, exporter.title.title().replace(' ',''))
    14251468        self.response.setHeader(
    1426             'Content-Disposition:', 'attachment; filename="%s' % filename)
    1427         return csv_data
     1469            'Content-Disposition', 'attachment; filename="%s' % filename)
     1470        # remove job and running_exports entry from context
     1471        self.context.delete_export_entry(
     1472            self.context.entry_from_job_id(job_id))
     1473        return result
    14281474
    14291475class ExportXMLPage(grok.View):
  • main/waeup.kofa/trunk/src/waeup/kofa/browser/resources.py

    r8126 r9217  
    302302    waeup_kofa, 'recaptcha_white.js'
    303303    )
     304
     305#: A page reloader (reloads after 3 secs)
     306page_reloader = ResourceInclusion(
     307    waeup_kofa, 'page_reloader.js', depends=[jquery])
     308
     309#: Disables page reloader (which is triggered by a JavaScript timer).
     310page_not_reloader = ResourceInclusion(
     311    waeup_kofa, 'page_not_reloader.js', depends=[jquery])
     312
     313loadbar = ResourceInclusion(
     314    waeup_kofa, 'loadbar.js', depends=[jquery])
  • main/waeup.kofa/trunk/src/waeup/kofa/browser/templates/datacenterexportpage.pt

    r7974 r9217  
    11<div i18n:domain="waeup.kofa" class="row">
    2   <div class="span4 columns">
    32  <div class="span8 columns">
    4     <p i18n:translate="">Here you can download parts of portal data.</p>
    5     <p i18n:translate="">
    6       Please pick the type of objects you want to export from the
    7       selection below.
    8     </p>
    9   </div>
     3    <div class="span8 columns">
     4      <p i18n:translate="">
     5        Here you can create CSV files from parts of portal data.
     6      </p>
     7      <p i18n:translate="">
     8        Please pick the type of objects you want to export from the
     9        selection below.
     10      </p>
     11      <p i18n:translate="">
     12        The file will be generated and then be made available for you
     13        to download. You must download or discard any existing export
     14        file before creating a new one.
     15      </p>
     16    </div>
    1017
    11   <form  method="POST">
    12     <fieldset>
     18    <form  method="POST">
     19      <fieldset>
    1320        <div class="clearfix">
    14           <label for="exporter">Data Type:</label>
    15           <div class="input">
    16             <select name="exporter">
    17               <span tal:repeat="items view/getExporters" tal:omit-tag="">
    18                 <option
    19                     tal:define="name python: items[1]; title python: items[0]"
    20                     tal:attributes="value name">
    21                   <span tal:replace="title">TITLE</span>
    22                 </option>
     21          <label for="running_exports"
     22                 tal:condition="view/getRunningExports">Running Export:</label>
     23          <div class="input span6">
     24            <div tal:repeat="items view/getRunningExports">
     25              <div>
     26                Data type:
     27                <span tal:content="python: items[2]">exporter</span><br />
     28                Status:
     29                <span tal:content="python: items[1]">status</span><br />
     30                <br /><br />
     31              </div>
     32              <div>
     33                <span tal:condition="not: python: view.job_finished(items[0])">
     34                  <img src=""
     35                       tal:attributes="src static/ajax-loader.gif"
     36                       alt="Loading..."
     37                       class="spinner" />
     38                  <input type="submit" name="reload" value="Reload"
     39                         class="btn primary" />
     40                </span>
     41                <div>
     42                  <span tal:condition="python: view.job_finished(items[0])">
     43                    <input type="submit" name="download" value="Download"
     44                           class="btn primary" />
     45                    <input type="submit" name="discard" value="Discard"
     46                         class="btn secondary" />
     47                  </span>
     48                </div>
     49              </div>
     50            </div>
     51
     52            <div>
     53              <tal:loading_bar content="structure provider:loadingbar" />
     54            </div>
     55          </div>
     56
     57          <div class="clearfix"
     58               tal:condition="not: view/getRunningExports">
     59            <label for="exporter">Data Type:</label>
     60            <div class="input">
     61              <select name="exporter">
     62                <span tal:repeat="items view/getExporters" tal:omit-tag="">
     63                  <option
     64                      tal:define="name python: items[1]; title python: items[0]"
     65                      tal:attributes="value name">
     66                    <span tal:replace="title">TITLE</span>
     67                  </option>
     68                </span>
     69              </select>
     70              <span class="help-inline" i18n:translate="">
     71                Type of objects to export
    2372              </span>
    24             </select>
    25             <span class="help-inline" i18n:translate="">
    26               Type of objects to export
    27             </span>
     73            </div>
    2874          </div>
    29         </div>
    30         <div class="input">
    31           <input i18n:translate="" type="submit" class="btn primary"
    32                  name="export" tal:attributes="value view/export_button" />
     75          <div class="input"
     76               tal:condition="not: view/getRunningExports">
     77            <input i18n:translate="" type="submit" class="btn primary"
     78                   name="start_export"
     79                   tal:attributes="value view/export_button" />
     80          </div>
    3381        </div>
    3482      </fieldset>
  • main/waeup.kofa/trunk/src/waeup/kofa/browser/tests/test_browser.py

    r9034 r9217  
    2121import shutil
    2222import tempfile
    23 import pytz
    24 from datetime import datetime, timedelta
    25 from StringIO import StringIO
    2623import os
    27 import grok
    28 from zope.event import notify
    29 from zope.component import createObject, queryUtility
     24from zc.async.testing import wait_for_result
     25from zope.component import createObject, getUtility
    3026from zope.component.hooks import setSite, clearSite
    31 from zope.catalog.interfaces import ICatalog
    3227from zope.security.interfaces import Unauthorized
    33 from zope.securitypolicy.interfaces import IPrincipalRoleManager
    3428from zope.testbrowser.testing import Browser
    35 from hurry.workflow.interfaces import IWorkflowInfo, IWorkflowState
    3629from waeup.kofa.testing import FunctionalLayer, FunctionalTestCase
    3730from waeup.kofa.app import University
     31from waeup.kofa.interfaces import IJobManager
     32from waeup.kofa.tests.test_async import FunctionalAsyncTestCase
    3833from waeup.kofa.university.faculty import Faculty
    3934from waeup.kofa.university.department import Department
     
    106101        shutil.rmtree(self.dc_root)
    107102
    108 
    109103class DataCenterUITests(UniversitySetup):
    110104    # Tests for DataCenter class views and pages
     
    149143        return
    150144
    151     def test_export(self):
     145
     146class DataCenterUIExportTests(UniversitySetup, FunctionalAsyncTestCase):
     147    # Tests for DataCenter class views and pages
     148
     149    layer = FunctionalLayer
     150
     151    def wait_for_export_job_completed(self):
     152        # helper function waiting until the current export job is completed
     153        manager = getUtility(IJobManager)
     154        job_id = self.app['datacenter'].running_exports[0][0]
     155        job = manager.get(job_id)
     156        wait_for_result(job)
     157        return job_id
     158
     159    def stored_in_datacenter(self, job_id):
     160        # tell whether job_id is stored in datacenter's running jobs list
     161        for entry in list(self.app['datacenter'].running_exports):
     162            if entry[0] == job_id:
     163                return True
     164        return False
     165
     166    def test_export_start(self):
     167        # we can trigger export file creation
    152168        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
    153169        self.browser.open(self.datacenter_path)
     
    156172        self.browser.getLink("Export data").click()
    157173        self.browser.getControl(name="exporter").value = ['faculties']
     174        self.browser.getControl("Create CSV file").click()
     175        self.assertEqual(self.browser.headers['Status'], '200 Ok')
     176        return
     177
     178    def test_export_download(self):
     179        # we can download a generated export result
     180        self.test_export_start()
     181        # while the export file is created, we get a reload button
     182        # (or a loading bar if javascript is enabled)...
     183        self.browser.getControl("Reload").click()
     184        # ...which is displayed as long as the job is not finished.
     185        # When the job is finished and we reload the page...
     186        job_id = self.wait_for_export_job_completed()
     187        try:
     188            self.browser.getControl("Reload").click()
     189        except LookupError:
     190            # if the job completed very fast, we will get the download
     191            # link immediately
     192            pass
     193        # ...we can download the result
    158194        self.browser.getControl("Download").click()
    159         self.assertEqual(self.browser.headers['Status'], '200 Ok')
    160         self.assertEqual(self.browser.headers['Content-Type'],
     195        self.assertEqual(self.browser.headers['content-type'],
    161196                         'text/csv; charset=UTF-8')
    162         self.assertTrue ('WAeUP.KofaFaculties.csv' in
    163             self.browser.headers['content-disposition'])
     197        self.assertEqual(self.browser.headers['content-disposition'],
     198                         'attachment; filename="WAeUP.Kofa_faculties.csv')
    164199        self.assertEqual(self.browser.contents,
    165200            'code,title,title_prefix,users_with_local_roles\r\n'
    166201            'fac1,Unnamed Faculty,faculty,[]\r\n')
    167         logfile = os.path.join(
    168             self.app['datacenter'].storage, 'logs', 'datacenter.log')
    169         logcontent = open(logfile).read()
    170         self.assertTrue('zope.mgr - browser.pages.ExportCSVView - '
    171                         'exported: faculties' in logcontent)
     202
     203        # after download, the job and the result file are removed
     204        manager = getUtility(IJobManager)
     205        result = manager.get(job_id)
     206        self.assertEqual(result, None)
     207        self.assertEqual(self.stored_in_datacenter(job_id), False)
     208        #logfile = os.path.join(
     209        #    self.app['datacenter'].storage, 'logs', 'datacenter.log')
     210        #logcontent = open(logfile).read()
     211        #self.assertTrue('zope.mgr - browser.pages.ExportCSVView - '
     212        #                'exported: faculties' in logcontent)
     213        return
     214
     215    def test_export_discard(self):
     216        # we can discard a generated export result
     217        self.test_export_start()
     218        self.wait_for_export_job_completed()
     219        self.browser.open(self.datacenter_path + '/@@export')
     220        self.browser.getControl("Discard").click()
     221        self.assertTrue('Discarded export result' in self.browser.contents)
    172222        return
    173223
Note: See TracChangeset for help on using the changeset viewer.