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

Last change on this file since 6082 was 6082, checked in by uli, 14 years ago

Reorder imports, fixes.

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)
[6078]44from waeup.sirp.widgets.restwidget import ReSTWidget
[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)
[6070]143    form_fields['startdate'].custom_widget = FriendlyDateDisplayWidget('le')
144    form_fields['enddate'].custom_widget = FriendlyDateDisplayWidget('le')
[6078]145    form_fields['description'].custom_widget = ReSTWidget
146
[6069]147    @grok.action('Add applicants container')
148    def addApplicantsContainer(self, **data):
149        if data['code'] in self.context.keys():
150            self.status = Invalid('The name chosen already exists '
151                                  'in the database')
[5822]152            return
153        # Add new applicants container...
[5846]154        provider = getUtility(IApplicantsContainerProvider,
[6078]155                              name=getattr(data['provider'],
[6069]156                                   'grokcore.component.directive.name'))
[5822]157        container = provider.factory()
[6069]158        self.applyData(container, **data)
159        self.context[data['code']] = container
160        self.flash('Added "%s".' % data['code'])
161        self.redirect(self.url(self.context, u'@@manage')+'#tab-1')
[5822]162        return
[6078]163
[6069]164    @grok.action('Cancel')
165    def cancel(self, **data):
[6078]166        self.redirect(self.url(self.context))
167
[5845]168class ApplicantsRootBreadcrumb(Breadcrumb):
169    """A breadcrumb for applicantsroot.
170    """
171    grok.context(IApplicantsRoot)
172    title = u'Applicants'
[6078]173
[5845]174class ApplicantsContainerBreadcrumb(Breadcrumb):
175    """A breadcrumb for applicantscontainers.
176    """
177    grok.context(IApplicantsContainer)
[5828]178
179class ApplicantsTab(PrimaryNavTab):
180    """Faculties-tab in primary navigation.
181    """
[6078]182
[5828]183    grok.context(IWAeUPObject)
184    grok.order(3)
[6069]185    grok.require('waeup.manageUniversity')
[5828]186    grok.template('primarynavtab')
187
[5843]188    pnav = 3
[5828]189    tab_title = u'Applicants'
190
191    @property
192    def link_target(self):
193        return self.view.application_url('applicants')
194
[6029]195class ApplicantsContainerPage(WAeUPDisplayFormPage):
[5830]196    """The standard view for regular applicant containers.
197    """
198    grok.context(IApplicantsContainer)
199    grok.name('index')
[6029]200    grok.template('applicantscontainerpage')
[5850]201    pnav = 3
[6053]202
203    form_fields = grok.AutoFields(IApplicantsContainer)
204    # Use friendlier date widget...
[6054]205    form_fields['startdate'].custom_widget = FriendlyDateDisplayWidget('le')
206    form_fields['enddate'].custom_widget = FriendlyDateDisplayWidget('le')
[6063]207    form_fields['description'].custom_widget = ReSTWidget
[6053]208
[5837]209    @property
210    def title(self):
211        return "Applicants Container: %s" % getattr(
212            self.context, '__name__', 'unnamed')
213
214    @property
215    def label(self):
216        return self.title
[5830]217
[5850]218
[5832]219class ManageApplicantsContainerActionButton(ManageActionButton):
220    grok.context(IApplicantsContainer)
221    grok.view(ApplicantsContainerPage)
[6070]222    text = 'Manage applicants container'
[5832]223
224
[5837]225class ManageApplicantsContainer(WAeUPEditFormPage):
226    grok.context(IApplicantsContainer)
[5850]227    grok.name('manage')
[5982]228    grok.template('form_manage_applicants_container')
[5837]229    form_fields = grok.AutoFields(IApplicantsContainer)
[5844]230    # Use friendlier date widget...
[6054]231    form_fields['startdate'].custom_widget = FriendlyDateWidget('le')
232    form_fields['enddate'].custom_widget = FriendlyDateWidget('le')
[5850]233
234    @property
235    def title(self):
236        return "Manage applicants container: %s" % getattr(
237            self.context, '__name__', 'unnamed')
[6078]238
[5850]239    @property
240    def label(self):
241        return self.title
242
[5845]243    pnav = 3
[5837]244
245    def update(self):
[5850]246        datepicker.need() # Enable jQuery datepicker in date fields.
[5982]247        tabs.need()
[6015]248        datatable.need()  # Enable jQurey datatables for contents listing
[5837]249        return super(ManageApplicantsContainer, self).update()
250
[5850]251    @grok.action('Save')
[5837]252    def apply(self, **data):
253        self.applyData(self.context, **data)
254        self.flash('Data saved.')
255        return
[6078]256
[5837]257    @grok.action('Back')
258    def cancel(self, **data):
259        self.redirect(self.url(self.context))
260        return
[5886]261
262class LoginApplicant(WAeUPPage):
263    grok.context(IApplicantsContainer)
264    grok.name('login')
265    grok.require('zope.Public')
266
267    title = u'Login'
[6078]268
[5886]269    @property
270    def label(self):
271        return self.title
272
273    pnav = 3
274    prefix = u'APP'
[6078]275
[5896]276    def update(self, SUBMIT=None):
277        self.ac_series = self.request.form.get('form.ac_series', None)
278        self.ac_number = self.request.form.get('form.ac_number', None)
[5886]279        if SUBMIT is None:
280            return
281
[5894]282        if self.request.principal.id == 'zope.anybody':
283            self.flash('Entered credentials are invalid')
[5886]284            return
[5894]285
286        if not IApplicantPrincipal.providedBy(self.request.principal):
287            # Don't care if user is already authenticated as non-applicant
288            return
289
[5905]290        pin = self.request.principal.access_code
291        if pin not in self.context.keys():
292            # Create applicant record
293            applicant = Applicant()
294            applicant.access_code = pin
295            self.context[pin] = applicant
[6078]296
[5937]297        # Assign current principal the owner role on created applicant
298        # record
299        role_manager = IPrincipalRoleManager(self.context)
300        role_manager.assignRoleToPrincipal(
[6043]301            'waeup.local.ApplicationOwner', self.request.principal.id)
[5937]302        self.redirect(self.url(self.context[pin], 'edit'))
[5886]303        return
304
[5273]305class DisplayApplicant(WAeUPDisplayFormPage):
306    grok.context(IApplicant)
307    grok.name('index')
[5937]308    grok.require('waeup.viewApplication')
[5941]309    form_fields = grok.AutoFields(IApplicant).omit('locked')
[5273]310    form_fields['fst_sit_results'].custom_widget = list_results_display_widget
[5919]311    form_fields['passport'].custom_widget = ThumbnailWidget
[6054]312    form_fields['date_of_birth'].custom_widget = FriendlyDateDisplayWidget('le')
[5273]313    label = 'Applicant'
314    title = 'Applicant'
[5843]315    pnav = 3
[5273]316
[5982]317class EditApplicantStudent(WAeUPEditFormPage):
318    """An applicant-centered edit view for applicant data.
319    """
[5273]320    grok.context(IApplicant)
321    grok.name('edit')
[5937]322    grok.require('waeup.editApplication')
[5941]323    form_fields = grok.AutoFields(IApplicantPDEEditData).omit('locked')
[5686]324    form_fields['passport'].custom_widget = EncodingImageFileWidget
[6054]325    form_fields['date_of_birth'].custom_widget = FriendlyDateWidget('le-year')
[5488]326    grok.template('form_edit_pde')
[5484]327
[5941]328    def emitLockMessage(self):
329        self.flash('The requested form is locked (read-only)')
330        self.redirect(self.url(self.context))
331        return
[6078]332
[5686]333    def update(self):
[5941]334        if self.context.locked:
335            self.emitLockMessage()
336            return
[6040]337        datepicker.need() # Enable jQuery datepicker in date fields.
[5982]338        super(EditApplicantStudent, self).update()
[5686]339        return
[5952]340
341    def filteredWidgets(self):
342        for widget in self.widgets:
343            if widget.name == 'form.confirm_passport':
344                continue
345            yield widget
346
[5484]347    @property
348    def label(self):
349        # XXX: Use current/upcoming session
350        return 'Apply for Post UDE Screening Test (2009/2010)'
[5273]351    title = 'Edit Application'
[5845]352    pnav = 3
[5273]353
354    @grok.action('Save')
355    def save(self, **data):
[5941]356        if self.context.locked:
357            self.emitLockMessage()
358            return
[5273]359        self.applyData(self.context, **data)
360        self.context._p_changed = True
361        return
362
[5484]363    @grok.action('Final Submit')
364    def finalsubmit(self, **data):
[5941]365        if self.context.locked:
366            self.emitLockMessage()
367            return
[5273]368        self.applyData(self.context, **data)
[5484]369        self.context._p_changed = True
[5941]370        if not self.dataComplete():
371            self.flash('Data yet not complete.')
372            return
373        self.context.locked = True
[5273]374        return
[5941]375
376    def dataComplete(self):
[6082]377        if self.context.confirm_passport is not True:
[5941]378            return False
379        if len(self.errors) > 0:
380            return False
381        return True
[5982]382
383class EditApplicantFull(WAeUPEditFormPage):
384    """A full edit view for applicant data.
385
386    This one is meant to be used by officers only.
387    """
388    grok.context(IApplicant)
389    grok.name('edit_full')
390    grok.require('waeup.editFullApplication')
391    form_fields = grok.AutoFields(IApplicantPDEEditData).omit('locked')
392    form_fields['passport'].custom_widget = EncodingImageFileWidget
[6054]393    form_fields['date_of_birth'].custom_widget = FriendlyDateWidget('le-year')
[5982]394    grok.template('form_edit_full')
395
396    def update(self):
397        if self.context.locked:
398            self.emitLockMessage()
399            return
[6041]400        datepicker.need() # Enable jQuery datepicker in date fields.
[5982]401        super(EditApplicantFull, self).update()
402        return
403
404    def filteredWidgets(self):
405        for widget in self.widgets:
406            if widget.name == 'form.confirm_passport':
407                continue
408            yield widget
409
410    @property
411    def label(self):
412        return 'Application for %s' % self.context.access_code
413    title = 'Edit Application'
414    pnav = 3
415
416    @grok.action('Save')
417    def save(self, **data):
418        self.applyData(self.context, **data)
419        self.context._p_changed = True
420        return
Note: See TracBrowser for help on using the repository browser.