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

Merge changes from trunk, r8786-HEAD

Location:
main/waeup.kofa/branches/uli-async-update
Files:
17 edited
5 copied

Legend:

Unmodified
Added
Removed
  • main/waeup.kofa/branches/uli-async-update

  • main/waeup.kofa/branches/uli-async-update/src/waeup/kofa/browser/batchprocessing.txt

    r8472 r9169  
    7575
    7676    >>> import cStringIO
    77     >>> browser.getLink('Upload CSV file').click()
     77    >>> browser.getLink('Upload data').click()
    7878    >>> filecontents = cStringIO.StringIO(
    7979    ...   open('faculties.csv', 'rb').read())
     
    8484Step 1: start batch processing:
    8585
    86     >>> browser.getLink('Batch processing').click()
     86    >>> browser.getLink('Process data').click()
    8787    >>> button = lookup_submit_value(
    8888    ...   'select', 'faculties_zope.mgr.csv', browser)
     
    9797    'Course Processor', 'CourseTicket Processor',
    9898    'Department Processor', 'Faculty Processor',
    99     'Payment Processor', 'Student Processor',
     99    'Student Payment Processor', 'Student Processor',
    100100    'StudentStudyCourse Processor (update only)',
    101     'StudentStudyLevel Processor', 'Verdict Processor (update only)']
     101    'StudentStudyLevel Processor',
     102    'User Processor',
     103    'Verdict Processor (update only)']
    102104
    103105    >>> importerselect.getControl('Faculty Processor').selected = True
     
    175177
    176178    >>> import cStringIO
    177     >>> browser.getLink('Upload CSV file').click()
     179    >>> browser.getLink('Upload data').click()
    178180    >>> filecontents = cStringIO.StringIO(
    179181    ...   open('departments.csv', 'rb').read())
     
    184186Step 1: start batch processing:
    185187
    186     >>> browser.getLink('Batch processing').click()
     188    >>> browser.getLink('Process data').click()
    187189    >>> button = lookup_submit_value(
    188190    ...   'select', 'departments_zope.mgr.csv', browser)
     
    240242
    241243    >>> import cStringIO
    242     >>> browser.getLink('Upload CSV file').click()
     244    >>> browser.getLink('Upload data').click()
    243245    >>> filecontents = cStringIO.StringIO(
    244246    ...   open('courses.csv', 'rb').read())
     
    249251Step 1: start batch processing:
    250252
    251     >>> browser.getLink('Batch processing').click()
     253    >>> browser.getLink('Process data').click()
    252254    >>> button = lookup_submit_value(
    253255    ...   'select', 'courses_zope.mgr.csv', browser)
     
    305307
    306308    >>> import cStringIO
    307     >>> browser.getLink('Upload CSV file').click()
     309    >>> browser.getLink('Upload data').click()
    308310    >>> filecontents = cStringIO.StringIO(
    309311    ...   open('certificates.csv', 'rb').read())
     
    314316Step 1: start batch processing:
    315317
    316     >>> browser.getLink('Batch processing').click()
     318    >>> browser.getLink('Process data').click()
    317319    >>> button = lookup_submit_value(
    318320    ...   'select', 'certificates_zope.mgr.csv', browser)
     
    371373
    372374    >>> import cStringIO
    373     >>> browser.getLink('Upload CSV file').click()
     375    >>> browser.getLink('Upload data').click()
    374376    >>> filecontents = cStringIO.StringIO(
    375377    ...   open('mycertcourses.csv', 'rb').read())
     
    380382Step 1: start batch processing:
    381383
    382     >>> browser.getLink('Batch processing').click()
     384    >>> browser.getLink('Process data').click()
    383385    >>> button = lookup_submit_value(
    384386    ...   'select', 'mycertcourses_zope.mgr.csv', browser)
     
    420422    ...File:...mycertcourses_zope.mgr.csv...
    421423
     424Batch processing users
     425======================
     426
     427    >>> browser.open('http://localhost/app/datacenter')
     428
     429Prepare a CSV file for certificate courses:
     430
     431    >>> open('users.csv', 'wb').write(
     432    ... """name,title,public_name,email,phone,roles
     433    ... uli,Uli Fouquet,Chief Developer,uli@abc.de,+49-234-567
     434    ... henrik, Henrik Bettermann,Admin,henrik@abc.de,+49-234-567,['waeup.PortalManager']
     435    ... """)
     436
     437Upload the file:
     438
     439    >>> import cStringIO
     440    >>> browser.getLink('Upload data').click()
     441    >>> filecontents = cStringIO.StringIO(
     442    ...   open('users.csv', 'rb').read())
     443    >>> filewidget = browser.getControl(name='uploadfile:file')
     444    >>> filewidget.add_file(filecontents, 'text/plain', 'users.csv')
     445    >>> browser.getControl(name='SUBMIT').click()
     446
     447Step 1: start batch processing:
     448
     449    >>> browser.getLink('Process data').click()
     450    >>> button = lookup_submit_value(
     451    ...   'select', 'users_zope.mgr.csv', browser)
     452    >>> button.click()
     453
     454Step 2: select a processor and mode:
     455
     456    >>> importerselect = browser.getControl(name='importer')
     457    >>> importerselect.getControl('User Processor').selected = True
     458    >>> modeselect = browser.getControl(name='mode')
     459    >>> modeselect.getControl(value='create').selected = True
     460    >>> browser.getControl('Proceed to step 3').click()
     461
     462Step 3: Fix headerlines
     463
     464We get informed that there are no problems with the current header:
     465
     466    >>> print browser.contents
     467    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
     468    ...
     469    Header fields OK
     470    ...
     471
     472The submit button is enabled:
     473
     474    >>> browser.getControl('Perform import').disabled
     475    False
     476
     477    >>> browser.getControl('Perform import').click()
     478
     479Step 4: See import results
     480
     481The import was successful:
     482
     483    >>> print browser.contents
     484    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
     485    ...Successfully processed 2 rows...
     486    ...Batch processing finished...
     487    ...File:...users_zope.mgr.csv...
    422488
    423489Pending files
     
    444510
    445511    >>> import cStringIO
    446     >>> browser.getLink('Upload CSV file').click()
     512    >>> browser.getLink('Upload data').click()
    447513    >>> filecontents = cStringIO.StringIO(
    448514    ...   open('newfaculties.csv', 'rb').read())
     
    453519Step 1: start batch processing:
    454520
    455     >>> browser.getLink('Batch processing').click()
     521    >>> browser.getLink('Process data').click()
    456522    >>> button = lookup_submit_value(
    457523    ...   'select', 'newfaculties_zope.mgr.csv', browser)
     
    515581
    516582    >>> browser.open('http://localhost/app/datacenter')
    517     >>> browser.getLink('Batch processing').click()
     583    >>> browser.getLink('Process data').click()
    518584    >>> button = lookup_submit_value(
    519585    ...   'select', 'newfaculties_zope.mgr.create.pending.csv', browser)
     
    551617    >>> sorted(os.listdir(dc_path + '/finished'))
    552618    ['certificates_zope.mgr.create.finished.csv', ...,
    553      'newfaculties_zope.mgr.create.finished.csv',
    554      'newfaculties_zope.mgr.csv']
    555 
     619    'users_zope.mgr.create.finished.csv', 'users_zope.mgr.csv']
     620
     621Processed (finished) Files
     622==========================
     623
     624    >>> browser.open('http://localhost/app/datacenter/processed')
     625    >>> '<a href="download?filename=finished/certificates_zope.mgr.csv">' in browser.contents
     626    True
    556627
    557628Log Files
  • main/waeup.kofa/branches/uli-async-update/src/waeup/kofa/browser/browser.txt

    r8777 r9169  
    10001000with their code as key.
    10011001
    1002 Each certificate provides a ``Add course referrer`` action button near top.
     1002Each certificate provides a ``Add certificate course`` action button near top.
    10031003
    10041004Certificates provide an add-form to add new certcourses:
     
    10061006  >>> cert_url = dept_url + '/certificates/CERT1'
    10071007  >>> browser.open(cert_url + '/manage')
    1008   >>> browser.getControl('Add course referrer').click()
     1008  >>> browser.getControl('Add certificate course').click()
    10091009  >>> print browser.contents
    10101010  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"...
     
    10251025  >>> ctrl.getControl('COURSE1').selected = True
    10261026  >>> browser.getControl(name='form.level').value = ['100']
    1027   >>> browser.getControl('Add course referrer').click()
     1027  >>> browser.getControl('Add certificate course').click()
    10281028
    10291029Our certificatecourse will be linked on the parent certificate page:
     
    10381038  >>> cert_url = dept_url + '/certificates/CERT1'
    10391039  >>> browser.open(cert_url + '/manage')
    1040   >>> browser.getControl('Add course referrer').click()
     1040  >>> browser.getControl('Add certificate course').click()
    10411041  >>> ctrl = browser.getControl(name='form.course')
    10421042  >>> ctrl.getControl('COURSE1').selected = True
    10431043  >>> browser.getControl(name='form.level').value = ['100']
    1044   >>> browser.getControl('Add course referrer').click()
    1045   >>> 'The chosen course referrer is already' in browser.contents
     1044  >>> browser.getControl('Add certificate course').click()
     1045  >>> 'The chosen certificate course is already' in browser.contents
    10461046  True
    10471047
     
    10631063
    10641064  >>> browser.open(cert_url + '/COURSE1_100')
    1065   >>> browser.getLink('Edit course referrer').click()
     1065  >>> browser.getLink('Edit certificate course').click()
    10661066
    10671067If we just click 'Save and return' nothing will change:
     
    10881088changed:
    10891089
    1090   >>> browser.getLink('Edit course referrer').click()
     1090  >>> browser.getLink('Edit certificate course').click()
    10911091  >>> browser.getControl(name='form.level').value = ['400']
    10921092  >>> browser.getControl('Cancel').click()
     
    11251125  >>> 'COURSE1_200</a>' in browser.contents
    11261126  True
    1127   >>> browser.getControl('Remove selected course referrers').click()
     1127  >>> browser.getControl('Remove selected certificate courses').click()
    11281128  >>> 'No item selected' in browser.contents
    11291129  True
    11301130  >>> browser.getControl(name='val_id').getControl(
    11311131  ...    value='COURSE1_200').selected = True
    1132   >>> browser.getControl('Remove selected course referrers').click()
     1132  >>> browser.getControl('Remove selected certificate courses').click()
    11331133  >>> 'Successfully removed: COURSE1_200' in browser.contents
    11341134  True
     
    12181218page:
    12191219
    1220   >>> browser.getLink('Upload CSV file').click()
     1220  >>> browser.getLink('Upload data').click()
    12211221
    12221222and enter the appropriate data in the form:
  • main/waeup.kofa/branches/uli-async-update/src/waeup/kofa/browser/layout.py

    r9003 r9169  
    191191    grok.baseclass()
    192192    template = default_waeup_display_template
     193    hide_hint = True
    193194
    194195class KofaEditFormPage(UtilityView,EditForm):
     
    215216        if self.widgets.get('perm_address'):
    216217            self.widgets['perm_address'].cssClass = 'span8'
    217             self.widgets['perm_address'].height = 10
     218            self.widgets['perm_address'].height = 6
     219        if self.widgets.get('next_kin_address'):
     220            self.widgets['next_kin_address'].cssClass = 'span8'
     221            self.widgets['next_kin_address'].height = 6
     222        if self.widgets.get('notice'):
     223            self.widgets['notice'].cssClass = 'span8'
     224            self.widgets['notice'].height = 6
    218225        if self.widgets.get('description'):
    219226            self.widgets['description'].cssClass = 'span12'
     
    306313        else:
    307314            return None
     315           
     316    def formatTZDate(self,datetimeobj):
     317        if isinstance(datetimeobj, datetime):
     318            tz = getUtility(IKofaUtils).tzinfo
     319            date = to_timezone(
     320                datetimeobj, tz).strftime("%d/%m/%Y")
     321            return date
     322        else:
     323            return None         
    308324
    309325    def update(self):
  • main/waeup.kofa/branches/uli-async-update/src/waeup/kofa/browser/pages.py

    r9166 r9169  
    2626import time
    2727import re
     28from urllib import urlencode
    2829from zope import schema
    2930from zope.authentication.interfaces import (
     
    3940    IPrincipalRoleManager, IPrincipalRoleMap)
    4041from zope.session.interfaces import ISession
     42from zope.password.interfaces import IPasswordManager
    4143from waeup.kofa.browser.layout import (
    4244    KofaPage, KofaForm, KofaEditFormPage, KofaAddFormPage,
     
    6769from waeup.kofa.widgets.htmlwidget import HTMLDisplayWidget
    6870from waeup.kofa.authentication import get_principal_role_manager
    69 from waeup.kofa.utils.helpers import get_user_account, msave
     71from waeup.kofa.utils.helpers import get_user_account
     72from waeup.kofa.mandates.mandate import PasswordMandate
    7073
    7174grok.context(IKofaObject)
     
    156159    return
    157160
     161# Save function used for save methods in pages
     162def msave(view, **data):
     163    changed_fields = view.applyData(view.context, **data)
     164    # Turn list of lists into single list
     165    if changed_fields:
     166        changed_fields = reduce(lambda x,y: x+y, changed_fields.values())
     167    fields_string = ' + '.join(changed_fields)
     168    view.flash(_('Form has been saved.'))
     169    ob_class = view.__implemented__.__name__.replace('waeup.kofa.','')
     170    if fields_string:
     171        grok.getSite().logger.info('%s - %s - saved: %s' % (ob_class, view.context.__name__, fields_string))
     172    return
     173
    158174#
    159175# Login/logout and language switch pages...
     
    192208                self.redirect(self.camefrom)
    193209                return
    194             self.flash(_('You entered wrong credentials.'))
     210            # Display appropriate flash message if credentials are correct
     211            # but student has been deactivated.
     212            login = self.request.form['form.login']
     213            if len(login) == 8 and grok.getSite()['students'].has_key(login):
     214                student = grok.getSite()['students'][
     215                    self.request.form['form.login']]
     216                password = self.request.form['form.password']
     217                passwordmanager = getUtility(IPasswordManager, 'SSHA')
     218                if passwordmanager.checkPassword(student.password, password):
     219                    self.flash(_('Your account has been deactivated.'))
     220                    return
     221            self.flash(_('You entered invalid credentials.'))
    195222
    196223
     
    372399    def entries(self):
    373400        return ()
    374 
    375 class ReindexPage(UtilityView, grok.View):
    376     """ Reindex view.
    377 
    378     Reindexes a catalog. For managers only.
    379     """
    380     grok.context(IUniversity)
    381     grok.name('reindex')
    382     grok.require('waeup.managePortal')
    383 
    384     def update(self,ctlg=None):
    385         if ctlg is None:
    386             self.flash('No catalog name provided.')
    387             return
    388         cat = queryUtility(ICatalog, name='%s_catalog' % ctlg)
    389         if cat is None:
    390             self.flash('%s_catalog does not exist' % ctlg)
    391             return
    392         self.context.logger.info(
    393             'Catalog `%s_catalog` re-indexing started.' % ctlg)
    394         cat.updateIndexes()
    395         no_of_entries = cat.values()[0].documentCount()
    396         self.flash('%d %s re-indexed.' % (no_of_entries,ctlg))
    397         self.context.logger.info(
    398             'Re-indexing of %d objects finished.' % no_of_entries)
    399         return
    400 
    401     def render(self):
    402         self.redirect(self.url(self.context, '@@index'))
    403         return
    404401
    405402#
     
    826823        return
    827824
     825class DatacenterFinishedPage(KofaEditFormPage):
     826    grok.context(IDataCenter)
     827    grok.name('processed')
     828    grok.require('waeup.manageDataCenter')
     829    label = _(u'Processed Files')
     830    pnav = 0
     831
     832    def update(self):
     833        datatable.need()
     834        return super(DatacenterFinishedPage, self).update()
     835
    828836class DatacenterUploadPage(KofaPage):
    829837    grok.context(IDataCenter)
    830838    grok.name('upload')
    831839    grok.require('waeup.manageDataCenter')
    832     label = _(u'Upload file')
     840    label = _(u'Upload portal data as CSV file')
    833841    pnav = 0
    834842    upload_button =_(u'Upload')
     
    849857                self.flash(_("Only csv files are allowed."))
    850858                return
    851             target = os.path.join(self.context.storage,
    852                                   self.getNormalizedFileName(filename))
     859            normalized_filename = self.getNormalizedFileName(filename)
     860            finished_file = os.path.join(
     861                self.context.storage, 'finished', normalized_filename)
     862            unfinished_file = os.path.join(
     863                self.context.storage, 'unfinished', normalized_filename)
     864            if os.path.exists(finished_file) or os.path.exists(unfinished_file):
     865                self.flash(_("File with same name was uploaded earlier."))
     866                return
     867            target = os.path.join(self.context.storage, normalized_filename)
    853868            open(target, 'wb').write(uploadfile.read())
    854869            os.chmod(target, 0664)
     
    881896        return '%s_%s%s' % (base, filtered_username, ext.lower())
    882897
     898    def getImporters(self):
     899        importers = getAllUtilitiesRegisteredFor(IBatchProcessor)
     900        importer_props = []
     901        for x in importers:
     902            iface_fields = schema.getFields(x.iface)
     903            available_fields = []
     904            for key in iface_fields.keys():
     905                iface_fields[key] = (iface_fields[key].__class__.__name__,
     906                    iface_fields[key].required)
     907            for value in x.available_fields:
     908                available_fields.append(
     909                    dict(f_name=value,
     910                         f_type=iface_fields.get(value, (None, False))[0],
     911                         f_required=iface_fields.get(value, (None, False))[1]
     912                         )
     913                    )
     914            available_fields = sorted(available_fields, key=lambda k: k['f_name'])
     915            importer_props.append(
     916                dict(title=x.name, name=x.util_name, fields=available_fields))
     917        return sorted(importer_props, key=lambda k: k['title'])
     918
    883919class FileDownloadView(UtilityView, grok.View):
    884920    grok.context(IDataCenter)
     
    897933            'Content-Type', 'text/csv; charset=UTF-8')
    898934        self.response.setHeader(
    899             'Content-Disposition:', 'attachment; filename="%s.csv' %
    900             self.filename.replace('.csv',''))
     935            'Content-Disposition:', 'attachment; filename="%s' %
     936            self.filename.replace('finished/',''))
    901937        fullpath = os.path.join(self.context.storage, self.filename)
    902938        return open(fullpath, 'rb').read()
     939
     940class SkeletonDownloadView(UtilityView, grok.View):
     941    grok.context(IDataCenter)
     942    grok.name('skeleton')
     943    grok.require('waeup.manageDataCenter')
     944
     945    def update(self, processorname=None):
     946        self.processorname = self.request.form['name']
     947        self.filename = ('%s_000.csv' %
     948            self.processorname.replace('processor','import'))
     949        return
     950
     951    def render(self):
     952        #ob_class = self.__implemented__.__name__.replace('waeup.kofa.','')
     953        #self.context.logger.info(
     954        #    '%s - skeleton downloaded: %s' % (ob_class, self.filename))
     955        self.response.setHeader(
     956            'Content-Type', 'text/csv; charset=UTF-8')
     957        self.response.setHeader(
     958            'Content-Disposition:', 'attachment; filename="%s' % self.filename)
     959        processor = getUtility(IBatchProcessor, name=self.processorname)
     960        csv_data = processor.get_csv_skeleton()
     961        return csv_data
    903962
    904963class DatacenterImportStep1(KofaPage):
     
    914973
    915974    def getFiles(self):
    916         files = self.context.getFiles(sort='date')
     975        files = self.context.getPendingFiles(sort='date')
    917976        for file in files:
    918977            name = file.name
     
    14261485            return
    14271486        result = open(path, 'rb').read()
     1487        acronym = grok.getSite()['configuration'].acronym.replace(' ','')
     1488        filename = "%s%s.csv" % (
     1489            acronym, exporter.title.title().replace(' ',''))
     1490        self.response.setHeader(
     1491            'Content-Disposition:', 'attachment; filename="%s' % filename)
    14281492        self.response.setHeader(
    14291493            'Content-Type', 'text/csv; charset=UTF-8')
     
    19872051    grok.template('certificatemanagepage')
    19882052    taboneactions = [_('Save'),_('Cancel')]
    1989     tabtwoactions = [_('Add course referrer'),
    1990                      _('Remove selected course referrers'),_('Cancel')]
     2053    tabtwoactions = [_('Add certificate course'),
     2054                     _('Remove selected certificate courses'),_('Cancel')]
    19912055    tabthreeactions1 = [_('Remove selected local roles')]
    19922056    tabthreeactions2 = [_('Add local role')]
     
    20112075        return msave(self, **data)
    20122076
    2013     @jsaction(_('Remove selected course referrers'))
     2077    @jsaction(_('Remove selected certificate courses'))
    20142078    def delCertificateCourses(self, **data):
    20152079        delSubobjects(self, redirect='@@manage', tab='2')
    20162080        return
    20172081
    2018     @action(_('Add course referrer'), validator=NullValidator)
     2082    @action(_('Add certificate course'), validator=NullValidator)
    20192083    def addCertificateCourse(self, **data):
    20202084        self.redirect(self.url(self.context, 'addcertificatecourse'))
     
    20532117    form_fields = grok.AutoFields(ICertificateCourseAdd)
    20542118    pnav = 1
    2055     label = _('Add course referrer')
    2056 
    2057     @action(_('Add course referrer'))
     2119    label = _('Add certificate course')
     2120
     2121    @action(_('Add certificate course'))
    20582122    def addCertcourse(self, **data):
    20592123        try:
    2060             self.context.addCourseRef(**data)
     2124            self.context.addCertCourse(**data)
    20612125        except KeyError:
    2062             self.status = self.flash(_('The chosen course referrer is already '
     2126            self.status = self.flash(_('The chosen certificate course is already '
    20632127                                  'part of this certificate.'))
    20642128            return
    20652129        self.status = self.flash(
    2066             _("Course referrer ${a}_${b} added.",
     2130            _("certificate course ${a}_${b} added.",
    20672131            mapping = {'a': data['course'].code, 'b': data['level']}))
    20682132        code = "%s_%s" % (data['course'].code, data['level'])
     
    21052169    grok.require('waeup.manageAcademics')
    21062170    form_fields = grok.AutoFields(ICertificateCourse)
    2107     label = _('Edit course referrer')
     2171    label = _('Edit certificate course')
    21082172    pnav = 1
    21092173
     
    21182182            old_level = self.context.level
    21192183            data['course'] = self.context.course
    2120             parent.addCourseRef(**data)
    2121             parent.delCourseRef(data['course'].code, level=old_level)
     2184            parent.addCertCourse(**data)
     2185            parent.delCertCourse(data['course'].code, level=old_level)
    21222186            self.flash(_('Form has been saved.'))
    21232187            old_code = "%s_%s" % (data['course'].code, old_level)
     
    21932257        # Change password
    21942258        kofa_utils = getUtility(IKofaUtils)
    2195         pwd = kofa_utils.genPassword()
    2196         IUserAccount(user).setPassword(pwd)
    2197         # Send email with new redentials
    2198         msg = _('You have successfully changed your password for the')
    2199         login_url = self.url(grok.getSite(), 'login')
     2259        password = kofa_utils.genPassword()
     2260        mandate = PasswordMandate()
     2261        mandate.params['password'] = password
     2262        mandate.params['user'] = user
     2263        site = grok.getSite()
     2264        site['mandates'].addMandate(mandate)
     2265        # Send email with credentials
     2266        args = {'mandate_id':mandate.mandate_id}
     2267        mandate_url = self.url(site) + '/mandate?%s' % urlencode(args)
     2268        url_info = u'Confirmation link: %s' % mandate_url
     2269        msg = _('You have successfully requested a password for the')
    22002270        success = kofa_utils.sendCredentials(
    2201             IUserAccount(user),pwd,login_url,msg)
     2271            IUserAccount(user),password,url_info,msg)
    22022272        if success:
    22032273            self.flash(_('An email with your user name and password ' +
  • main/waeup.kofa/branches/uli-async-update/src/waeup/kofa/browser/pdf.py

    r8257 r9169  
    8383
    8484    Main things fixed here:
    85 
     85    If html code:
    8686    - remove newlines (not visible in HTML but visible in PDF)
    8787    - add <br> tags after <div> (as divs break lines in HTML but not in PDF)
     88    If not html code:
     89    - just replace newlines by <br> tags
    8890    """
    89     # Add br tag if widgets contain div tags
    90     # which are not supported by reportlab
    91     html = html.replace('</div>', '</div><br />')
    92     html = html.replace('\n', '')
     91    if '</' in html:
     92        # Add br tag if widgets contain div tags
     93        # which are not supported by reportlab
     94        html = html.replace('</div>', '</div><br />')
     95        html = html.replace('\n', '')
     96    else:
     97        html = html.replace('\n', '<br />')
    9398    return html
    9499
     
    265270                                target_language=lang)
    266271            f_label = Paragraph(f_label, ENTRY1_STYLE)
    267             f_text = format_html(widget())
     272            f_text = translate(widget(), domain, target_language=lang)
     273            f_text = format_html(f_text)
     274            if f_text:
     275                hint = ' <font size=9>' + widget.hint + '</font>'
     276                f_text = f_text + hint
    268277            f_text = Paragraph(f_text, ENTRY1_STYLE)
    269278            table_data.append([f_label,f_text])
  • main/waeup.kofa/branches/uli-async-update/src/waeup/kofa/browser/static/datatable.js

    r7811 r9169  
    11$(document).ready(function(){
    2     $('.dataTable').dataTable();
     2  $('.dataTable').dataTable();
     3
     4        $('.dataTableFiles').dataTable( {
     5                "aaSorting": [[ 2, "desc" ]],
     6        } );
     7
    38        $('.dataTableManage').dataTable( {
    49                "aaSorting": [[ 1, "asc" ]],
    510                "aoColumnDefs":[{ "bSortable": false, "aTargets": [ 0 ] }]
    611        } );
     12
     13        $('.dataTableManageFiles').dataTable( {
     14                "aaSorting": [[ 3, "desc" ]],
     15                "aoColumnDefs":[{ "bSortable": false, "aTargets": [ 0 ] }]
     16        } );
     17
     18
    719});
    820
  • main/waeup.kofa/branches/uli-async-update/src/waeup/kofa/browser/templates/actionbutton.pt

    r7459 r9169  
    11<a class="btn actionbar" tal:condition="viewlet/target_url"
    2    tal:attributes="href viewlet/target_url">
     2   tal:attributes="href viewlet/target_url; onclick viewlet/onclick">
    33  <img src="" alt="edit"
    44   tal:attributes="src viewlet/icon_url;
  • main/waeup.kofa/branches/uli-async-update/src/waeup/kofa/browser/templates/certificatemanagepage.pt

    r7811 r9169  
    44  <ul class="tabs" data-tabs="tabs">
    55    <li tal:attributes="class view/tab1"><a href="#tab-1" i18n:translate="">Settings</a></li>
    6     <li tal:attributes="class view/tab2"><a href="#tab-2" i18n:translate="">Course Referrers</a></li>
     6    <li tal:attributes="class view/tab2"><a href="#tab-2" i18n:translate="">Certificate Courses</a></li>
    77    <li tal:attributes="class view/tab3"><a href="#tab-3" i18n:translate="">Local Roles</a></li>
    88  </ul>
     
    2424    </div>
    2525    <div id="tab-2" tal:attributes="class view/tab2">
    26       <h3 i18n:translate="">Course Referrers</h3>
     26      <h3>
     27        <span tal:content="context/__name__">Code</span>
     28        <span i18n:domain="waeup.kofa" i18n:translate="">Courses</span>
     29      </h3>
    2730      <table class="display dataTableManage">
    2831        <thead>
    2932          <tr>
    30             <th>&nbsp;</th><th i18n:translate="">Level</th>
    31             <th i18n:translate="">Semester</th><th i18n:translate="">Referrer</th>
    32             <th i18n:translate="">Course</th><th i18n:translate="">Title</th>
     33            <th>&nbsp;</th>
     34            <th i18n:translate="">Level</th>
     35            <th i18n:translate="">Semester</th>
     36            <th i18n:translate="">Cert. Course</th>
     37            <th i18n:translate="">Dep. Course</th>
     38            <th i18n:translate="">Title</th>
    3339            <th i18n:translate="">Mandatory</th>
    3440          </tr>
     
    3743          <tr tal:repeat="cc context/values" class="gradeC">
    3844             <td>
    39               <input type="checkbox"
    40                          name="val_id"
     45              <input type="checkbox" name="val_id"
    4146                         tal:attributes="value cc/__name__" />
    4247            </td>
  • main/waeup.kofa/branches/uli-async-update/src/waeup/kofa/browser/templates/certificatepage.pt

    r7811 r9169  
    2020<h3>
    2121  <span tal:content="context/__name__">Code</span>
    22   <span i18n:domain="waeup.kofa" i18n:translate="">Course Referrers</span>
     22  <span i18n:domain="waeup.kofa" i18n:translate="">Courses</span>
    2323</h3>
    2424<br />
     
    2626<thead>
    2727  <tr>
    28     <th i18n:translate="">Level</th><th i18n:translate="">Semester</th>
    29     <th i18n:translate="">Referrer</th><th i18n:translate="">Course</th>
    30     <th i18n:translate="">Title</th><th i18n:translate="">Mandatory</th>
     28    <th i18n:translate="">Level</th>
     29    <th i18n:translate="">Semester</th>
     30    <th i18n:translate="">Cert. Course</th>
     31    <th i18n:translate="">Dep. Course</th>
     32    <th i18n:translate="">Title</th>
     33    <th i18n:translate="">Mandatory</th>
    3134  </tr>
    3235</thead>
  • main/waeup.kofa/branches/uli-async-update/src/waeup/kofa/browser/templates/datacenterpage.pt

    r8366 r9169  
    1111<form action="." tal:attributes="action request/URL" method="post"
    1212      i18n:domain="waeup.kofa" enctype="multipart/form-data">
    13     <table i18n:domain="waeup.kofa" class="display dataTableManage">
     13    <table i18n:domain="waeup.kofa" class="display dataTableManageFiles">
    1414      <thead>
    1515        <tr>
     
    2121      </thead>
    2222      <tbody>
    23         <tr tal:repeat="file context/getFiles" class="gradeC">
     23        <tr tal:repeat="file context/getPendingFiles" class="gradeC">
    2424          <td>
    2525            <input type="checkbox" name="val_id"
  • main/waeup.kofa/branches/uli-async-update/src/waeup/kofa/browser/templates/datacenteruploadpage.pt

    r7705 r9169  
    99  </div>
    1010</form>
     11
     12<br /><br />
     13
     14<h2 i18n:translate="">Available Processors (Importers)</h2>
     15
     16<table i18n:domain="waeup.kofa">
     17  <thead>
     18    <tr>
     19      <th i18n:translate="">Processor</th>
     20      <th i18n:translate="">Required Schema Fields</th>
     21      <th i18n:translate="">Optional Schema Fields</th>
     22      <th i18n:translate="">Non-Schema Fields</th>
     23      <th i18n:translate="">CSV Skeleton File</th>
     24    </tr>
     25  </thead>
     26  <tr tal:repeat="importer view/getImporters">
     27    <td tal:content="importer/title"></td>
     28    <td nowrap>
     29      <span tal:repeat="field importer/fields">
     30          <tal:schemafield condition="field/f_type">
     31            <tal:required condition="field/f_required">
     32              <span tal:replace="field/f_name"></span>
     33              (<span tal:replace="field/f_type"></span>)
     34              <br />
     35            </tal:required>
     36          </tal:schemafield>
     37      </span>
     38    </td>
     39    <td nowrap>
     40      <span tal:repeat="field importer/fields">
     41          <tal:schemafield condition="field/f_type">
     42            <tal:notrequired condition="not:field/f_required">
     43              <span tal:replace="field/f_name"></span>
     44              (<span tal:replace="field/f_type"></span>)
     45              <br />
     46            </tal:notrequired>
     47          </tal:schemafield>
     48      </span>
     49    </td>
     50    <td>
     51      <span tal:repeat="field importer/fields">
     52          <tal:extrafield condition="not:field/f_type">
     53            <span tal:replace="field/f_name"></span>
     54            <br />
     55          </tal:extrafield>
     56      </span>
     57    </td>
     58
     59    <td>
     60      <a i18n:translate=""
     61         tal:attributes="href python: 'skeleton?name=' + importer['name']">Download</a>
     62    </td>
     63  </tr>
     64</table>
  • main/waeup.kofa/branches/uli-async-update/src/waeup/kofa/browser/templates/loginpage.pt

    r8777 r9169  
    3737    If you are having trouble logging in, make sure to enable  cookies in your web browser.
    3838  </p>
    39   <p i18n:translate="login_trouble2">
     39  <p i18n:translate="login_trouble2" tal:condition="python:False">
    4040    You don't have an account because you are a fresh student, or your student record has just been created?
    41     Acquire a Password Access Code (PWD) and inititialize your student account
    42     <strong><a href  ="setpassword"> here</a></strong>.
     41    Acquire a Password Activation Code (PWD) and inititialize your student account
     42    <strong><a href ="setpassword"> here</a></strong>.
     43  </p>
     44  <p i18n:translate="login_trouble4">
     45    You don't have an account because you are a fresh student, or your student record has just been created?
     46    Inititialize your student account <strong><a href="requestpw"> here</a></strong>.
    4347  </p>
    4448  <p i18n:translate="login_trouble3"> Or simply forgot your student id, application id or password? Then request a new password
  • main/waeup.kofa/branches/uli-async-update/src/waeup/kofa/browser/templates/widgets.pt

    r8045 r9169  
    1818        <div tal:content="structure widget/error">ERROR</div>
    1919      </tal:error>
    20       <tal:hint tal:condition="widget/hint">
     20      <tal:hint
     21        tal:condition="python: widget.hint and not getattr(view,'hide_hint',False)">
    2122        <div class="hint" tal:content="structure widget/hint">HINT</div>
    2223      </tal:hint>
  • main/waeup.kofa/branches/uli-async-update/src/waeup/kofa/browser/tests/test_browser.py

    r9166 r9169  
    9090        self.app['faculties']['fac1']['dep1'].courses.addCourse(
    9191            self.course)
    92         self.app['faculties']['fac1']['dep1'].certificates['CERT1'].addCourseRef(
     92        self.app['faculties']['fac1']['dep1'].certificates['CERT1'].addCertCourse(
    9393            self.course, level=100)
    9494
     
    127127        self.assertEqual(self.browser.headers['Status'], '200 Ok')
    128128        self.assertEqual(self.browser.url, self.datacenter_path)
    129         self.browser.getLink("Upload CSV file").click()
     129        self.browser.getLink("Upload data").click()
    130130        file = open(SAMPLE_FILE)
    131131        ctrl = self.browser.getControl(name='uploadfile:file')
     
    181181        self.assertEqual(self.browser.headers['Status'], '200 Ok')
    182182        self.assertEqual(self.browser.url, self.datacenter_path)
    183         self.browser.getLink("Export CSV file").click()
     183        self.browser.getLink("Export data").click()
    184184        self.browser.getControl(name="exporter").value = ['faculties']
    185185        self.browser.getControl("Create CSV file").click()
     
    206206        self.assertEqual(self.browser.headers['Content-Type'],
    207207                         'text/csv; charset=UTF-8')
     208        self.assertTrue ('WAeUP.KofaFaculties.csv' in
     209            self.browser.headers['content-disposition'])
    208210        self.assertEqual(self.browser.contents,
    209             'code,title,title_prefix\r\nfac1,Unnamed Faculty,faculty\r\n')
     211            'code,title,title_prefix,users_with_local_roles\r\n'
     212            'fac1,Unnamed Faculty,faculty,[]\r\n')
    210213
    211214        # after download, the job and the result file are removed
     
    229232        self.assertTrue('Discarded export result' in self.browser.contents)
    230233        return
     234
     235    def test_skeleton_download(self):
     236        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
     237        self.browser.open(self.datacenter_path)
     238        self.browser.getLink("Upload data").click()
     239        self.assertTrue(
     240            '<a href="skeleton?name=facultyprocessor">Download</a>'
     241            in self.browser.contents)
     242        self.browser.getLink(url='skeleton?name=facultyprocessor').click()
     243        self.assertEqual(self.browser.headers['Status'], '200 Ok')
     244        self.assertEqual(self.browser.headers['Content-Type'],
     245                         'text/csv; charset=UTF-8')
     246        self.assertEqual(self.browser.contents,
     247            'code,local_roles,title,title_prefix\r\n')
     248        return
  • main/waeup.kofa/branches/uli-async-update/src/waeup/kofa/browser/tests/test_permissions.py

    r7811 r9169  
    9191        cert.code = 'cert1'
    9292        dept.certificates.addCertificate(cert)
    93         cert.addCourseRef(course)
     93        cert.addCertCourse(course)
    9494
    9595        self.browser = Browser()
  • main/waeup.kofa/branches/uli-async-update/src/waeup/kofa/browser/viewlets.py

    r8387 r9169  
    6666    """A base for action buttons.
    6767
    68     An action button provides an icon, some text and links to a
    69     target.  If you want to set a different text, icon or target name
     68    An action button provides an icon, some text, links to a
     69    target and optionally an onclick event handler.
     70    If you want to set a different text, icon or target name
    7071    for some active button below, just override the approriate
    7172    attribute in the concerned viewlet.
     
    8283     * ``target_url``
    8384          The URL of the link target.
     85
     86     * ``onclick``
     87          An onclick Javascript event handler.
    8488
    8589    """
     
    143147        return self.view.url(self.view.context, self.target)
    144148
     149    @property
     150    def onclick(self):
     151        """Onclick event...
     152        """
     153        return
     154
    145155class PlainActionButton(ActionButton):
    146156    """A base for action buttons without image
     
    386396    grok.require('waeup.manageDataCenter')
    387397    text = _('Edit settings')
     398    grok.order(1)
    388399
    389400class ManageFacultiesContainerActionButton(ManageActionButton):
     
    456467    grok.context(ICertificateCourse)
    457468    grok.view(CertificateCoursePage)
    458     text = _('Edit course referrer')
    459 
    460 #
    461 # Add actions...
    462 #
     469    text = _('Edit certificate course')
    463470
    464471class AddUserActionButton(AddActionButton):
     
    468475    text = _('Add user')
    469476
    470 #
    471 # Actions with a 'browse' icon...
    472 #
    473 class BrowseActionButton(ActionButton):
    474     grok.baseclass()
    475     grok.context(IKofaObject)
    476     grok.template('actionbutton')
    477     grok.viewletmanager(ActionBar)
     477class BrowseDatacenterLogs(ActionButton):
     478    grok.context(IDataCenter)
    478479    grok.require('waeup.manageDataCenter')
    479     icon = 'actionicon_manage.png' # File must exist in static/
    480     target = '@@show' # link to this viewname.
    481     text = _('Show logs') # Text to display on the button
    482 
    483 class BrowseDatacenterLogs(BrowseActionButton):
    484     grok.context(IDataCenter)
    485480    grok.view(DatacenterPage)
    486     grok.order(4)
     481    grok.order(2)
    487482    icon = 'actionicon_info.png'
    488483    target = '@@logs'
    489484    text = _('Show logs')
    490485
    491 #
    492 # Misc. buttons...
    493 #
     486class UploadCSVButton(ActionButton):
     487    grok.context(IDataCenter)
     488    grok.view(DatacenterPage)
     489    grok.require('waeup.manageDataCenter')
     490    grok.order(3)
     491    icon = 'actionicon_up.png'
     492    target = '@@upload'
     493    text = _('Upload data')
     494
    494495class BatchOpButton(ActionButton):
    495496    grok.context(IDataCenter)
    496497    grok.view(DatacenterPage)
    497498    grok.require('waeup.importData')
    498     grok.order(6)
     499    grok.order(4)
    499500    icon = 'actionicon_gear.png'
    500501    target = '@@import1'
    501     text = _('Batch processing')
    502 
    503 class UploadCSVButton(ActionButton):
     502    text = _('Process data')
     503
     504class ExportCSVButton(ActionButton):
    504505    grok.context(IDataCenter)
    505506    grok.view(DatacenterPage)
    506507    grok.require('waeup.manageDataCenter')
    507508    grok.order(5)
    508     icon = 'actionicon_up.png'
    509     target = '@@upload'
    510     text = _('Upload CSV file')
    511 
    512 class ExportCSVButton(ActionButton):
    513     grok.context(IDataCenter)
    514     grok.view(DatacenterPage)
    515     grok.require('waeup.manageDataCenter')
    516     grok.order(7)
    517509    icon = 'actionicon_down.png'
    518510    target = '@@export'
    519     text = _('Export CSV file')
     511    text = _('Export data')
     512
     513class BrowseFinishedFiles(ActionButton):
     514    grok.context(IDataCenter)
     515    grok.require('waeup.manageDataCenter')
     516    grok.view(DatacenterPage)
     517    grok.order(6)
     518    icon = 'actionicon_finished.png'
     519    target = '@@processed'
     520    text = _('View processed files')
    520521
    521522#
Note: See TracChangeset for help on using the changeset viewer.