source: main/waeup.sirp/trunk/src/waeup/sirp/applicants/browser.py @ 6362

Last change on this file since 6362 was 6360, checked in by Henrik Bettermann, 14 years ago

Now exports passport picture into pdf. libjpeg62-dev must be installed!

File size: 24.5 KB
RevLine 
[5273]1##
2## browser.py
3## Login : <uli@pu.smp.net>
[6153]4## Started on  Sun Jun 27 11:03:10 2010 Uli Fouquet & Henrik Bettermann
[5273]5## $Id$
[6078]6##
[6063]7## Copyright (C) 2010 Uli Fouquet & Henrik Bettermann
[5273]8## This program is free software; you can redistribute it and/or modify
9## it under the terms of the GNU General Public License as published by
10## the Free Software Foundation; either version 2 of the License, or
11## (at your option) any later version.
[6078]12##
[5273]13## This program is distributed in the hope that it will be useful,
14## but WITHOUT ANY WARRANTY; without even the implied warranty of
15## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16## GNU General Public License for more details.
[6078]17##
[5273]18## You should have received a copy of the GNU General Public License
19## along with this program; if not, write to the Free Software
20## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21##
[5824]22"""UI components for basic applicants and related components.
[5273]23"""
[6082]24import sys
[5273]25import grok
26
[6305]27from datetime import datetime
[6081]28from zope.formlib.widget import CustomWidgetFactory
[6358]29from zope.formlib.form import setUpEditWidgets
[5937]30from zope.securitypolicy.interfaces import IPrincipalRoleManager
[6153]31from zope.traversing.browser import absoluteURL
[6081]32
[6303]33from hurry.workflow.interfaces import IWorkflowInfo, IWorkflowState
[6357]34from reportlab.pdfgen import canvas
35
[6359]36from waeup.sirp.accesscodes import invalidate_accesscode
[5273]37from waeup.sirp.browser import (
[6321]38    WAeUPPage, WAeUPEditFormPage, WAeUPAddFormPage, WAeUPDisplayFormPage)
[6081]39from waeup.sirp.browser.breadcrumbs import Breadcrumb
[6103]40from waeup.sirp.browser.layout import NullValidator
[6321]41from waeup.sirp.browser.pages import add_local_role, del_local_roles
[6013]42from waeup.sirp.browser.resources import datepicker, tabs, datatable
[6153]43from waeup.sirp.browser.viewlets import (
44    ManageActionButton, PrimaryNavTab, LeftSidebarLink
45    )
[6081]46from waeup.sirp.image.browser.widget import (
47    ThumbnailWidget, EncodingImageFileWidget,
[5822]48    )
[6184]49from waeup.sirp.interfaces import IWAeUPObject, ILocalRolesAssignable
[6321]50from waeup.sirp.permissions import get_users_with_local_roles
[6254]51from waeup.sirp.university.interfaces import ICertificate
[6054]52from waeup.sirp.widgets.datewidget import (
53    FriendlyDateWidget, FriendlyDateDisplayWidget)
[6084]54from waeup.sirp.widgets.restwidget import ReSTDisplayWidget
[5303]55from waeup.sirp.widgets.objectwidget import (
[5301]56    WAeUPObjectWidget, WAeUPObjectDisplayWidget)
[5303]57from waeup.sirp.widgets.multilistwidget import (
[5273]58    MultiListWidget, MultiListDisplayWidget)
[6153]59from waeup.sirp.applicants import ResultEntry, Applicant, get_applicant_data
[6081]60from waeup.sirp.applicants.interfaces import (
[6321]61    IApplicant, IApplicantPrincipal,IApplicantEdit, IApplicantsRoot,
62    IApplicantsContainer, IApplicantsContainerAdd, application_types_vocab
[5686]63    )
[6353]64from waeup.sirp.applicants.workflow import INITIALIZED, STARTED
[5320]65
[5273]66results_widget = CustomWidgetFactory(
[5301]67    WAeUPObjectWidget, ResultEntry)
[5273]68
69results_display_widget = CustomWidgetFactory(
[5301]70    WAeUPObjectDisplayWidget, ResultEntry)
[5273]71
72list_results_widget = CustomWidgetFactory(
73    MultiListWidget, subwidget=results_widget)
74
75list_results_display_widget = CustomWidgetFactory(
76    MultiListDisplayWidget, subwidget=results_display_widget)
77
[6353]78#TRANSITION_OBJECTS = create_workflow()
[6305]79
[6322]80#TRANSITION_DICT = dict([
81#    (transition_object.transition_id,transition_object.title)
82#    for transition_object in TRANSITION_OBJECTS])
[6305]83
[6067]84class ApplicantsRootPage(WAeUPPage):
[5822]85    grok.context(IApplicantsRoot)
86    grok.name('index')
[6153]87    grok.require('waeup.Public')
[5822]88    title = 'Applicants'
[6069]89    label = 'Application Section'
[5843]90    pnav = 3
[6012]91
92    def update(self):
[6067]93        super(ApplicantsRootPage, self).update()
[6012]94        datatable.need()
95        return
96
[5828]97class ManageApplicantsRootActionButton(ManageActionButton):
98    grok.context(IApplicantsRoot)
[6067]99    grok.view(ApplicantsRootPage)
[6198]100    grok.require('waeup.manageApplications')
[6069]101    text = 'Manage application section'
[5828]102
[6069]103class ApplicantsRootManageFormPage(WAeUPEditFormPage):
[5828]104    grok.context(IApplicantsRoot)
105    grok.name('manage')
[6107]106    grok.template('applicantsrootmanagepage')
[6069]107    title = 'Applicants'
108    label = 'Manage application section'
[5843]109    pnav = 3
[6198]110    grok.require('waeup.manageApplications')
[6069]111    taboneactions = ['Add applicants container', 'Remove selected','Cancel']
[6184]112    tabtwoactions1 = ['Remove selected local roles']
113    tabtwoactions2 = ['Add local role']
[6069]114    subunits = 'Applicants Containers'
[6078]115
[6069]116    def update(self):
117        tabs.need()
[6108]118        datatable.need()
[6069]119        return super(ApplicantsRootManageFormPage, self).update()
[5828]120
[6184]121    def getLocalRoles(self):
122        roles = ILocalRolesAssignable(self.context)
123        return roles()
124
125    def getUsers(self):
126        """Get a list of all users.
127        """
128        for key, val in grok.getSite()['users'].items():
129            url = self.url(val)
130            yield(dict(url=url, name=key, val=val))
131
132    def getUsersWithLocalRoles(self):
133        return get_users_with_local_roles(self.context)
134
[6069]135    # ToDo: Show warning message before deletion
136    @grok.action('Remove selected')
137    def delApplicantsContainers(self, **data):
138        form = self.request.form
139        child_id = form['val_id']
140        if not isinstance(child_id, list):
141            child_id = [child_id]
142        deleted = []
143        for id in child_id:
144            try:
145                del self.context[id]
146                deleted.append(id)
147            except:
148                self.flash('Could not delete %s: %s: %s' % (
149                        id, sys.exc_info()[0], sys.exc_info()[1]))
150        if len(deleted):
151            self.flash('Successfully removed: %s' % ', '.join(deleted))
[6078]152        self.redirect(self.url(self.context, '@@manage')+'#tab-1')
153        return
[5828]154
[6069]155    @grok.action('Add applicants container', validator=NullValidator)
156    def addApplicantsContainer(self, **data):
157        self.redirect(self.url(self.context, '@@add'))
[6078]158        return
159
[6069]160    @grok.action('Cancel', validator=NullValidator)
161    def cancel(self, **data):
162        self.redirect(self.url(self.context))
[6078]163        return
164
[6184]165    @grok.action('Add local role', validator=NullValidator)
166    def addLocalRole(self, **data):
167        return add_local_role(self,2, **data)
168
169    @grok.action('Remove selected local roles')
170    def delLocalRoles(self, **data):
171        return del_local_roles(self,2,**data)
172
[6069]173class ApplicantsContainerAddFormPage(WAeUPAddFormPage):
[5822]174    grok.context(IApplicantsRoot)
[6198]175    grok.require('waeup.manageApplications')
[5822]176    grok.name('add')
[6107]177    grok.template('applicantscontaineraddpage')
[6069]178    title = 'Applicants'
179    label = 'Add applicants container'
[5843]180    pnav = 3
[6078]181
[6103]182    form_fields = grok.AutoFields(
183        IApplicantsContainerAdd).omit('code').omit('title')
[6083]184    form_fields['startdate'].custom_widget = FriendlyDateWidget('le')
185    form_fields['enddate'].custom_widget = FriendlyDateWidget('le')
[6078]186
[6083]187    def update(self):
188        datepicker.need() # Enable jQuery datepicker in date fields.
189        return super(ApplicantsContainerAddFormPage, self).update()
190
[6069]191    @grok.action('Add applicants container')
192    def addApplicantsContainer(self, **data):
[6103]193        year = data['year']
194        code = u'%s%s' % (data['prefix'], year)
195        prefix = application_types_vocab.getTerm(data['prefix'])
196        title = u'%s %s/%s' % (prefix.title, year, year + 1)
[6087]197        if code in self.context.keys():
[6105]198            self.flash(
199                'An applicants container for the same application '
200                'type and entrance year exists already in the database.')
[5822]201            return
202        # Add new applicants container...
[6083]203        provider = data['provider'][1]
[5822]204        container = provider.factory()
[6069]205        self.applyData(container, **data)
[6087]206        container.code = code
207        container.title = title
208        self.context[code] = container
[6105]209        self.flash('Added: "%s".' % code)
[6069]210        self.redirect(self.url(self.context, u'@@manage')+'#tab-1')
[5822]211        return
[6078]212
[6103]213    @grok.action('Cancel', validator=NullValidator)
[6069]214    def cancel(self, **data):
[6103]215        self.redirect(self.url(self.context, '@@manage') + '#tab-1')
[6078]216
[5845]217class ApplicantsRootBreadcrumb(Breadcrumb):
218    """A breadcrumb for applicantsroot.
219    """
220    grok.context(IApplicantsRoot)
[6153]221    title = u'Application Section'
[6078]222
[5845]223class ApplicantsContainerBreadcrumb(Breadcrumb):
224    """A breadcrumb for applicantscontainers.
225    """
226    grok.context(IApplicantsContainer)
[6319]227
[6153]228class ApplicantBreadcrumb(Breadcrumb):
229    """A breadcrumb for applicants.
230    """
231    grok.context(IApplicant)
[6319]232
[6153]233    @property
234    def title(self):
235        """Get a title for a context.
236        """
237        return self.context.access_code
[5828]238
239class ApplicantsTab(PrimaryNavTab):
[6153]240    """Applicants tab in primary navigation.
[5828]241    """
[6078]242
[5828]243    grok.context(IWAeUPObject)
244    grok.order(3)
[6336]245    grok.require('waeup.Public')
[5828]246    grok.template('primarynavtab')
247
[5843]248    pnav = 3
[5828]249    tab_title = u'Applicants'
250
251    @property
252    def link_target(self):
253        return self.view.application_url('applicants')
254
[6029]255class ApplicantsContainerPage(WAeUPDisplayFormPage):
[5830]256    """The standard view for regular applicant containers.
257    """
258    grok.context(IApplicantsContainer)
259    grok.name('index')
[6153]260    grok.require('waeup.Public')
[6029]261    grok.template('applicantscontainerpage')
[5850]262    pnav = 3
[6053]263
[6105]264    form_fields = grok.AutoFields(IApplicantsContainer).omit('title')
[6054]265    form_fields['startdate'].custom_widget = FriendlyDateDisplayWidget('le')
266    form_fields['enddate'].custom_widget = FriendlyDateDisplayWidget('le')
[6084]267    form_fields['description'].custom_widget = ReSTDisplayWidget
[6053]268
[5837]269    @property
270    def title(self):
[6087]271        return "Applicants Container: %s" % self.context.title
[5837]272
273    @property
274    def label(self):
[6087]275        return self.context.title
[5830]276
[6107]277class ApplicantsContainerManageActionButton(ManageActionButton):
[6336]278    grok.order(1)
[5832]279    grok.context(IApplicantsContainer)
280    grok.view(ApplicantsContainerPage)
[6198]281    grok.require('waeup.manageApplications')
[6070]282    text = 'Manage applicants container'
[5832]283
[6336]284class LoginApplicantActionButton(ManageActionButton):
285    grok.order(2)
286    grok.context(IApplicantsContainer)
287    grok.view(ApplicantsContainerPage)
288    grok.require('waeup.Anonymous')
289    icon = 'login.png'
290    text = 'Login for applicants'
291    target = 'login'
[5832]292
[6107]293class ApplicantsContainerManageFormPage(WAeUPEditFormPage):
[5837]294    grok.context(IApplicantsContainer)
[5850]295    grok.name('manage')
[6107]296    grok.template('applicantscontainermanagepage')
[6105]297    form_fields = grok.AutoFields(IApplicantsContainer).omit('title')
298    taboneactions = ['Save','Cancel']
299    tabtwoactions = ['Add applicant', 'Remove selected','Cancel']
[6184]300    tabthreeactions1 = ['Remove selected local roles']
301    tabthreeactions2 = ['Add local role']
[5844]302    # Use friendlier date widget...
[6054]303    form_fields['startdate'].custom_widget = FriendlyDateWidget('le')
304    form_fields['enddate'].custom_widget = FriendlyDateWidget('le')
[6198]305    grok.require('waeup.manageApplications')
[5850]306
307    @property
308    def title(self):
[6087]309        return "Applicants Container: %s" % self.context.title
[6078]310
[5850]311    @property
312    def label(self):
[6087]313        return 'Manage applicants container'
[5850]314
[5845]315    pnav = 3
[5837]316
317    def update(self):
[5850]318        datepicker.need() # Enable jQuery datepicker in date fields.
[5982]319        tabs.need()
[6015]320        datatable.need()  # Enable jQurey datatables for contents listing
[6107]321        return super(ApplicantsContainerManageFormPage, self).update()
[5837]322
[6184]323    def getLocalRoles(self):
324        roles = ILocalRolesAssignable(self.context)
325        return roles()
326
327    def getUsers(self):
328        """Get a list of all users.
329        """
330        for key, val in grok.getSite()['users'].items():
331            url = self.url(val)
332            yield(dict(url=url, name=key, val=val))
333
334    def getUsersWithLocalRoles(self):
335        return get_users_with_local_roles(self.context)
336
[5850]337    @grok.action('Save')
[5837]338    def apply(self, **data):
339        self.applyData(self.context, **data)
340        self.flash('Data saved.')
341        return
[6078]342
[6105]343    # ToDo: Show warning message before deletion
344    @grok.action('Remove selected')
345    def delApplicant(self, **data):
[6189]346        form = self.request.form
347        if form.has_key('val_id'):
348            child_id = form['val_id']
349        else:
350            self.flash('No applicant selected!')
351            self.redirect(self.url(self.context, '@@manage')+'#tab-2')
352            return
353        if not isinstance(child_id, list):
354            child_id = [child_id]
355        deleted = []
356        for id in child_id:
357            try:
358                del self.context[id]
359                deleted.append(id)
360            except:
361                self.flash('Could not delete %s: %s: %s' % (
362                        id, sys.exc_info()[0], sys.exc_info()[1]))
363        if len(deleted):
364            self.flash('Successfully removed: %s' % ', '.join(deleted))
365        self.redirect(self.url(self.context, u'@@manage')+'#tab-2')
366        return
[6105]367
368    @grok.action('Add applicant', validator=NullValidator)
369    def addApplicant(self, **data):
[6327]370        self.redirect(self.url(self.context, 'addapplicant'))
371        return
[6105]372
373    @grok.action('Cancel', validator=NullValidator)
[5837]374    def cancel(self, **data):
375        self.redirect(self.url(self.context))
376        return
[5886]377
[6184]378    @grok.action('Add local role', validator=NullValidator)
379    def addLocalRole(self, **data):
380        return add_local_role(self,3, **data)
[6105]381
[6184]382    @grok.action('Remove selected local roles')
383    def delLocalRoles(self, **data):
384        return del_local_roles(self,3,**data)
385
[5886]386class LoginApplicant(WAeUPPage):
387    grok.context(IApplicantsContainer)
388    grok.name('login')
[6153]389    grok.require('waeup.Public')
[5886]390
[6110]391    @property
392    def title(self):
393        return u"Applicant Login: %s" % self.context.title
[6078]394
[5886]395    @property
396    def label(self):
[6110]397        return u'Login for applicants only'
[5886]398
399    pnav = 3
[6319]400
[6110]401    @property
402    def ac_prefix(self):
403        return self.context.ac_prefix
[6078]404
[5896]405    def update(self, SUBMIT=None):
406        self.ac_series = self.request.form.get('form.ac_series', None)
407        self.ac_number = self.request.form.get('form.ac_number', None)
[5886]408        if SUBMIT is None:
409            return
[5894]410        if self.request.principal.id == 'zope.anybody':
[6105]411            self.flash('Entered credentials are invalid.')
[5886]412            return
[5894]413        if not IApplicantPrincipal.providedBy(self.request.principal):
414            # Don't care if user is already authenticated as non-applicant
415            return
[5905]416        pin = self.request.principal.access_code
[6359]417        if pin in self.context.keys():
418            self.redirect(self.url(self.context[pin], 'edit'))
419            return
420
421        # Mark pin as used
422        invalidate_accesscode(pin)
423
424        # Create applicant record
425        applicant = Applicant()
426        applicant.access_code = pin
427        self.context[pin] = applicant
428
[5937]429        # Assign current principal the owner role on created applicant
430        # record
[6184]431        role_manager = IPrincipalRoleManager(self.context[pin])
[5937]432        role_manager.assignRoleToPrincipal(
[6043]433            'waeup.local.ApplicationOwner', self.request.principal.id)
[6325]434        # Assign current principal the PortalUser role
435        role_manager = IPrincipalRoleManager(grok.getSite()['faculties'])
436        role_manager.assignRoleToPrincipal(
437            'waeup.PortalUser', self.request.principal.id)
[6349]438        # XXX: disable for now. Pins will get a different workflow.
439        #state = IWorkflowState(self.context[pin]).getState()
440        #if state == INITIALIZED:
441        #    IWorkflowInfo(self.context[pin]).fireTransition('start')
[5937]442        self.redirect(self.url(self.context[pin], 'edit'))
[5886]443        return
[6319]444
[6327]445class ApplicantAddFormPage(WAeUPAddFormPage):
446    """Add-form to add certificate to a department.
447    """
448    grok.context(IApplicantsContainer)
449    grok.require('waeup.manageApplications')
450    grok.name('addapplicant')
451    grok.template('applicantaddpage')
452    title = 'Applicants'
453    label = 'Add applicant'
454    pnav = 3
455
456    @property
457    def title(self):
458        return "Applicants Container: %s" % self.context.title
459
460    @property
461    def ac_prefix(self):
462        return self.context.ac_prefix
463
464    @grok.action('Create application record')
465    def addApplicant(self, **data):
466        ac_series = self.request.form.get('form.ac_series', None)
467        ac_number = self.request.form.get('form.ac_number', None)
468        pin = '%s-%s-%s' % (self.ac_prefix,ac_series,ac_number)
469        if pin not in self.context.keys():
470            # Create applicant record
471            applicant = Applicant()
472            applicant.access_code = pin
473            self.context[pin] = applicant
474        self.redirect(self.url(self.context[pin], 'edit'))
475        return
476
[6153]477class AccessCodeLink(LeftSidebarLink):
478    grok.order(1)
479    grok.require('waeup.Public')
[5886]480
[6153]481    def render(self):
482        if not IApplicantPrincipal.providedBy(self.request.principal):
483            return ''
484        access_code = getattr(self.request.principal,'access_code',None)
485        if access_code:
486            applicant_object = get_applicant_data(access_code)
487            url = absoluteURL(applicant_object, self.request)
[6198]488            return u'<div class="portlet"><a href="%s/edit">%s</a></div>' % (
[6153]489                url,access_code)
490        return ''
491
[5273]492class DisplayApplicant(WAeUPDisplayFormPage):
493    grok.context(IApplicant)
494    grok.name('index')
[6198]495    grok.require('waeup.handleApplication')
[6320]496    form_fields = grok.AutoFields(IApplicant).omit(
497        'locked').omit('course_admitted')
[6196]498    #form_fields['fst_sit_results'].custom_widget = list_results_display_widget
[5919]499    form_fields['passport'].custom_widget = ThumbnailWidget
[6054]500    form_fields['date_of_birth'].custom_widget = FriendlyDateDisplayWidget('le')
[5273]501    label = 'Applicant'
[6254]502    grok.template('form_display')
[5843]503    pnav = 3
[5273]504
[6196]505    @property
506    def title(self):
507        return '%s' % self.context.access_code
508
509    @property
510    def label(self):
511        container_title = self.context.__parent__.title
512        return '%s Application Record' % container_title
513
[6254]514    def getCourseAdmitted(self):
[6355]515        """Return link, title and code in html format to the certificate
516           admitted.
[6351]517        """
[6254]518        course_admitted = self.context.course_admitted
519        if ICertificate.providedBy(course_admitted):
520            url = self.url(course_admitted)
521            title = course_admitted.title
522            code = course_admitted.code
523            return '<a href="%s">%s (%s)</a>' %(url,title,code)
524        return 'not yet admitted'
525
[6358]526class PDFActionButton(ManageActionButton):
527    grok.context(IApplicant)
528    grok.view(DisplayApplicant)
529    grok.require('waeup.handleApplication')
530    icon = 'actionicon_pdf.png'
531    text = 'Download pdf slip'
532    target = 'application_slip.pdf'
533
534class ExportPDFPage(grok.View):
535    """Deliver a PDF slip of the context.
536    """
537    grok.context(IApplicant)
538    grok.name('application_slip.pdf')
539    grok.require('waeup.handleApplication')
540    form_fields = grok.AutoFields(IApplicant).omit(
541        'locked').omit('course_admitted')
[6360]542    #form_fields['passport'].custom_widget = ThumbnailWidget
[6358]543    form_fields['date_of_birth'].custom_widget = FriendlyDateDisplayWidget('le')
544
545    prefix = 'form'
546
547    def getCourseAdmitted(self):
548        """Return title and code in html format to the certificate
549           admitted.
550        """
551        course_admitted = self.context.course_admitted
552        if ICertificate.providedBy(course_admitted):
553            title = course_admitted.title
554            code = course_admitted.code
555            return '%s (%s)' %(title,code)
556        return 'not yet admitted'
557
558    def setUpWidgets(self, ignore_request=False):
559        self.adapters = {}
560        self.widgets = setUpEditWidgets(
561            self.form_fields, self.prefix, self.context, self.request,
562            adapters=self.adapters, for_display=True,
563            ignore_request=ignore_request
564            )
565
566    # Render a demo pdf page
567    def render(self):
568        from reportlab.pdfgen import canvas
569        from reportlab.lib.units import cm
570        from reportlab.lib.pagesizes import A4, landscape
571        from reportlab.lib.styles import getSampleStyleSheet
[6360]572        from reportlab.platypus import Frame, Paragraph, Image
[6358]573
574        pdf = canvas.Canvas('application_slip.pdf',pagesize=A4)
575        width, height = A4
576        style = getSampleStyleSheet()
577        story = []
578        frame = Frame(1*cm,1*cm,width-(2*cm),height-(2*cm))
579        self.setUpWidgets()
[6360]580       
[6358]581        for widget in self.widgets:
582            if widget.name != 'form.passport':
583                ptext = widget()
584                story.append(Paragraph(ptext, style["Normal"]))
[6360]585            else:
586                #import pdb; pdb.set_trace()
587                filename = widget._data.file.name
588                im = Image(filename)
589                story.append(im)
[6358]590        frame.addFromList(story,pdf)
591        self.response.setHeader(
592            'Content-Type', 'application/pdf')
593        return pdf.getpdfdata()
594
[6198]595class ApplicantsManageActionButton(ManageActionButton):
596    grok.context(IApplicant)
597    grok.view(DisplayApplicant)
598    grok.require('waeup.manageApplications')
599    text = 'Edit application record'
600    target = 'edit_full'
601
[6196]602class EditApplicantFull(WAeUPEditFormPage):
603    """A full edit view for applicant data.
604    """
605    grok.context(IApplicant)
606    grok.name('edit_full')
[6198]607    grok.require('waeup.manageApplications')
[6196]608    form_fields = grok.AutoFields(IApplicant)   #.omit('locked')
609    form_fields['passport'].custom_widget = EncodingImageFileWidget
610    form_fields['date_of_birth'].custom_widget = FriendlyDateWidget('le-year')
611    grok.template('form_edit')
[6322]612    manage_applications = True
[6196]613    pnav = 3
614
615    def update(self):
616        datepicker.need() # Enable jQuery datepicker in date fields.
617        super(EditApplicantFull, self).update()
[6353]618        self.wf_info = IWorkflowInfo(self.context)
[6196]619        return
620
621    @property
622    def title(self):
623        return self.context.access_code
624
625    @property
626    def label(self):
627        container_title = self.context.__parent__.title
628        return '%s Application Form' % container_title
629
[6303]630    def getTransitions(self):
[6351]631        """Return a list of dicts of allowed transition ids and titles.
[6353]632
633        Each list entry provides keys ``name`` and ``title`` for
634        internal name and (human readable) title of a single
635        transition.
[6349]636        """
[6353]637        allowed_transitions = self.wf_info.getManualTransitions()
[6355]638        return [dict(name='', title='No transition')] +[
639            dict(name=x, title=y) for x, y in allowed_transitions]
[6303]640
[6196]641    @grok.action('Save')
642    def save(self, **data):
643        self.applyData(self.context, **data)
644        self.context._p_changed = True
[6303]645        form = self.request.form
646        if form.has_key('transition') and form['transition']:
[6305]647            transition_id = form['transition']
[6353]648            self.wf_info.fireTransition(transition_id)
[6196]649        self.flash('Form has been saved.')
[6348]650        self.context.getApplicantsRootLogger().info('Saved')
[6196]651        return
652
653class EditApplicantStudent(EditApplicantFull):
[5982]654    """An applicant-centered edit view for applicant data.
655    """
[6196]656    grok.context(IApplicantEdit)
[5273]657    grok.name('edit')
[6198]658    grok.require('waeup.handleApplication')
[6196]659    form_fields = grok.AutoFields(IApplicantEdit).omit('locked')
[5686]660    form_fields['passport'].custom_widget = EncodingImageFileWidget
[6054]661    form_fields['date_of_birth'].custom_widget = FriendlyDateWidget('le-year')
[6196]662    grok.template('form_edit')
[6322]663    manage_applications = False
[5484]664
[6322]665
[5941]666    def emitLockMessage(self):
[6105]667        self.flash('The requested form is locked (read-only).')
[5941]668        self.redirect(self.url(self.context))
669        return
[6078]670
[5686]671    def update(self):
[5941]672        if self.context.locked:
[6198]673            self.redirect(self.url(self.context))
[5941]674            return
[6040]675        datepicker.need() # Enable jQuery datepicker in date fields.
[5982]676        super(EditApplicantStudent, self).update()
[5686]677        return
[5952]678
[6196]679    def dataNotComplete(self):
[6322]680        if not self.request.form.get('confirm_passport', False):
[6196]681            return 'Passport confirmation box not ticked.'
682        if len(self.errors) > 0:
683            return 'Form has errors.'
684        return False
[5952]685
[5273]686    @grok.action('Save')
687    def save(self, **data):
[5941]688        if self.context.locked:
689            self.emitLockMessage()
690            return
[5273]691        self.applyData(self.context, **data)
692        self.context._p_changed = True
[6196]693        self.flash('Form has been saved.')
[5273]694        return
695
[5484]696    @grok.action('Final Submit')
697    def finalsubmit(self, **data):
[5941]698        if self.context.locked:
699            self.emitLockMessage()
700            return
[5273]701        self.applyData(self.context, **data)
[5484]702        self.context._p_changed = True
[6196]703        if self.dataNotComplete():
704            self.flash(self.dataNotComplete())
[5941]705            return
[6303]706        state = IWorkflowState(self.context).getState()
[6322]707        # This shouldn't happen, but the application officer
708        # might have forgotten to lock the form after changing the state
[6303]709        if state != STARTED:
[6322]710            self.flash('This form cannot be submitted. Wrong state!')
[6303]711            return
712        IWorkflowInfo(self.context).fireTransition('submit')
[5941]713        self.context.locked = True
[6196]714        self.flash('Form has been submitted.')
715        self.redirect(self.url(self.context))
[5273]716        return
[5941]717
Note: See TracBrowser for help on using the repository browser.