Index: main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/browser/batchprocessing.txt
===================================================================
--- main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/browser/batchprocessing.txt	(revision 9209)
+++ main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/browser/batchprocessing.txt	(revision 9211)
@@ -75,5 +75,5 @@
 
     >>> import cStringIO
-    >>> browser.getLink('Upload data').click()
+    >>> browser.getLink('Upload CSV file').click()
     >>> filecontents = cStringIO.StringIO(
     ...   open('faculties.csv', 'rb').read())
@@ -84,5 +84,5 @@
 Step 1: start batch processing:
 
-    >>> browser.getLink('Process data').click()
+    >>> browser.getLink('Batch processing').click()
     >>> button = lookup_submit_value(
     ...   'select', 'faculties_zope.mgr.csv', browser)
@@ -97,10 +97,7 @@
     'Course Processor', 'CourseTicket Processor',
     'Department Processor', 'Faculty Processor',
-    'Hostel Processor',
-    'Student Payment Processor', 'Student Processor',
+    'Payment Processor', 'Student Processor',
     'StudentStudyCourse Processor (update only)',
-    'StudentStudyLevel Processor',
-    'User Processor',
-    'Verdict Processor (update only)']
+    'StudentStudyLevel Processor', 'Verdict Processor (update only)']
 
     >>> importerselect.getControl('Faculty Processor').selected = True
@@ -178,5 +175,5 @@
 
     >>> import cStringIO
-    >>> browser.getLink('Upload data').click()
+    >>> browser.getLink('Upload CSV file').click()
     >>> filecontents = cStringIO.StringIO(
     ...   open('departments.csv', 'rb').read())
@@ -187,5 +184,5 @@
 Step 1: start batch processing:
 
-    >>> browser.getLink('Process data').click()
+    >>> browser.getLink('Batch processing').click()
     >>> button = lookup_submit_value(
     ...   'select', 'departments_zope.mgr.csv', browser)
@@ -243,5 +240,5 @@
 
     >>> import cStringIO
-    >>> browser.getLink('Upload data').click()
+    >>> browser.getLink('Upload CSV file').click()
     >>> filecontents = cStringIO.StringIO(
     ...   open('courses.csv', 'rb').read())
@@ -252,5 +249,5 @@
 Step 1: start batch processing:
 
-    >>> browser.getLink('Process data').click()
+    >>> browser.getLink('Batch processing').click()
     >>> button = lookup_submit_value(
     ...   'select', 'courses_zope.mgr.csv', browser)
@@ -308,5 +305,5 @@
 
     >>> import cStringIO
-    >>> browser.getLink('Upload data').click()
+    >>> browser.getLink('Upload CSV file').click()
     >>> filecontents = cStringIO.StringIO(
     ...   open('certificates.csv', 'rb').read())
@@ -317,5 +314,5 @@
 Step 1: start batch processing:
 
-    >>> browser.getLink('Process data').click()
+    >>> browser.getLink('Batch processing').click()
     >>> button = lookup_submit_value(
     ...   'select', 'certificates_zope.mgr.csv', browser)
@@ -374,5 +371,5 @@
 
     >>> import cStringIO
-    >>> browser.getLink('Upload data').click()
+    >>> browser.getLink('Upload CSV file').click()
     >>> filecontents = cStringIO.StringIO(
     ...   open('mycertcourses.csv', 'rb').read())
@@ -383,5 +380,5 @@
 Step 1: start batch processing:
 
-    >>> browser.getLink('Process data').click()
+    >>> browser.getLink('Batch processing').click()
     >>> button = lookup_submit_value(
     ...   'select', 'mycertcourses_zope.mgr.csv', browser)
@@ -423,68 +420,4 @@
     ...File:...mycertcourses_zope.mgr.csv...
 
-Batch processing users
-======================
-
-    >>> browser.open('http://localhost/app/datacenter')
-
-Prepare a CSV file for users:
-
-    >>> open('users.csv', 'wb').write(
-    ... """name,title,public_name,email,phone,roles
-    ... uli,Uli Fouquet,Chief Developer,uli@abc.de,+49-234-567
-    ... henrik,Henrik Bettermann,Admin,henrik@abc.de,+49-234-567,['waeup.PortalManager']
-    ... """)
-
-Upload the file:
-
-    >>> import cStringIO
-    >>> browser.getLink('Upload data').click()
-    >>> filecontents = cStringIO.StringIO(
-    ...   open('users.csv', 'rb').read())
-    >>> filewidget = browser.getControl(name='uploadfile:file')
-    >>> filewidget.add_file(filecontents, 'text/plain', 'users.csv')
-    >>> browser.getControl(name='SUBMIT').click()
-
-Step 1: start batch processing:
-
-    >>> browser.getLink('Process data').click()
-    >>> button = lookup_submit_value(
-    ...   'select', 'users_zope.mgr.csv', browser)
-    >>> button.click()
-
-Step 2: select a processor and mode:
-
-    >>> importerselect = browser.getControl(name='importer')
-    >>> importerselect.getControl('User Processor').selected = True
-    >>> modeselect = browser.getControl(name='mode')
-    >>> modeselect.getControl(value='create').selected = True
-    >>> browser.getControl('Proceed to step 3').click()
-
-Step 3: Fix headerlines
-
-We get informed that there are no problems with the current header:
-
-    >>> print browser.contents
-    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
-    ...
-    Header fields OK
-    ...
-
-The submit button is enabled:
-
-    >>> browser.getControl('Perform import').disabled
-    False
-
-    >>> browser.getControl('Perform import').click()
-
-Step 4: See import results
-
-The import was successful:
-
-    >>> print browser.contents
-    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
-    ...Successfully processed 2 rows...
-    ...Batch processing finished...
-    ...File:...users_zope.mgr.csv...
 
 Pending files
@@ -511,5 +444,5 @@
 
     >>> import cStringIO
-    >>> browser.getLink('Upload data').click()
+    >>> browser.getLink('Upload CSV file').click()
     >>> filecontents = cStringIO.StringIO(
     ...   open('newfaculties.csv', 'rb').read())
@@ -520,5 +453,5 @@
 Step 1: start batch processing:
 
-    >>> browser.getLink('Process data').click()
+    >>> browser.getLink('Batch processing').click()
     >>> button = lookup_submit_value(
     ...   'select', 'newfaculties_zope.mgr.csv', browser)
@@ -582,5 +515,5 @@
 
     >>> browser.open('http://localhost/app/datacenter')
-    >>> browser.getLink('Process data').click()
+    >>> browser.getLink('Batch processing').click()
     >>> button = lookup_submit_value(
     ...   'select', 'newfaculties_zope.mgr.create.pending.csv', browser)
@@ -618,12 +551,7 @@
     >>> sorted(os.listdir(dc_path + '/finished'))
     ['certificates_zope.mgr.create.finished.csv', ...,
-    'users_zope.mgr.create.finished.csv', 'users_zope.mgr.csv']
-
-Processed (finished) Files
-==========================
-
-    >>> browser.open('http://localhost/app/datacenter/processed')
-    >>> '<a href="download?filename=finished/certificates_zope.mgr.csv">' in browser.contents
-    True
+     'newfaculties_zope.mgr.create.finished.csv',
+     'newfaculties_zope.mgr.csv']
+
 
 Log Files
Index: main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/browser/browser.txt
===================================================================
--- main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/browser/browser.txt	(revision 9209)
+++ main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/browser/browser.txt	(revision 9211)
@@ -81,5 +81,5 @@
   >>> browser.getControl(name="form.identifier").value = 'forgetful'
   >>> browser.getControl(name="form.email").value = 'aa@aa.ng'
-  >>> browser.getControl("Send login credentials").click()
+  >>> browser.getControl("Get login credentials").click()
   >>> print browser.contents
   <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"...
@@ -1000,5 +1000,5 @@
 with their code as key.
 
-Each certificate provides a ``Add certificate course`` action button near top.
+Each certificate provides a ``Add course referrer`` action button near top.
 
 Certificates provide an add-form to add new certcourses:
@@ -1006,5 +1006,5 @@
   >>> cert_url = dept_url + '/certificates/CERT1'
   >>> browser.open(cert_url + '/manage')
-  >>> browser.getControl('Add certificate course').click()
+  >>> browser.getControl('Add course referrer').click()
   >>> print browser.contents
   <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"...
@@ -1025,5 +1025,5 @@
   >>> ctrl.getControl('COURSE1').selected = True
   >>> browser.getControl(name='form.level').value = ['100']
-  >>> browser.getControl('Add certificate course').click()
+  >>> browser.getControl('Add course referrer').click()
 
 Our certificatecourse will be linked on the parent certificate page:
@@ -1038,10 +1038,10 @@
   >>> cert_url = dept_url + '/certificates/CERT1'
   >>> browser.open(cert_url + '/manage')
-  >>> browser.getControl('Add certificate course').click()
+  >>> browser.getControl('Add course referrer').click()
   >>> ctrl = browser.getControl(name='form.course')
   >>> ctrl.getControl('COURSE1').selected = True
   >>> browser.getControl(name='form.level').value = ['100']
-  >>> browser.getControl('Add certificate course').click()
-  >>> 'The chosen certificate course is already' in browser.contents
+  >>> browser.getControl('Add course referrer').click()
+  >>> 'The chosen course referrer is already' in browser.contents
   True
 
@@ -1063,5 +1063,5 @@
 
   >>> browser.open(cert_url + '/COURSE1_100')
-  >>> browser.getLink('Edit certificate course').click()
+  >>> browser.getLink('Edit course referrer').click()
 
 If we just click 'Save and return' nothing will change:
@@ -1088,5 +1088,5 @@
 changed:
 
-  >>> browser.getLink('Edit certificate course').click()
+  >>> browser.getLink('Edit course referrer').click()
   >>> browser.getControl(name='form.level').value = ['400']
   >>> browser.getControl('Cancel').click()
@@ -1125,10 +1125,10 @@
   >>> 'COURSE1_200</a>' in browser.contents
   True
-  >>> browser.getControl('Remove selected certificate courses').click()
+  >>> browser.getControl('Remove selected course referrers').click()
   >>> 'No item selected' in browser.contents
   True
   >>> browser.getControl(name='val_id').getControl(
   ...    value='COURSE1_200').selected = True
-  >>> browser.getControl('Remove selected certificate courses').click()
+  >>> browser.getControl('Remove selected course referrers').click()
   >>> 'Successfully removed: COURSE1_200' in browser.contents
   True
@@ -1218,5 +1218,5 @@
 page:
 
-  >>> browser.getLink('Upload data').click()
+  >>> browser.getLink('Upload CSV file').click()
 
 and enter the appropriate data in the form:
Index: main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/browser/layout.py
===================================================================
--- main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/browser/layout.py	(revision 9209)
+++ main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/browser/layout.py	(revision 9211)
@@ -191,5 +191,4 @@
     grok.baseclass()
     template = default_waeup_display_template
-    hide_hint = True
 
 class KofaEditFormPage(UtilityView,EditForm):
@@ -216,11 +215,5 @@
         if self.widgets.get('perm_address'):
             self.widgets['perm_address'].cssClass = 'span8'
-            self.widgets['perm_address'].height = 6
-        if self.widgets.get('next_kin_address'):
-            self.widgets['next_kin_address'].cssClass = 'span8'
-            self.widgets['next_kin_address'].height = 6
-        if self.widgets.get('notice'):
-            self.widgets['notice'].cssClass = 'span8'
-            self.widgets['notice'].height = 6
+            self.widgets['perm_address'].height = 10
         if self.widgets.get('description'):
             self.widgets['description'].cssClass = 'span12'
@@ -313,13 +306,4 @@
         else:
             return None
-            
-    def formatTZDate(self,datetimeobj):
-        if isinstance(datetimeobj, datetime):
-            tz = getUtility(IKofaUtils).tzinfo
-            date = to_timezone(
-                datetimeobj, tz).strftime("%d/%m/%Y")
-            return date
-        else:
-            return None          
 
     def update(self):
Index: main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/browser/pages.py
===================================================================
--- main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/browser/pages.py	(revision 9209)
+++ main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/browser/pages.py	(revision 9211)
@@ -18,4 +18,5 @@
 """ Viewing components for Kofa objects.
 """
+import copy
 import csv
 import grok
@@ -23,5 +24,6 @@
 import re
 import sys
-from urllib import urlencode
+import time
+import re
 from zope import schema
 from zope.authentication.interfaces import (
@@ -32,8 +34,9 @@
     getUtilitiesFor,
     )
+#from zope.component.interfaces import Invalid
 from zope.event import notify
-from zope.securitypolicy.interfaces import IPrincipalRoleManager
+from zope.securitypolicy.interfaces import (
+    IPrincipalRoleManager, IPrincipalRoleMap)
 from zope.session.interfaces import ISession
-from zope.password.interfaces import IPasswordManager
 from waeup.kofa.browser.layout import (
     KofaPage, KofaForm, KofaEditFormPage, KofaAddFormPage,
@@ -46,5 +49,5 @@
 from waeup.kofa.browser.layout import jsaction, action, UtilityView
 from waeup.kofa.browser.resources import (
-    warning, tabs, datatable)
+    warning, datepicker, tabs, datatable, page_reloader, page_not_reloader)
 from waeup.kofa.interfaces import MessageFactory as _
 from waeup.kofa.interfaces import(
@@ -61,7 +64,8 @@
 from waeup.kofa.university.vocabularies import course_levels
 from waeup.kofa.authentication import LocalRoleSetEvent
+#from waeup.kofa.widgets.restwidget import ReSTDisplayWidget
 from waeup.kofa.widgets.htmlwidget import HTMLDisplayWidget
-from waeup.kofa.utils.helpers import get_user_account
-from waeup.kofa.mandates.mandate import PasswordMandate
+from waeup.kofa.authentication import get_principal_role_manager
+from waeup.kofa.utils.helpers import get_user_account, msave
 
 grok.context(IKofaObject)
@@ -152,17 +156,4 @@
     return
 
-# Save function used for save methods in pages
-def msave(view, **data):
-    changed_fields = view.applyData(view.context, **data)
-    # Turn list of lists into single list
-    if changed_fields:
-        changed_fields = reduce(lambda x,y: x+y, changed_fields.values())
-    fields_string = ' + '.join(changed_fields)
-    view.flash(_('Form has been saved.'))
-    ob_class = view.__implemented__.__name__.replace('waeup.kofa.','')
-    if fields_string:
-        grok.getSite().logger.info('%s - %s - saved: %s' % (ob_class, view.context.__name__, fields_string))
-    return
-
 #
 # Login/logout and language switch pages...
@@ -201,16 +192,5 @@
                 self.redirect(self.camefrom)
                 return
-            # Display appropriate flash message if credentials are correct
-            # but student has been deactivated.
-            login = self.request.form['form.login']
-            if len(login) == 8 and grok.getSite()['students'].has_key(login):
-                student = grok.getSite()['students'][
-                    self.request.form['form.login']]
-                password = self.request.form['form.password']
-                passwordmanager = getUtility(IPasswordManager, 'SSHA')
-                if passwordmanager.checkPassword(student.password, password):
-                    self.flash(_('Your account has been deactivated.'))
-                    return
-            self.flash(_('You entered invalid credentials.'))
+            self.flash(_('You entered wrong credentials.'))
 
 
@@ -392,4 +372,34 @@
     def entries(self):
         return ()
+
+class ReindexPage(UtilityView, grok.View):
+    """ Reindex view.
+
+    Reindexes a catalog. For managers only.
+    """
+    grok.context(IUniversity)
+    grok.name('reindex')
+    grok.require('waeup.managePortal')
+
+    def update(self,ctlg=None):
+        if ctlg is None:
+            self.flash('No catalog name provided.')
+            return
+        cat = queryUtility(ICatalog, name='%s_catalog' % ctlg)
+        if cat is None:
+            self.flash('%s_catalog does not exist' % ctlg)
+            return
+        self.context.logger.info(
+            'Catalog `%s_catalog` re-indexing started.' % ctlg)
+        cat.updateIndexes()
+        no_of_entries = cat.values()[0].documentCount()
+        self.flash('%d %s re-indexed.' % (no_of_entries,ctlg))
+        self.context.logger.info(
+            'Re-indexing of %d objects finished.' % no_of_entries)
+        return
+
+    def render(self):
+        self.redirect(self.url(self.context, '@@index'))
+        return
 
 #
@@ -791,4 +801,5 @@
     def delFiles(self, **data):
         form = self.request.form
+        logger = self.context.logger
         if form.has_key('val_id'):
             child_id = form['val_id']
@@ -815,20 +826,9 @@
         return
 
-class DatacenterFinishedPage(KofaEditFormPage):
-    grok.context(IDataCenter)
-    grok.name('processed')
-    grok.require('waeup.manageDataCenter')
-    label = _(u'Processed Files')
-    pnav = 0
-
-    def update(self):
-        datatable.need()
-        return super(DatacenterFinishedPage, self).update()
-
 class DatacenterUploadPage(KofaPage):
     grok.context(IDataCenter)
     grok.name('upload')
     grok.require('waeup.manageDataCenter')
-    label = _(u'Upload portal data as CSV file')
+    label = _(u'Upload file')
     pnav = 0
     upload_button =_(u'Upload')
@@ -849,13 +849,6 @@
                 self.flash(_("Only csv files are allowed."))
                 return
-            normalized_filename = self.getNormalizedFileName(filename)
-            finished_file = os.path.join(
-                self.context.storage, 'finished', normalized_filename)
-            unfinished_file = os.path.join(
-                self.context.storage, 'unfinished', normalized_filename)
-            if os.path.exists(finished_file) or os.path.exists(unfinished_file):
-                self.flash(_("File with same name was uploaded earlier."))
-                return
-            target = os.path.join(self.context.storage, normalized_filename)
+            target = os.path.join(self.context.storage,
+                                  self.getNormalizedFileName(filename))
             open(target, 'wb').write(uploadfile.read())
             os.chmod(target, 0664)
@@ -888,25 +881,4 @@
         return '%s_%s%s' % (base, filtered_username, ext.lower())
 
-    def getImporters(self):
-        importers = getAllUtilitiesRegisteredFor(IBatchProcessor)
-        importer_props = []
-        for x in importers:
-            iface_fields = schema.getFields(x.iface)
-            available_fields = []
-            for key in iface_fields.keys():
-                iface_fields[key] = (iface_fields[key].__class__.__name__,
-                    iface_fields[key].required)
-            for value in x.available_fields:
-                available_fields.append(
-                    dict(f_name=value,
-                         f_type=iface_fields.get(value, (None, False))[0],
-                         f_required=iface_fields.get(value, (None, False))[1]
-                         )
-                    )
-            available_fields = sorted(available_fields, key=lambda k: k['f_name'])
-            importer_props.append(
-                dict(title=x.name, name=x.util_name, fields=available_fields))
-        return sorted(importer_props, key=lambda k: k['title'])
-
 class FileDownloadView(UtilityView, grok.View):
     grok.context(IDataCenter)
@@ -925,31 +897,8 @@
             'Content-Type', 'text/csv; charset=UTF-8')
         self.response.setHeader(
-            'Content-Disposition:', 'attachment; filename="%s' %
-            self.filename.replace('finished/',''))
+            'Content-Disposition:', 'attachment; filename="%s.csv' %
+            self.filename.replace('.csv',''))
         fullpath = os.path.join(self.context.storage, self.filename)
         return open(fullpath, 'rb').read()
-
-class SkeletonDownloadView(UtilityView, grok.View):
-    grok.context(IDataCenter)
-    grok.name('skeleton')
-    grok.require('waeup.manageDataCenter')
-
-    def update(self, processorname=None):
-        self.processorname = self.request.form['name']
-        self.filename = ('%s_000.csv' %
-            self.processorname.replace('processor','import'))
-        return
-
-    def render(self):
-        #ob_class = self.__implemented__.__name__.replace('waeup.kofa.','')
-        #self.context.logger.info(
-        #    '%s - skeleton downloaded: %s' % (ob_class, self.filename))
-        self.response.setHeader(
-            'Content-Type', 'text/csv; charset=UTF-8')
-        self.response.setHeader(
-            'Content-Disposition:', 'attachment; filename="%s' % self.filename)
-        processor = getUtility(IBatchProcessor, name=self.processorname)
-        csv_data = processor.get_csv_skeleton()
-        return csv_data
 
 class DatacenterImportStep1(KofaPage):
@@ -965,5 +914,5 @@
 
     def getFiles(self):
-        files = self.context.getPendingFiles(sort='date')
+        files = self.context.getFiles(sort='date')
         for file in files:
             name = file.name
@@ -1189,4 +1138,8 @@
         return False
 
+    @property
+    def nextstep(self):
+        return self.url(self.context, '@@import4')
+
     def update(self, headerfield=None, back2=None, cancel=None, proceed=None):
         datatable.need()
@@ -1409,4 +1362,10 @@
            string representing the exporter title used when triggering
            the export job.
+
+        Calling this method also installs a JavaScript page reloader
+        that reloads the page after some time (1.5 secs), if there is
+        a running export that is not completed yet.
+
+        The method caches results.
         """
         if self._running_exports is None:
@@ -1416,4 +1375,9 @@
     def _getRunningExports(self):
         result = self.context.get_export_jobs_status(self.user_id)
+        uncompleted = [x for x in result if x[0] != 'completed']
+        #if len(uncompleted):
+        #    page_reloader.need()
+        #else:
+        #    page_not_reloader.need()
         return result
 
@@ -1462,10 +1426,6 @@
             return
         result = open(path, 'rb').read()
-        acronym = grok.getSite()['configuration'].acronym.replace(' ','')
-        filename = "%s_%s" % (acronym, os.path.basename(path))
         self.response.setHeader(
             'Content-Type', 'text/csv; charset=UTF-8')
-        self.response.setHeader(
-            'Content-Disposition', 'attachment; filename="%s' % filename)
         # remove job and running_exports entry from context
         self.context.delete_export_entry(
@@ -2027,6 +1987,6 @@
     grok.template('certificatemanagepage')
     taboneactions = [_('Save'),_('Cancel')]
-    tabtwoactions = [_('Add certificate course'),
-                     _('Remove selected certificate courses'),_('Cancel')]
+    tabtwoactions = [_('Add course referrer'),
+                     _('Remove selected course referrers'),_('Cancel')]
     tabthreeactions1 = [_('Remove selected local roles')]
     tabthreeactions2 = [_('Add local role')]
@@ -2051,10 +2011,10 @@
         return msave(self, **data)
 
-    @jsaction(_('Remove selected certificate courses'))
+    @jsaction(_('Remove selected course referrers'))
     def delCertificateCourses(self, **data):
         delSubobjects(self, redirect='@@manage', tab='2')
         return
 
-    @action(_('Add certificate course'), validator=NullValidator)
+    @action(_('Add course referrer'), validator=NullValidator)
     def addCertificateCourse(self, **data):
         self.redirect(self.url(self.context, 'addcertificatecourse'))
@@ -2093,16 +2053,16 @@
     form_fields = grok.AutoFields(ICertificateCourseAdd)
     pnav = 1
-    label = _('Add certificate course')
-
-    @action(_('Add certificate course'))
+    label = _('Add course referrer')
+
+    @action(_('Add course referrer'))
     def addCertcourse(self, **data):
         try:
-            self.context.addCertCourse(**data)
+            self.context.addCourseRef(**data)
         except KeyError:
-            self.status = self.flash(_('The chosen certificate course is already '
+            self.status = self.flash(_('The chosen course referrer is already '
                                   'part of this certificate.'))
             return
         self.status = self.flash(
-            _("certificate course ${a}_${b} added.",
+            _("Course referrer ${a}_${b} added.",
             mapping = {'a': data['course'].code, 'b': data['level']}))
         code = "%s_%s" % (data['course'].code, data['level'])
@@ -2145,5 +2105,5 @@
     grok.require('waeup.manageAcademics')
     form_fields = grok.AutoFields(ICertificateCourse)
-    label = _('Edit certificate course')
+    label = _('Edit course referrer')
     pnav = 1
 
@@ -2158,6 +2118,6 @@
             old_level = self.context.level
             data['course'] = self.context.course
-            parent.addCertCourse(**data)
-            parent.delCertCourse(data['course'].code, level=old_level)
+            parent.addCourseRef(**data)
+            parent.delCourseRef(data['course'].code, level=old_level)
             self.flash(_('Form has been saved.'))
             old_code = "%s_%s" % (data['course'].code, old_level)
@@ -2218,5 +2178,5 @@
         return None
 
-    @action(_('Send login credentials to email address'), style='primary')
+    @action(_('Get login credentials'), style='primary')
     def request(self, **data):
         if not self.captcha_result.is_valid:
@@ -2233,17 +2193,11 @@
         # Change password
         kofa_utils = getUtility(IKofaUtils)
-        password = kofa_utils.genPassword()
-        mandate = PasswordMandate()
-        mandate.params['password'] = password
-        mandate.params['user'] = user
-        site = grok.getSite()
-        site['mandates'].addMandate(mandate)
-        # Send email with credentials
-        args = {'mandate_id':mandate.mandate_id}
-        mandate_url = self.url(site) + '/mandate?%s' % urlencode(args)
-        url_info = u'Confirmation link: %s' % mandate_url
-        msg = _('You have successfully requested a password for the')
+        pwd = kofa_utils.genPassword()
+        IUserAccount(user).setPassword(pwd)
+        # Send email with new redentials
+        msg = _('You have successfully changed your password for the')
+        login_url = self.url(grok.getSite(), 'login')
         success = kofa_utils.sendCredentials(
-            IUserAccount(user),password,url_info,msg)
+            IUserAccount(user),pwd,login_url,msg)
         if success:
             self.flash(_('An email with your user name and password ' +
Index: main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/browser/pdf.py
===================================================================
--- main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/browser/pdf.py	(revision 9209)
+++ main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/browser/pdf.py	(revision 9211)
@@ -83,17 +83,12 @@
 
     Main things fixed here:
-    If html code:
+
     - remove newlines (not visible in HTML but visible in PDF)
     - add <br> tags after <div> (as divs break lines in HTML but not in PDF)
-    If not html code:
-    - just replace newlines by <br> tags
     """
-    if '</' in html:
-        # Add br tag if widgets contain div tags
-        # which are not supported by reportlab
-        html = html.replace('</div>', '</div><br />')
-        html = html.replace('\n', '')
-    else:
-        html = html.replace('\n', '<br />')
+    # Add br tag if widgets contain div tags
+    # which are not supported by reportlab
+    html = html.replace('</div>', '</div><br />')
+    html = html.replace('\n', '')
     return html
 
@@ -270,9 +265,5 @@
                                 target_language=lang)
             f_label = Paragraph(f_label, ENTRY1_STYLE)
-            f_text = translate(widget(), domain, target_language=lang)
-            f_text = format_html(f_text)
-            if f_text:
-                hint = ' <font size=9>' + widget.hint + '</font>'
-                f_text = f_text + hint
+            f_text = format_html(widget())
             f_text = Paragraph(f_text, ENTRY1_STYLE)
             table_data.append([f_label,f_text])
Index: main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/browser/static/datatable.js
===================================================================
--- main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/browser/static/datatable.js	(revision 9209)
+++ main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/browser/static/datatable.js	(revision 9211)
@@ -1,20 +1,8 @@
 $(document).ready(function(){
-  $('.dataTable').dataTable();
-
-	$('.dataTableFiles').dataTable( {
-		"aaSorting": [[ 2, "desc" ]],
-	} );
-
+    $('.dataTable').dataTable();
 	$('.dataTableManage').dataTable( {
 		"aaSorting": [[ 1, "asc" ]],
 		"aoColumnDefs":[{ "bSortable": false, "aTargets": [ 0 ] }]
 	} );
-
-	$('.dataTableManageFiles').dataTable( {
-		"aaSorting": [[ 3, "desc" ]],
-		"aoColumnDefs":[{ "bSortable": false, "aTargets": [ 0 ] }]
-	} );
-
-
 });
 
Index: main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/browser/static/jquery.dataTables.min.js
===================================================================
--- main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/browser/static/jquery.dataTables.min.js	(revision 9209)
+++ main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/browser/static/jquery.dataTables.min.js	(revision 9211)
@@ -15,7 +15,4 @@
  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
  * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
- *
- * Customized by Henrik Bettermann: this.aLengthMenu, this._iDisplayLength, this._iDisplayEnd
- *
  */
 (function(j,ra,p){j.fn.dataTableSettings=[];var D=j.fn.dataTableSettings;j.fn.dataTableExt={};var n=j.fn.dataTableExt;n.sVersion="1.7.6";n.sErrMode="alert";n.iApiIndex=0;n.oApi={};n.afnFiltering=[];n.aoFeatures=[];n.ofnSearch={};n.afnSortData=[];n.oStdClasses={sPagePrevEnabled:"paginate_enabled_previous",sPagePrevDisabled:"paginate_disabled_previous",sPageNextEnabled:"paginate_enabled_next",sPageNextDisabled:"paginate_disabled_next",sPageJUINext:"",sPageJUIPrev:"",sPageButton:"paginate_button",sPageButtonActive:"paginate_active",
@@ -41,5 +38,5 @@
 [];this.aoColumns=[];this.iNextId=0;this.asDataSearch=[];this.oPreviousSearch={sSearch:"",bRegex:false,bSmart:true};this.aoPreSearchCols=[];this.aaSorting=[[0,"asc",0]];this.aaSortingFixed=null;this.asStripClasses=[];this.asDestoryStrips=[];this.sDestroyWidth=0;this.fnFooterCallback=this.fnHeaderCallback=this.fnRowCallback=null;this.aoDrawCallback=[];this.fnInitComplete=null;this.sTableId="";this.nTableWrapper=this.nTBody=this.nTFoot=this.nTHead=this.nTable=null;this.bInitialised=false;this.aoOpenRows=
 [];this.sDom="lfrtip";this.sPaginationType="two_button";this.iCookieDuration=7200;this.sCookiePrefix="SpryMedia_DataTables_";this.fnCookieCallback=null;this.aoStateSave=[];this.aoStateLoad=[];this.sAjaxSource=this.oLoadedState=null;this.bAjaxDataGet=true;this.fnServerData=function(a,b,c){j.ajax({url:a,data:b,success:c,dataType:"json",cache:false,error:function(d,f){f=="parsererror"&&alert("DataTables warning: JSON data from server could not be parsed. This is caused by a JSON formatting error.")}})};
-this.fnFormatNumber=function(a){if(a<1E3)return a;else{var b=a+"";a=b.split("");var c="";b=b.length;for(var d=0;d<b;d++){if(d%3===0&&d!==0)c=","+c;c=a[b-d-1]+c}}return c};this.aLengthMenu=[10,25,50,100,1000,5000];this.bDrawing=this.iDraw=0;this.iDrawError=-1;this._iDisplayLength=1000;this._iDisplayStart=0;this._iDisplayEnd=1000;this._iRecordsDisplay=this._iRecordsTotal=0;this.bJUI=false;this.oClasses=n.oStdClasses;this.bSorted=this.bFiltered=false;this.oInit=null}function r(a){return function(){var b=[A(this[n.iApiIndex])].concat(Array.prototype.slice.call(arguments));
+this.fnFormatNumber=function(a){if(a<1E3)return a;else{var b=a+"";a=b.split("");var c="";b=b.length;for(var d=0;d<b;d++){if(d%3===0&&d!==0)c=","+c;c=a[b-d-1]+c}}return c};this.aLengthMenu=[10,25,50,100,1000,5000];this.bDrawing=this.iDraw=0;this.iDrawError=-1;this._iDisplayLength=10;this._iDisplayStart=0;this._iDisplayEnd=10;this._iRecordsDisplay=this._iRecordsTotal=0;this.bJUI=false;this.oClasses=n.oStdClasses;this.bSorted=this.bFiltered=false;this.oInit=null}function r(a){return function(){var b=[A(this[n.iApiIndex])].concat(Array.prototype.slice.call(arguments));
 return n.oApi[a].apply(this,b)}}function s(a){var b,c;if(a.bInitialised===false)setTimeout(function(){s(a)},200);else{sa(a);U(a);K(a,true);a.oFeatures.bAutoWidth&&$(a);b=0;for(c=a.aoColumns.length;b<c;b++)if(a.aoColumns[b].sWidth!==null)a.aoColumns[b].nTh.style.width=v(a.aoColumns[b].sWidth);if(a.oFeatures.bSort)O(a);else{a.aiDisplay=a.aiDisplayMaster.slice();E(a);C(a)}if(a.sAjaxSource!==null&&!a.oFeatures.bServerSide)a.fnServerData.call(a.oInstance,a.sAjaxSource,[],function(d){for(b=0;b<d.aaData.length;b++)u(a,
 d.aaData[b]);a.iInitDisplayStart=a._iDisplayStart;if(a.oFeatures.bSort)O(a);else{a.aiDisplay=a.aiDisplayMaster.slice();E(a);C(a)}K(a,false);w(a,d)});else if(!a.oFeatures.bServerSide){K(a,false);w(a)}}}function w(a,b){a._bInitComplete=true;if(typeof a.fnInitComplete=="function")typeof b!="undefined"?a.fnInitComplete.call(a.oInstance,a,b):a.fnInitComplete.call(a.oInstance,a)}function y(a,b,c){o(a.oLanguage,b,"sProcessing");o(a.oLanguage,b,"sLengthMenu");o(a.oLanguage,b,"sEmptyTable");o(a.oLanguage,
Index: main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/browser/templates/actionbutton.pt
===================================================================
--- main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/browser/templates/actionbutton.pt	(revision 9209)
+++ main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/browser/templates/actionbutton.pt	(revision 9211)
@@ -1,4 +1,4 @@
 <a class="btn actionbar" tal:condition="viewlet/target_url"
-   tal:attributes="href viewlet/target_url; onclick viewlet/onclick">
+   tal:attributes="href viewlet/target_url">
   <img src="" alt="edit"
    tal:attributes="src viewlet/icon_url;
Index: main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/browser/templates/certificatemanagepage.pt
===================================================================
--- main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/browser/templates/certificatemanagepage.pt	(revision 9209)
+++ main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/browser/templates/certificatemanagepage.pt	(revision 9211)
@@ -4,5 +4,5 @@
   <ul class="tabs" data-tabs="tabs">
     <li tal:attributes="class view/tab1"><a href="#tab-1" i18n:translate="">Settings</a></li>
-    <li tal:attributes="class view/tab2"><a href="#tab-2" i18n:translate="">Certificate Courses</a></li>
+    <li tal:attributes="class view/tab2"><a href="#tab-2" i18n:translate="">Course Referrers</a></li>
     <li tal:attributes="class view/tab3"><a href="#tab-3" i18n:translate="">Local Roles</a></li>
   </ul>
@@ -24,17 +24,11 @@
     </div>
     <div id="tab-2" tal:attributes="class view/tab2">
-      <h3>
-        <span tal:content="context/__name__">Code</span>
-        <span i18n:domain="waeup.kofa" i18n:translate="">Courses</span>
-      </h3>
+      <h3 i18n:translate="">Course Referrers</h3>
       <table class="display dataTableManage">
         <thead>
           <tr>
-            <th>&nbsp;</th>
-            <th i18n:translate="">Level</th>
-            <th i18n:translate="">Semester</th>
-            <th i18n:translate="">Cert. Course</th>
-            <th i18n:translate="">Dep. Course</th>
-            <th i18n:translate="">Title</th>
+            <th>&nbsp;</th><th i18n:translate="">Level</th>
+            <th i18n:translate="">Semester</th><th i18n:translate="">Referrer</th>
+            <th i18n:translate="">Course</th><th i18n:translate="">Title</th>
             <th i18n:translate="">Mandatory</th>
           </tr>
@@ -43,5 +37,6 @@
           <tr tal:repeat="cc context/values" class="gradeC">
              <td>
-              <input type="checkbox" name="val_id"
+              <input type="checkbox"
+        		 name="val_id"
         		 tal:attributes="value cc/__name__" />
             </td>
Index: main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/browser/templates/certificatepage.pt
===================================================================
--- main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/browser/templates/certificatepage.pt	(revision 9209)
+++ main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/browser/templates/certificatepage.pt	(revision 9211)
@@ -20,5 +20,5 @@
 <h3>
   <span tal:content="context/__name__">Code</span>
-  <span i18n:domain="waeup.kofa" i18n:translate="">Courses</span>
+  <span i18n:domain="waeup.kofa" i18n:translate="">Course Referrers</span>
 </h3>
 <br />
@@ -26,10 +26,7 @@
 <thead>
   <tr>
-    <th i18n:translate="">Level</th>
-    <th i18n:translate="">Semester</th>
-    <th i18n:translate="">Cert. Course</th>
-    <th i18n:translate="">Dep. Course</th>
-    <th i18n:translate="">Title</th>
-    <th i18n:translate="">Mandatory</th>
+    <th i18n:translate="">Level</th><th i18n:translate="">Semester</th>
+    <th i18n:translate="">Referrer</th><th i18n:translate="">Course</th>
+    <th i18n:translate="">Title</th><th i18n:translate="">Mandatory</th>
   </tr>
 </thead>
Index: main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/browser/templates/datacenterfinishedpage.pt
===================================================================
--- main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/browser/templates/datacenterfinishedpage.pt	(revision 9209)
+++ 	(revision )
@@ -1,17 +1,0 @@
-<table i18n:domain="waeup.kofa" class="display dataTableFiles">
-  <thead>
-    <tr>
-      <th i18n:translate="">File</th>
-      <th i18n:translate="">Datasets</th>
-      <th i18n:translate="">Upload Date</th>
-    </tr>
-  </thead>
-  <tbody>
-    <tr tal:repeat="file context/getFinishedFiles" class="gradeC">
-      <td><a tal:attributes="href python: 'download?filename=' + file.rel_path"
-             tal:content="file/name">FILENAME</a></td>
-      <td tal:content="python: file.lines-1">12 k</td>
-      <td tal:content="file/uploaddate">Mar 12, 2008</td>
-    </tr>
-  </tbody>
-</table>
Index: main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/browser/templates/datacenterpage.pt
===================================================================
--- main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/browser/templates/datacenterpage.pt	(revision 9209)
+++ main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/browser/templates/datacenterpage.pt	(revision 9211)
@@ -11,15 +11,15 @@
 <form action="." tal:attributes="action request/URL" method="post"
       i18n:domain="waeup.kofa" enctype="multipart/form-data">
-    <table i18n:domain="waeup.kofa" class="display dataTableManageFiles">
+    <table i18n:domain="waeup.kofa" class="display dataTableManage">
       <thead>
         <tr>
           <th></th>
           <th i18n:translate="">File</th>
-          <th i18n:translate="">Datasets</th>
+          <th i18n:translate="">Size</th>
           <th i18n:translate="">Upload Date</th>
         </tr>
       </thead>
       <tbody>
-        <tr tal:repeat="file context/getPendingFiles" class="gradeC">
+        <tr tal:repeat="file context/getFiles" class="gradeC">
           <td>
             <input type="checkbox" name="val_id"
@@ -28,5 +28,5 @@
           <td><a tal:attributes="href python: 'download?filename=' + file.name"
                  tal:content="file/name">FILENAME</a></td>
-          <td tal:content="python: file.lines - 1">100</td>
+          <td tal:content="file/size">12 k</td>
           <td tal:content="file/uploaddate">Mar 12, 2008</td>
         </tr>
Index: main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/browser/templates/datacenteruploadpage.pt
===================================================================
--- main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/browser/templates/datacenteruploadpage.pt	(revision 9209)
+++ main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/browser/templates/datacenteruploadpage.pt	(revision 9211)
@@ -9,56 +9,2 @@
   </div>
 </form>
-
-<br /><br />
-
-<h2 i18n:translate="">Available Processors (Importers)</h2>
-
-<table i18n:domain="waeup.kofa">
-  <thead>
-    <tr>
-      <th i18n:translate="">Processor</th>
-      <th i18n:translate="">Required Schema Fields</th>
-      <th i18n:translate="">Optional Schema Fields</th>
-      <th i18n:translate="">Non-Schema Fields</th>
-      <th i18n:translate="">CSV Skeleton File</th>
-    </tr>
-  </thead>
-  <tr tal:repeat="importer view/getImporters">
-    <td tal:content="importer/title"></td>
-    <td nowrap>
-      <span tal:repeat="field importer/fields">
-          <tal:schemafield condition="field/f_type">
-            <tal:required condition="field/f_required">
-              <span tal:replace="field/f_name"></span>
-              (<span tal:replace="field/f_type"></span>)
-              <br />
-            </tal:required>
-          </tal:schemafield>
-      </span>
-    </td>
-    <td nowrap>
-      <span tal:repeat="field importer/fields">
-          <tal:schemafield condition="field/f_type">
-            <tal:notrequired condition="not:field/f_required">
-              <span tal:replace="field/f_name"></span>
-              (<span tal:replace="field/f_type"></span>)
-              <br />
-            </tal:notrequired>
-          </tal:schemafield>
-      </span>
-    </td>
-    <td>
-      <span tal:repeat="field importer/fields">
-          <tal:extrafield condition="not:field/f_type">
-            <span tal:replace="field/f_name"></span>
-            <br />
-          </tal:extrafield>
-      </span>
-    </td>
-
-    <td>
-      <a i18n:translate=""
-         tal:attributes="href python: 'skeleton?name=' + importer['name']">Download</a>
-    </td>
-  </tr>
-</table>
Index: main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/browser/templates/loginpage.pt
===================================================================
--- main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/browser/templates/loginpage.pt	(revision 9209)
+++ main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/browser/templates/loginpage.pt	(revision 9211)
@@ -37,12 +37,8 @@
     If you are having trouble logging in, make sure to enable  cookies in your web browser.
   </p>
-  <p i18n:translate="login_trouble2" tal:condition="python:False">
+  <p i18n:translate="login_trouble2">
     You don't have an account because you are a fresh student, or your student record has just been created?
-    Acquire a Password Activation Code (PWD) and inititialize your student account
-    <strong><a href ="setpassword"> here</a></strong>.
-  </p>
-  <p i18n:translate="login_trouble4">
-    You don't have an account because you are a fresh student, or your student record has just been created?
-    Inititialize your student account <strong><a href="requestpw"> here</a></strong>.
+    Acquire a Password Access Code (PWD) and inititialize your student account
+    <strong><a href  ="setpassword"> here</a></strong>.
   </p>
   <p i18n:translate="login_trouble3"> Or simply forgot your student id, application id or password? Then request a new password
Index: main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/browser/templates/widgets.pt
===================================================================
--- main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/browser/templates/widgets.pt	(revision 9209)
+++ main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/browser/templates/widgets.pt	(revision 9211)
@@ -18,6 +18,5 @@
         <div tal:content="structure widget/error">ERROR</div>
       </tal:error>
-      <tal:hint
-        tal:condition="python: widget.hint and not getattr(view,'hide_hint',False)">
+      <tal:hint tal:condition="widget/hint">
         <div class="hint" tal:content="structure widget/hint">HINT</div>
       </tal:hint>
Index: main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/browser/tests/test_browser.py
===================================================================
--- main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/browser/tests/test_browser.py	(revision 9209)
+++ main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/browser/tests/test_browser.py	(revision 9211)
@@ -21,10 +21,18 @@
 import shutil
 import tempfile
+import pytz
+from datetime import datetime, timedelta
+from StringIO import StringIO
 import os
+import grok
 from zc.async.testing import wait_for_result
-from zope.component import createObject, getUtility
+from zope.event import notify
+from zope.component import createObject, queryUtility, getUtility
 from zope.component.hooks import setSite, clearSite
+from zope.catalog.interfaces import ICatalog
 from zope.security.interfaces import Unauthorized
+from zope.securitypolicy.interfaces import IPrincipalRoleManager
 from zope.testbrowser.testing import Browser
+from hurry.workflow.interfaces import IWorkflowInfo, IWorkflowState
 from waeup.kofa.testing import FunctionalLayer, FunctionalTestCase
 from waeup.kofa.app import University
@@ -33,4 +41,7 @@
 from waeup.kofa.university.faculty import Faculty
 from waeup.kofa.university.department import Department
+
+
+
 
 SAMPLE_FILE = os.path.join(os.path.dirname(__file__), 'test_file.csv')
@@ -79,5 +90,5 @@
         self.app['faculties']['fac1']['dep1'].courses.addCourse(
             self.course)
-        self.app['faculties']['fac1']['dep1'].certificates['CERT1'].addCertCourse(
+        self.app['faculties']['fac1']['dep1'].certificates['CERT1'].addCourseRef(
             self.course, level=100)
 
@@ -116,5 +127,5 @@
         self.assertEqual(self.browser.headers['Status'], '200 Ok')
         self.assertEqual(self.browser.url, self.datacenter_path)
-        self.browser.getLink("Upload data").click()
+        self.browser.getLink("Upload CSV file").click()
         file = open(SAMPLE_FILE)
         ctrl = self.browser.getControl(name='uploadfile:file')
@@ -170,5 +181,5 @@
         self.assertEqual(self.browser.headers['Status'], '200 Ok')
         self.assertEqual(self.browser.url, self.datacenter_path)
-        self.browser.getLink("Export data").click()
+        self.browser.getLink("Export CSV file").click()
         self.browser.getControl(name="exporter").value = ['faculties']
         self.browser.getControl("Create CSV file").click()
@@ -193,11 +204,8 @@
         # ...we can download the result
         self.browser.getControl("Download").click()
-        self.assertEqual(self.browser.headers['content-type'],
+        self.assertEqual(self.browser.headers['Content-Type'],
                          'text/csv; charset=UTF-8')
-        self.assertEqual(self.browser.headers['content-disposition'],
-                         'attachment; filename="WAeUP.Kofa_faculties.csv')
         self.assertEqual(self.browser.contents,
-            'code,title,title_prefix,users_with_local_roles\r\n'
-            'fac1,Unnamed Faculty,faculty,[]\r\n')
+            'code,title,title_prefix\r\nfac1,Unnamed Faculty,faculty\r\n')
 
         # after download, the job and the result file are removed
@@ -221,17 +229,2 @@
         self.assertTrue('Discarded export result' in self.browser.contents)
         return
-
-    def test_skeleton_download(self):
-        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
-        self.browser.open(self.datacenter_path)
-        self.browser.getLink("Upload data").click()
-        self.assertTrue(
-            '<a href="skeleton?name=facultyprocessor">Download</a>'
-            in self.browser.contents)
-        self.browser.getLink(url='skeleton?name=facultyprocessor').click()
-        self.assertEqual(self.browser.headers['Status'], '200 Ok')
-        self.assertEqual(self.browser.headers['Content-Type'],
-                         'text/csv; charset=UTF-8')
-        self.assertEqual(self.browser.contents,
-            'code,local_roles,title,title_prefix\r\n')
-        return
Index: main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/browser/tests/test_permissions.py
===================================================================
--- main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/browser/tests/test_permissions.py	(revision 9209)
+++ main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/browser/tests/test_permissions.py	(revision 9211)
@@ -91,5 +91,5 @@
         cert.code = 'cert1'
         dept.certificates.addCertificate(cert)
-        cert.addCertCourse(course)
+        cert.addCourseRef(course)
 
         self.browser = Browser()
Index: main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/browser/viewlets.py
===================================================================
--- main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/browser/viewlets.py	(revision 9209)
+++ main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/browser/viewlets.py	(revision 9211)
@@ -66,7 +66,6 @@
     """A base for action buttons.
 
-    An action button provides an icon, some text, links to a
-    target and optionally an onclick event handler.
-    If you want to set a different text, icon or target name
+    An action button provides an icon, some text and links to a
+    target.  If you want to set a different text, icon or target name
     for some active button below, just override the approriate
     attribute in the concerned viewlet.
@@ -83,7 +82,4 @@
      * ``target_url``
           The URL of the link target.
-
-     * ``onclick``
-          An onclick Javascript event handler.
 
     """
@@ -147,10 +143,4 @@
         return self.view.url(self.view.context, self.target)
 
-    @property
-    def onclick(self):
-        """Onclick event...
-        """
-        return
-
 class PlainActionButton(ActionButton):
     """A base for action buttons without image
@@ -396,5 +386,4 @@
     grok.require('waeup.manageDataCenter')
     text = _('Edit settings')
-    grok.order(1)
 
 class ManageFacultiesContainerActionButton(ManageActionButton):
@@ -467,5 +456,9 @@
     grok.context(ICertificateCourse)
     grok.view(CertificateCoursePage)
-    text = _('Edit certificate course')
+    text = _('Edit course referrer')
+
+#
+# Add actions...
+#
 
 class AddUserActionButton(AddActionButton):
@@ -475,12 +468,36 @@
     text = _('Add user')
 
-class BrowseDatacenterLogs(ActionButton):
+#
+# Actions with a 'browse' icon...
+#
+class BrowseActionButton(ActionButton):
+    grok.baseclass()
+    grok.context(IKofaObject)
+    grok.template('actionbutton')
+    grok.viewletmanager(ActionBar)
+    grok.require('waeup.manageDataCenter')
+    icon = 'actionicon_manage.png' # File must exist in static/
+    target = '@@show' # link to this viewname.
+    text = _('Show logs') # Text to display on the button
+
+class BrowseDatacenterLogs(BrowseActionButton):
     grok.context(IDataCenter)
-    grok.require('waeup.manageDataCenter')
     grok.view(DatacenterPage)
-    grok.order(2)
+    grok.order(4)
     icon = 'actionicon_info.png'
     target = '@@logs'
     text = _('Show logs')
+
+#
+# Misc. buttons...
+#
+class BatchOpButton(ActionButton):
+    grok.context(IDataCenter)
+    grok.view(DatacenterPage)
+    grok.require('waeup.importData')
+    grok.order(6)
+    icon = 'actionicon_gear.png'
+    target = '@@import1'
+    text = _('Batch processing')
 
 class UploadCSVButton(ActionButton):
@@ -488,17 +505,8 @@
     grok.view(DatacenterPage)
     grok.require('waeup.manageDataCenter')
-    grok.order(3)
+    grok.order(5)
     icon = 'actionicon_up.png'
     target = '@@upload'
-    text = _('Upload data')
-
-class BatchOpButton(ActionButton):
-    grok.context(IDataCenter)
-    grok.view(DatacenterPage)
-    grok.require('waeup.importData')
-    grok.order(4)
-    icon = 'actionicon_gear.png'
-    target = '@@import1'
-    text = _('Process data')
+    text = _('Upload CSV file')
 
 class ExportCSVButton(ActionButton):
@@ -506,17 +514,8 @@
     grok.view(DatacenterPage)
     grok.require('waeup.manageDataCenter')
-    grok.order(5)
+    grok.order(7)
     icon = 'actionicon_down.png'
     target = '@@export'
-    text = _('Export data')
-
-class BrowseFinishedFiles(ActionButton):
-    grok.context(IDataCenter)
-    grok.require('waeup.manageDataCenter')
-    grok.view(DatacenterPage)
-    grok.order(6)
-    icon = 'actionicon_finished.png'
-    target = '@@processed'
-    text = _('View processed files')
+    text = _('Export CSV file')
 
 #
