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

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

Rename RestWidget? to RestDisplayWidget?.

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