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

Last change on this file since 6363 was 6363, checked in by Henrik Bettermann, 13 years ago

Further pdf improvements (in progress): Show data in table layout

File size: 25.6 KB
Line 
1##
2## browser.py
3## Login : <uli@pu.smp.net>
4## Started on  Sun Jun 27 11:03:10 2010 Uli Fouquet & Henrik Bettermann
5## $Id$
6##
7## Copyright (C) 2010 Uli Fouquet & Henrik Bettermann
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.
12##
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.
17##
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##
22"""UI components for basic applicants and related components.
23"""
24import sys
25import grok
26
27from datetime import datetime
28from zope.formlib.widget import CustomWidgetFactory
29from zope.formlib.form import setUpEditWidgets
30from zope.securitypolicy.interfaces import IPrincipalRoleManager
31from zope.traversing.browser import absoluteURL
32
33from hurry.workflow.interfaces import IWorkflowInfo, IWorkflowState
34from reportlab.pdfgen import canvas
35
36from waeup.sirp.accesscodes import invalidate_accesscode
37from waeup.sirp.browser import (
38    WAeUPPage, WAeUPEditFormPage, WAeUPAddFormPage, WAeUPDisplayFormPage)
39from waeup.sirp.browser.breadcrumbs import Breadcrumb
40from waeup.sirp.browser.layout import NullValidator
41from waeup.sirp.browser.pages import add_local_role, del_local_roles
42from waeup.sirp.browser.resources import datepicker, tabs, datatable
43from waeup.sirp.browser.viewlets import (
44    ManageActionButton, PrimaryNavTab, LeftSidebarLink
45    )
46from waeup.sirp.image.browser.widget import (
47    ThumbnailWidget, EncodingImageFileWidget,
48    )
49from waeup.sirp.interfaces import IWAeUPObject, ILocalRolesAssignable
50from waeup.sirp.permissions import get_users_with_local_roles
51from waeup.sirp.university.interfaces import ICertificate
52from waeup.sirp.widgets.datewidget import (
53    FriendlyDateWidget, FriendlyDateDisplayWidget)
54from waeup.sirp.widgets.restwidget import ReSTDisplayWidget
55from waeup.sirp.widgets.objectwidget import (
56    WAeUPObjectWidget, WAeUPObjectDisplayWidget)
57from waeup.sirp.widgets.multilistwidget import (
58    MultiListWidget, MultiListDisplayWidget)
59from waeup.sirp.applicants import ResultEntry, Applicant, get_applicant_data
60from waeup.sirp.applicants.interfaces import (
61    IApplicant, IApplicantPrincipal,IApplicantEdit, IApplicantsRoot,
62    IApplicantsContainer, IApplicantsContainerAdd, application_types_vocab
63    )
64from waeup.sirp.applicants.workflow import INITIALIZED, STARTED
65
66results_widget = CustomWidgetFactory(
67    WAeUPObjectWidget, ResultEntry)
68
69results_display_widget = CustomWidgetFactory(
70    WAeUPObjectDisplayWidget, ResultEntry)
71
72list_results_widget = CustomWidgetFactory(
73    MultiListWidget, subwidget=results_widget)
74
75list_results_display_widget = CustomWidgetFactory(
76    MultiListDisplayWidget, subwidget=results_display_widget)
77
78#TRANSITION_OBJECTS = create_workflow()
79
80#TRANSITION_DICT = dict([
81#    (transition_object.transition_id,transition_object.title)
82#    for transition_object in TRANSITION_OBJECTS])
83
84class ApplicantsRootPage(WAeUPPage):
85    grok.context(IApplicantsRoot)
86    grok.name('index')
87    grok.require('waeup.Public')
88    title = 'Applicants'
89    label = 'Application Section'
90    pnav = 3
91
92    def update(self):
93        super(ApplicantsRootPage, self).update()
94        datatable.need()
95        return
96
97class ManageApplicantsRootActionButton(ManageActionButton):
98    grok.context(IApplicantsRoot)
99    grok.view(ApplicantsRootPage)
100    grok.require('waeup.manageApplications')
101    text = 'Manage application section'
102
103class ApplicantsRootManageFormPage(WAeUPEditFormPage):
104    grok.context(IApplicantsRoot)
105    grok.name('manage')
106    grok.template('applicantsrootmanagepage')
107    title = 'Applicants'
108    label = 'Manage application section'
109    pnav = 3
110    grok.require('waeup.manageApplications')
111    taboneactions = ['Add applicants container', 'Remove selected','Cancel']
112    tabtwoactions1 = ['Remove selected local roles']
113    tabtwoactions2 = ['Add local role']
114    subunits = 'Applicants Containers'
115
116    def update(self):
117        tabs.need()
118        datatable.need()
119        return super(ApplicantsRootManageFormPage, self).update()
120
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
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))
152        self.redirect(self.url(self.context, '@@manage')+'#tab-1')
153        return
154
155    @grok.action('Add applicants container', validator=NullValidator)
156    def addApplicantsContainer(self, **data):
157        self.redirect(self.url(self.context, '@@add'))
158        return
159
160    @grok.action('Cancel', validator=NullValidator)
161    def cancel(self, **data):
162        self.redirect(self.url(self.context))
163        return
164
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
173class ApplicantsContainerAddFormPage(WAeUPAddFormPage):
174    grok.context(IApplicantsRoot)
175    grok.require('waeup.manageApplications')
176    grok.name('add')
177    grok.template('applicantscontaineraddpage')
178    title = 'Applicants'
179    label = 'Add applicants container'
180    pnav = 3
181
182    form_fields = grok.AutoFields(
183        IApplicantsContainerAdd).omit('code').omit('title')
184    form_fields['startdate'].custom_widget = FriendlyDateWidget('le')
185    form_fields['enddate'].custom_widget = FriendlyDateWidget('le')
186
187    def update(self):
188        datepicker.need() # Enable jQuery datepicker in date fields.
189        return super(ApplicantsContainerAddFormPage, self).update()
190
191    @grok.action('Add applicants container')
192    def addApplicantsContainer(self, **data):
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)
197        if code in self.context.keys():
198            self.flash(
199                'An applicants container for the same application '
200                'type and entrance year exists already in the database.')
201            return
202        # Add new applicants container...
203        provider = data['provider'][1]
204        container = provider.factory()
205        self.applyData(container, **data)
206        container.code = code
207        container.title = title
208        self.context[code] = container
209        self.flash('Added: "%s".' % code)
210        self.redirect(self.url(self.context, u'@@manage')+'#tab-1')
211        return
212
213    @grok.action('Cancel', validator=NullValidator)
214    def cancel(self, **data):
215        self.redirect(self.url(self.context, '@@manage') + '#tab-1')
216
217class ApplicantsRootBreadcrumb(Breadcrumb):
218    """A breadcrumb for applicantsroot.
219    """
220    grok.context(IApplicantsRoot)
221    title = u'Application Section'
222
223class ApplicantsContainerBreadcrumb(Breadcrumb):
224    """A breadcrumb for applicantscontainers.
225    """
226    grok.context(IApplicantsContainer)
227
228class ApplicantBreadcrumb(Breadcrumb):
229    """A breadcrumb for applicants.
230    """
231    grok.context(IApplicant)
232
233    @property
234    def title(self):
235        """Get a title for a context.
236        """
237        return self.context.access_code
238
239class ApplicantsTab(PrimaryNavTab):
240    """Applicants tab in primary navigation.
241    """
242
243    grok.context(IWAeUPObject)
244    grok.order(3)
245    grok.require('waeup.Public')
246    grok.template('primarynavtab')
247
248    pnav = 3
249    tab_title = u'Applicants'
250
251    @property
252    def link_target(self):
253        return self.view.application_url('applicants')
254
255class ApplicantsContainerPage(WAeUPDisplayFormPage):
256    """The standard view for regular applicant containers.
257    """
258    grok.context(IApplicantsContainer)
259    grok.name('index')
260    grok.require('waeup.Public')
261    grok.template('applicantscontainerpage')
262    pnav = 3
263
264    form_fields = grok.AutoFields(IApplicantsContainer).omit('title')
265    form_fields['startdate'].custom_widget = FriendlyDateDisplayWidget('le')
266    form_fields['enddate'].custom_widget = FriendlyDateDisplayWidget('le')
267    form_fields['description'].custom_widget = ReSTDisplayWidget
268
269    @property
270    def title(self):
271        return "Applicants Container: %s" % self.context.title
272
273    @property
274    def label(self):
275        return self.context.title
276
277class ApplicantsContainerManageActionButton(ManageActionButton):
278    grok.order(1)
279    grok.context(IApplicantsContainer)
280    grok.view(ApplicantsContainerPage)
281    grok.require('waeup.manageApplications')
282    text = 'Manage applicants container'
283
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'
292
293class ApplicantsContainerManageFormPage(WAeUPEditFormPage):
294    grok.context(IApplicantsContainer)
295    grok.name('manage')
296    grok.template('applicantscontainermanagepage')
297    form_fields = grok.AutoFields(IApplicantsContainer).omit('title')
298    taboneactions = ['Save','Cancel']
299    tabtwoactions = ['Add applicant', 'Remove selected','Cancel']
300    tabthreeactions1 = ['Remove selected local roles']
301    tabthreeactions2 = ['Add local role']
302    # Use friendlier date widget...
303    form_fields['startdate'].custom_widget = FriendlyDateWidget('le')
304    form_fields['enddate'].custom_widget = FriendlyDateWidget('le')
305    grok.require('waeup.manageApplications')
306
307    @property
308    def title(self):
309        return "Applicants Container: %s" % self.context.title
310
311    @property
312    def label(self):
313        return 'Manage applicants container'
314
315    pnav = 3
316
317    def update(self):
318        datepicker.need() # Enable jQuery datepicker in date fields.
319        tabs.need()
320        datatable.need()  # Enable jQurey datatables for contents listing
321        return super(ApplicantsContainerManageFormPage, self).update()
322
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
337    @grok.action('Save')
338    def apply(self, **data):
339        self.applyData(self.context, **data)
340        self.flash('Data saved.')
341        return
342
343    # ToDo: Show warning message before deletion
344    @grok.action('Remove selected')
345    def delApplicant(self, **data):
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
367
368    @grok.action('Add applicant', validator=NullValidator)
369    def addApplicant(self, **data):
370        self.redirect(self.url(self.context, 'addapplicant'))
371        return
372
373    @grok.action('Cancel', validator=NullValidator)
374    def cancel(self, **data):
375        self.redirect(self.url(self.context))
376        return
377
378    @grok.action('Add local role', validator=NullValidator)
379    def addLocalRole(self, **data):
380        return add_local_role(self,3, **data)
381
382    @grok.action('Remove selected local roles')
383    def delLocalRoles(self, **data):
384        return del_local_roles(self,3,**data)
385
386class LoginApplicant(WAeUPPage):
387    grok.context(IApplicantsContainer)
388    grok.name('login')
389    grok.require('waeup.Public')
390
391    @property
392    def title(self):
393        return u"Applicant Login: %s" % self.context.title
394
395    @property
396    def label(self):
397        return u'Login for applicants only'
398
399    pnav = 3
400
401    @property
402    def ac_prefix(self):
403        return self.context.ac_prefix
404
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)
408        if SUBMIT is None:
409            return
410        if self.request.principal.id == 'zope.anybody':
411            self.flash('Entered credentials are invalid.')
412            return
413        if not IApplicantPrincipal.providedBy(self.request.principal):
414            # Don't care if user is already authenticated as non-applicant
415            return
416        pin = self.request.principal.access_code
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
429        # Assign current principal the owner role on created applicant
430        # record
431        role_manager = IPrincipalRoleManager(self.context[pin])
432        role_manager.assignRoleToPrincipal(
433            'waeup.local.ApplicationOwner', self.request.principal.id)
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)
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')
442        self.redirect(self.url(self.context[pin], 'edit'))
443        return
444
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
477class AccessCodeLink(LeftSidebarLink):
478    grok.order(1)
479    grok.require('waeup.Public')
480
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)
488            return u'<div class="portlet"><a href="%s/edit">%s</a></div>' % (
489                url,access_code)
490        return ''
491
492class DisplayApplicant(WAeUPDisplayFormPage):
493    grok.context(IApplicant)
494    grok.name('index')
495    grok.require('waeup.handleApplication')
496    form_fields = grok.AutoFields(IApplicant).omit(
497        'locked').omit('course_admitted')
498    #form_fields['fst_sit_results'].custom_widget = list_results_display_widget
499    form_fields['passport'].custom_widget = ThumbnailWidget
500    form_fields['date_of_birth'].custom_widget = FriendlyDateDisplayWidget('le')
501    label = 'Applicant'
502    grok.template('form_display')
503    pnav = 3
504
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
514    def getCourseAdmitted(self):
515        """Return link, title and code in html format to the certificate
516           admitted.
517        """
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
526class PDFActionButton(ManageActionButton):
527    grok.context(IApplicant)
528    grok.view(DisplayApplicant)
529    grok.require('waeup.handleApplication')
530    icon = 'actionicon_pdf.png'
531    text = 'Application 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')
542    form_fields['date_of_birth'].custom_widget = FriendlyDateDisplayWidget('le')
543    prefix = 'form'
544
545    @property
546    def label(self):
547        container_title = self.context.__parent__.title
548        return '%s Application Record' % container_title
549
550    def getCourseAdmitted(self):
551        """Return title and code in html format to the certificate
552           admitted.
553        """
554        course_admitted = self.context.course_admitted
555        if ICertificate.providedBy(course_admitted):
556            title = course_admitted.title
557            code = course_admitted.code
558            return '%s (%s)' %(title,code)
559        return 'not yet admitted'
560
561    def setUpWidgets(self, ignore_request=False):
562        self.adapters = {}
563        self.widgets = setUpEditWidgets(
564            self.form_fields, self.prefix, self.context, self.request,
565            adapters=self.adapters, for_display=True,
566            ignore_request=ignore_request
567            )
568
569    def render(self):
570        from reportlab.pdfgen import canvas
571        from reportlab.lib.units import cm
572        from reportlab.lib.pagesizes import A4, landscape
573        from reportlab.lib.styles import getSampleStyleSheet
574        from reportlab.platypus import (Frame, Paragraph, Image,
575            Table, Spacer)
576        from reportlab.platypus.flowables import HRFlowable
577
578        pdf = canvas.Canvas('application_slip.pdf',pagesize=A4)
579        width, height = A4
580        style = getSampleStyleSheet()
581
582        story = []
583        frame_header = Frame(1*cm,1*cm,width-(4*cm),height-(1*cm))
584        header_title = getattr(grok.getSite(), 'name', u'Sample University')
585        story.append(Paragraph(header_title, style["Heading1"]))
586        #import pdb; pdb.set_trace()
587        frame_header.addFromList(story,pdf)
588
589        story = []
590        frame_body = Frame(1*cm,1*cm,width-(4*cm),height-(3*cm))
591        story.append(Paragraph(self.label, style["Title"]))
592        story.append(HRFlowable())
593        story.append(Spacer(1, 24))
594
595        self.setUpWidgets()
596
597        data = []
598        for widget in self.widgets:
599            f_label = '<font size=12>%s</font>' % widget.label.strip()
600            f_label = Paragraph(f_label, style["Normal"])
601            if widget.name != 'form.passport':
602                f_text = '<font size=12>%s</font>' % widget()
603                f_text = Paragraph(f_text, style["Normal"])
604                data.append([f_label,f_text])
605            else:
606                filename = widget._data.file.name
607                im = Image(filename)
608                data.append([f_label,im])
609        f_label = '<font size=12>Admitted Course of Study</font>'
610        f_text = '<font size=12>%s</font>' % self.getCourseAdmitted()
611        f_label = Paragraph(f_label, style["Normal"])
612        f_text = Paragraph(f_text, style["Normal"])
613        data.append([f_label,f_text])
614        table = Table(data)
615        story.append(table)
616        frame_body.addFromList(story,pdf)
617
618        self.response.setHeader(
619            'Content-Type', 'application/pdf')
620        return pdf.getpdfdata()
621
622class ApplicantsManageActionButton(ManageActionButton):
623    grok.context(IApplicant)
624    grok.view(DisplayApplicant)
625    grok.require('waeup.manageApplications')
626    text = 'Edit application record'
627    target = 'edit_full'
628
629class EditApplicantFull(WAeUPEditFormPage):
630    """A full edit view for applicant data.
631    """
632    grok.context(IApplicant)
633    grok.name('edit_full')
634    grok.require('waeup.manageApplications')
635    form_fields = grok.AutoFields(IApplicant)   #.omit('locked')
636    form_fields['passport'].custom_widget = EncodingImageFileWidget
637    form_fields['date_of_birth'].custom_widget = FriendlyDateWidget('le-year')
638    grok.template('form_edit')
639    manage_applications = True
640    pnav = 3
641
642    def update(self):
643        datepicker.need() # Enable jQuery datepicker in date fields.
644        super(EditApplicantFull, self).update()
645        self.wf_info = IWorkflowInfo(self.context)
646        return
647
648    @property
649    def title(self):
650        return self.context.access_code
651
652    @property
653    def label(self):
654        container_title = self.context.__parent__.title
655        return '%s Application Form' % container_title
656
657    def getTransitions(self):
658        """Return a list of dicts of allowed transition ids and titles.
659
660        Each list entry provides keys ``name`` and ``title`` for
661        internal name and (human readable) title of a single
662        transition.
663        """
664        allowed_transitions = self.wf_info.getManualTransitions()
665        return [dict(name='', title='No transition')] +[
666            dict(name=x, title=y) for x, y in allowed_transitions]
667
668    @grok.action('Save')
669    def save(self, **data):
670        self.applyData(self.context, **data)
671        self.context._p_changed = True
672        form = self.request.form
673        if form.has_key('transition') and form['transition']:
674            transition_id = form['transition']
675            self.wf_info.fireTransition(transition_id)
676        self.flash('Form has been saved.')
677        self.context.getApplicantsRootLogger().info('Saved')
678        return
679
680class EditApplicantStudent(EditApplicantFull):
681    """An applicant-centered edit view for applicant data.
682    """
683    grok.context(IApplicantEdit)
684    grok.name('edit')
685    grok.require('waeup.handleApplication')
686    form_fields = grok.AutoFields(IApplicantEdit).omit('locked')
687    form_fields['passport'].custom_widget = EncodingImageFileWidget
688    form_fields['date_of_birth'].custom_widget = FriendlyDateWidget('le-year')
689    grok.template('form_edit')
690    manage_applications = False
691
692
693    def emitLockMessage(self):
694        self.flash('The requested form is locked (read-only).')
695        self.redirect(self.url(self.context))
696        return
697
698    def update(self):
699        if self.context.locked:
700            self.redirect(self.url(self.context))
701            return
702        datepicker.need() # Enable jQuery datepicker in date fields.
703        super(EditApplicantStudent, self).update()
704        return
705
706    def dataNotComplete(self):
707        if not self.request.form.get('confirm_passport', False):
708            return 'Passport confirmation box not ticked.'
709        if len(self.errors) > 0:
710            return 'Form has errors.'
711        return False
712
713    @grok.action('Save')
714    def save(self, **data):
715        if self.context.locked:
716            self.emitLockMessage()
717            return
718        self.applyData(self.context, **data)
719        self.context._p_changed = True
720        self.flash('Form has been saved.')
721        return
722
723    @grok.action('Final Submit')
724    def finalsubmit(self, **data):
725        if self.context.locked:
726            self.emitLockMessage()
727            return
728        self.applyData(self.context, **data)
729        self.context._p_changed = True
730        if self.dataNotComplete():
731            self.flash(self.dataNotComplete())
732            return
733        state = IWorkflowState(self.context).getState()
734        # This shouldn't happen, but the application officer
735        # might have forgotten to lock the form after changing the state
736        if state != STARTED:
737            self.flash('This form cannot be submitted. Wrong state!')
738            return
739        IWorkflowInfo(self.context).fireTransition('submit')
740        self.context.locked = True
741        self.flash('Form has been submitted.')
742        self.redirect(self.url(self.context))
743        return
744
Note: See TracBrowser for help on using the repository browser.