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

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

Align ApplicantsRootManageFormPage? with manage form pages in university package. This includes buttoms for the manual addition and deletion of applicants.

File size: 14.5 KB
RevLine 
[5273]1##
2## browser.py
3## Login : <uli@pu.smp.net>
4## Started on  Sun Jun 27 11:03:10 2010 Uli Fouquet
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
[6082]27from zope.component import getUtility
[6081]28from zope.formlib.widget import CustomWidgetFactory
[6082]29from zope.interface import Invalid
[5937]30from zope.securitypolicy.interfaces import IPrincipalRoleManager
[6081]31
[5273]32from waeup.sirp.browser import (
33    WAeUPPage, WAeUPEditFormPage, WAeUPAddFormPage,
34    WAeUPDisplayFormPage, NullValidator)
[6081]35from waeup.sirp.browser.breadcrumbs import Breadcrumb
[6103]36from waeup.sirp.browser.layout import NullValidator
[6013]37from waeup.sirp.browser.resources import datepicker, tabs, datatable
[6082]38from waeup.sirp.browser.viewlets import ManageActionButton, PrimaryNavTab
[6081]39from waeup.sirp.image.browser.widget import (
40    ThumbnailWidget, EncodingImageFileWidget,
[5822]41    )
[6081]42from waeup.sirp.interfaces import IWAeUPObject
[6054]43from waeup.sirp.widgets.datewidget import (
44    FriendlyDateWidget, FriendlyDateDisplayWidget)
[6084]45from waeup.sirp.widgets.restwidget import ReSTDisplayWidget
[5303]46from waeup.sirp.widgets.objectwidget import (
[5301]47    WAeUPObjectWidget, WAeUPObjectDisplayWidget)
[5303]48from waeup.sirp.widgets.multilistwidget import (
[5273]49    MultiListWidget, MultiListDisplayWidget)
[6081]50
[6082]51from waeup.sirp.applicants import ResultEntry, Applicant
[6081]52from waeup.sirp.applicants.interfaces import (
53    IApplicant, IApplicantPrincipal, IApplicantPDEEditData,
54    IApplicantsRoot, IApplicantsContainer, IApplicantsContainerProvider,
[6087]55    IApplicantsContainerAdd, application_types_vocab
[5686]56    )
[5320]57
[5273]58results_widget = CustomWidgetFactory(
[5301]59    WAeUPObjectWidget, ResultEntry)
[5273]60
61results_display_widget = CustomWidgetFactory(
[5301]62    WAeUPObjectDisplayWidget, ResultEntry)
[5273]63
64list_results_widget = CustomWidgetFactory(
65    MultiListWidget, subwidget=results_widget)
66
67list_results_display_widget = CustomWidgetFactory(
68    MultiListDisplayWidget, subwidget=results_display_widget)
69
[6067]70class ApplicantsRootPage(WAeUPPage):
[5822]71    grok.context(IApplicantsRoot)
72    grok.name('index')
73    title = 'Applicants'
[6069]74    label = 'Application Section'
[5843]75    pnav = 3
[6012]76
77    def update(self):
[6067]78        super(ApplicantsRootPage, self).update()
[6012]79        datatable.need()
80        return
81
[5828]82class ManageApplicantsRootActionButton(ManageActionButton):
83    grok.context(IApplicantsRoot)
[6067]84    grok.view(ApplicantsRootPage)
[6069]85    grok.require('waeup.manageUniversity')
86    text = 'Manage application section'
[5828]87
[6069]88class ApplicantsRootManageFormPage(WAeUPEditFormPage):
[5828]89    grok.context(IApplicantsRoot)
90    grok.name('manage')
91    grok.template('applicantsrooteditpage')
[6069]92    title = 'Applicants'
93    label = 'Manage application section'
[5843]94    pnav = 3
[6069]95    grok.require('waeup.manageUniversity')
96    taboneactions = ['Add applicants container', 'Remove selected','Cancel']
97    subunits = 'Applicants Containers'
[6078]98
[6069]99    def update(self):
100        tabs.need()
101        #warning.need()
102        return super(ApplicantsRootManageFormPage, self).update()
[5828]103
[6069]104    # ToDo: Show warning message before deletion
105    @grok.action('Remove selected')
106    def delApplicantsContainers(self, **data):
107        form = self.request.form
108        child_id = form['val_id']
109        if not isinstance(child_id, list):
110            child_id = [child_id]
111        deleted = []
112        for id in child_id:
113            try:
114                del self.context[id]
115                deleted.append(id)
116            except:
117                self.flash('Could not delete %s: %s: %s' % (
118                        id, sys.exc_info()[0], sys.exc_info()[1]))
119        if len(deleted):
120            self.flash('Successfully removed: %s' % ', '.join(deleted))
[6078]121        self.redirect(self.url(self.context, '@@manage')+'#tab-1')
122        return
[5828]123
[6069]124    @grok.action('Add applicants container', validator=NullValidator)
125    def addApplicantsContainer(self, **data):
126        self.redirect(self.url(self.context, '@@add'))
[6078]127        return
128
[6069]129    @grok.action('Cancel', validator=NullValidator)
130    def cancel(self, **data):
131        self.redirect(self.url(self.context))
[6078]132        return
133
[6069]134class ApplicantsContainerAddFormPage(WAeUPAddFormPage):
[5822]135    grok.context(IApplicantsRoot)
[6069]136    grok.require('waeup.manageUniversity')
[5822]137    grok.name('add')
[6069]138    grok.template('applicantscontaineraddformpage')
139    title = 'Applicants'
140    label = 'Add applicants container'
[5843]141    pnav = 3
[6078]142
[6103]143    form_fields = grok.AutoFields(
144        IApplicantsContainerAdd).omit('code').omit('title')
[6083]145    form_fields['startdate'].custom_widget = FriendlyDateWidget('le')
146    form_fields['enddate'].custom_widget = FriendlyDateWidget('le')
[6078]147
[6083]148    def update(self):
149        datepicker.need() # Enable jQuery datepicker in date fields.
[6103]150        from waeup.sirp.browser.resources import jqueryui
151        jqueryui.need()
[6083]152        return super(ApplicantsContainerAddFormPage, self).update()
153
[6069]154    @grok.action('Add applicants container')
155    def addApplicantsContainer(self, **data):
[6103]156        year = data['year']
157        code = u'%s%s' % (data['prefix'], year)
158        prefix = application_types_vocab.getTerm(data['prefix'])
159        title = u'%s %s/%s' % (prefix.title, year, year + 1)
[6087]160        if code in self.context.keys():
[6105]161            self.flash(
162                'An applicants container for the same application '
163                'type and entrance year exists already in the database.')
[5822]164            return
165        # Add new applicants container...
[6083]166        provider = data['provider'][1]
[5822]167        container = provider.factory()
[6069]168        self.applyData(container, **data)
[6087]169        container.code = code
170        container.title = title
171        self.context[code] = container
[6105]172        self.flash('Added: "%s".' % code)
[6069]173        self.redirect(self.url(self.context, u'@@manage')+'#tab-1')
[5822]174        return
[6078]175
[6103]176    @grok.action('Cancel', validator=NullValidator)
[6069]177    def cancel(self, **data):
[6103]178        self.redirect(self.url(self.context, '@@manage') + '#tab-1')
[6078]179
[5845]180class ApplicantsRootBreadcrumb(Breadcrumb):
181    """A breadcrumb for applicantsroot.
182    """
183    grok.context(IApplicantsRoot)
184    title = u'Applicants'
[6078]185
[5845]186class ApplicantsContainerBreadcrumb(Breadcrumb):
187    """A breadcrumb for applicantscontainers.
188    """
189    grok.context(IApplicantsContainer)
[5828]190
191class ApplicantsTab(PrimaryNavTab):
192    """Faculties-tab in primary navigation.
193    """
[6078]194
[5828]195    grok.context(IWAeUPObject)
196    grok.order(3)
[6069]197    grok.require('waeup.manageUniversity')
[5828]198    grok.template('primarynavtab')
199
[5843]200    pnav = 3
[5828]201    tab_title = u'Applicants'
202
203    @property
204    def link_target(self):
205        return self.view.application_url('applicants')
206
[6029]207class ApplicantsContainerPage(WAeUPDisplayFormPage):
[5830]208    """The standard view for regular applicant containers.
209    """
210    grok.context(IApplicantsContainer)
211    grok.name('index')
[6029]212    grok.template('applicantscontainerpage')
[5850]213    pnav = 3
[6053]214
[6105]215    form_fields = grok.AutoFields(IApplicantsContainer).omit('title')
[6054]216    form_fields['startdate'].custom_widget = FriendlyDateDisplayWidget('le')
217    form_fields['enddate'].custom_widget = FriendlyDateDisplayWidget('le')
[6084]218    form_fields['description'].custom_widget = ReSTDisplayWidget
[6053]219
[5837]220    @property
221    def title(self):
[6087]222        return "Applicants Container: %s" % self.context.title
[5837]223
224    @property
225    def label(self):
[6087]226        return self.context.title
[5830]227
[5832]228class ManageApplicantsContainerActionButton(ManageActionButton):
229    grok.context(IApplicantsContainer)
230    grok.view(ApplicantsContainerPage)
[6070]231    text = 'Manage applicants container'
[5832]232
233
[5837]234class ManageApplicantsContainer(WAeUPEditFormPage):
235    grok.context(IApplicantsContainer)
[5850]236    grok.name('manage')
[5982]237    grok.template('form_manage_applicants_container')
[6105]238    form_fields = grok.AutoFields(IApplicantsContainer).omit('title')
239    taboneactions = ['Save','Cancel']
240    tabtwoactions = ['Add applicant', 'Remove selected','Cancel']
[5844]241    # Use friendlier date widget...
[6054]242    form_fields['startdate'].custom_widget = FriendlyDateWidget('le')
243    form_fields['enddate'].custom_widget = FriendlyDateWidget('le')
[5850]244
245    @property
246    def title(self):
[6087]247        return "Applicants Container: %s" % self.context.title
[6078]248
[5850]249    @property
250    def label(self):
[6087]251        return 'Manage applicants container'
[5850]252
[5845]253    pnav = 3
[5837]254
255    def update(self):
[5850]256        datepicker.need() # Enable jQuery datepicker in date fields.
[5982]257        tabs.need()
[6015]258        datatable.need()  # Enable jQurey datatables for contents listing
[5837]259        return super(ManageApplicantsContainer, self).update()
260
[5850]261    @grok.action('Save')
[5837]262    def apply(self, **data):
263        self.applyData(self.context, **data)
264        self.flash('Data saved.')
265        return
[6078]266
[6105]267    # ToDo: Show warning message before deletion
268    @grok.action('Remove selected')
269    def delApplicant(self, **data):
270        return self.flash('Removal of applicants is not yet implemented!')
271
272    @grok.action('Add applicant', validator=NullValidator)
273    def addApplicant(self, **data):
274        return self.flash('Manual addition of applicants not yet implemented!')
275
276    @grok.action('Cancel', validator=NullValidator)
[5837]277    def cancel(self, **data):
278        self.redirect(self.url(self.context))
279        return
[5886]280
[6105]281
[5886]282class LoginApplicant(WAeUPPage):
283    grok.context(IApplicantsContainer)
284    grok.name('login')
285    grok.require('zope.Public')
286
287    title = u'Login'
[6078]288
[5886]289    @property
290    def label(self):
291        return self.title
292
293    pnav = 3
294    prefix = u'APP'
[6078]295
[5896]296    def update(self, SUBMIT=None):
297        self.ac_series = self.request.form.get('form.ac_series', None)
298        self.ac_number = self.request.form.get('form.ac_number', None)
[5886]299        if SUBMIT is None:
300            return
301
[5894]302        if self.request.principal.id == 'zope.anybody':
[6105]303            self.flash('Entered credentials are invalid.')
[5886]304            return
[5894]305
306        if not IApplicantPrincipal.providedBy(self.request.principal):
307            # Don't care if user is already authenticated as non-applicant
308            return
309
[5905]310        pin = self.request.principal.access_code
311        if pin not in self.context.keys():
312            # Create applicant record
313            applicant = Applicant()
314            applicant.access_code = pin
315            self.context[pin] = applicant
[6078]316
[5937]317        # Assign current principal the owner role on created applicant
318        # record
319        role_manager = IPrincipalRoleManager(self.context)
320        role_manager.assignRoleToPrincipal(
[6043]321            'waeup.local.ApplicationOwner', self.request.principal.id)
[5937]322        self.redirect(self.url(self.context[pin], 'edit'))
[5886]323        return
324
[5273]325class DisplayApplicant(WAeUPDisplayFormPage):
326    grok.context(IApplicant)
327    grok.name('index')
[5937]328    grok.require('waeup.viewApplication')
[5941]329    form_fields = grok.AutoFields(IApplicant).omit('locked')
[5273]330    form_fields['fst_sit_results'].custom_widget = list_results_display_widget
[5919]331    form_fields['passport'].custom_widget = ThumbnailWidget
[6054]332    form_fields['date_of_birth'].custom_widget = FriendlyDateDisplayWidget('le')
[5273]333    label = 'Applicant'
334    title = 'Applicant'
[5843]335    pnav = 3
[5273]336
[5982]337class EditApplicantStudent(WAeUPEditFormPage):
338    """An applicant-centered edit view for applicant data.
339    """
[5273]340    grok.context(IApplicant)
341    grok.name('edit')
[5937]342    grok.require('waeup.editApplication')
[5941]343    form_fields = grok.AutoFields(IApplicantPDEEditData).omit('locked')
[5686]344    form_fields['passport'].custom_widget = EncodingImageFileWidget
[6054]345    form_fields['date_of_birth'].custom_widget = FriendlyDateWidget('le-year')
[5488]346    grok.template('form_edit_pde')
[5484]347
[5941]348    def emitLockMessage(self):
[6105]349        self.flash('The requested form is locked (read-only).')
[5941]350        self.redirect(self.url(self.context))
351        return
[6078]352
[5686]353    def update(self):
[5941]354        if self.context.locked:
355            self.emitLockMessage()
356            return
[6040]357        datepicker.need() # Enable jQuery datepicker in date fields.
[5982]358        super(EditApplicantStudent, self).update()
[5686]359        return
[5952]360
361    def filteredWidgets(self):
362        for widget in self.widgets:
363            if widget.name == 'form.confirm_passport':
364                continue
365            yield widget
366
[5484]367    @property
368    def label(self):
369        # XXX: Use current/upcoming session
370        return 'Apply for Post UDE Screening Test (2009/2010)'
[5273]371    title = 'Edit Application'
[5845]372    pnav = 3
[5273]373
374    @grok.action('Save')
375    def save(self, **data):
[5941]376        if self.context.locked:
377            self.emitLockMessage()
378            return
[5273]379        self.applyData(self.context, **data)
380        self.context._p_changed = True
381        return
382
[5484]383    @grok.action('Final Submit')
384    def finalsubmit(self, **data):
[5941]385        if self.context.locked:
386            self.emitLockMessage()
387            return
[5273]388        self.applyData(self.context, **data)
[5484]389        self.context._p_changed = True
[5941]390        if not self.dataComplete():
391            self.flash('Data yet not complete.')
392            return
393        self.context.locked = True
[5273]394        return
[5941]395
396    def dataComplete(self):
[6082]397        if self.context.confirm_passport is not True:
[5941]398            return False
399        if len(self.errors) > 0:
400            return False
401        return True
[5982]402
403class EditApplicantFull(WAeUPEditFormPage):
404    """A full edit view for applicant data.
405
406    This one is meant to be used by officers only.
407    """
408    grok.context(IApplicant)
409    grok.name('edit_full')
410    grok.require('waeup.editFullApplication')
411    form_fields = grok.AutoFields(IApplicantPDEEditData).omit('locked')
412    form_fields['passport'].custom_widget = EncodingImageFileWidget
[6054]413    form_fields['date_of_birth'].custom_widget = FriendlyDateWidget('le-year')
[5982]414    grok.template('form_edit_full')
415
416    def update(self):
417        if self.context.locked:
418            self.emitLockMessage()
419            return
[6041]420        datepicker.need() # Enable jQuery datepicker in date fields.
[5982]421        super(EditApplicantFull, self).update()
422        return
423
424    def filteredWidgets(self):
425        for widget in self.widgets:
426            if widget.name == 'form.confirm_passport':
427                continue
428            yield widget
429
430    @property
431    def label(self):
432        return 'Application for %s' % self.context.access_code
433    title = 'Edit Application'
434    pnav = 3
435
436    @grok.action('Save')
437    def save(self, **data):
438        self.applyData(self.context, **data)
439        self.context._p_changed = True
440        return
Note: See TracBrowser for help on using the repository browser.