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

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

Remove more trash, reorder imports.

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