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

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

Add attribute 'ac_prefix' to ApplicantsContainer? to preselect ac batches. Use this ac_prefix in loginapplicant.pt.

File size: 14.7 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')
[6107]91    grok.template('applicantsrootmanagepage')
[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()
[6108]101        datatable.need()
[6069]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')
[6107]138    grok.template('applicantscontaineraddpage')
[6069]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.
[6110]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
[6107]228class ApplicantsContainerManageActionButton(ManageActionButton):
[5832]229    grok.context(IApplicantsContainer)
230    grok.view(ApplicantsContainerPage)
[6070]231    text = 'Manage applicants container'
[5832]232
233
[6107]234class ApplicantsContainerManageFormPage(WAeUPEditFormPage):
[5837]235    grok.context(IApplicantsContainer)
[5850]236    grok.name('manage')
[6107]237    grok.template('applicantscontainermanagepage')
[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
[6107]259        return super(ApplicantsContainerManageFormPage, self).update()
[5837]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
[6110]287    @property
288    def title(self):
289        return u"Applicant Login: %s" % self.context.title
[6078]290
[5886]291    @property
292    def label(self):
[6110]293        return u'Login for applicants only'
[5886]294
295    pnav = 3
[6110]296   
297    @property
298    def ac_prefix(self):
299        return self.context.ac_prefix
[6078]300
[5896]301    def update(self, SUBMIT=None):
302        self.ac_series = self.request.form.get('form.ac_series', None)
303        self.ac_number = self.request.form.get('form.ac_number', None)
[5886]304        if SUBMIT is None:
305            return
306
[5894]307        if self.request.principal.id == 'zope.anybody':
[6105]308            self.flash('Entered credentials are invalid.')
[5886]309            return
[5894]310
311        if not IApplicantPrincipal.providedBy(self.request.principal):
312            # Don't care if user is already authenticated as non-applicant
313            return
314
[5905]315        pin = self.request.principal.access_code
316        if pin not in self.context.keys():
317            # Create applicant record
318            applicant = Applicant()
319            applicant.access_code = pin
320            self.context[pin] = applicant
[6078]321
[5937]322        # Assign current principal the owner role on created applicant
323        # record
324        role_manager = IPrincipalRoleManager(self.context)
325        role_manager.assignRoleToPrincipal(
[6043]326            'waeup.local.ApplicationOwner', self.request.principal.id)
[5937]327        self.redirect(self.url(self.context[pin], 'edit'))
[5886]328        return
329
[5273]330class DisplayApplicant(WAeUPDisplayFormPage):
331    grok.context(IApplicant)
332    grok.name('index')
[5937]333    grok.require('waeup.viewApplication')
[5941]334    form_fields = grok.AutoFields(IApplicant).omit('locked')
[5273]335    form_fields['fst_sit_results'].custom_widget = list_results_display_widget
[5919]336    form_fields['passport'].custom_widget = ThumbnailWidget
[6054]337    form_fields['date_of_birth'].custom_widget = FriendlyDateDisplayWidget('le')
[5273]338    label = 'Applicant'
339    title = 'Applicant'
[5843]340    pnav = 3
[5273]341
[5982]342class EditApplicantStudent(WAeUPEditFormPage):
343    """An applicant-centered edit view for applicant data.
344    """
[5273]345    grok.context(IApplicant)
346    grok.name('edit')
[5937]347    grok.require('waeup.editApplication')
[5941]348    form_fields = grok.AutoFields(IApplicantPDEEditData).omit('locked')
[5686]349    form_fields['passport'].custom_widget = EncodingImageFileWidget
[6054]350    form_fields['date_of_birth'].custom_widget = FriendlyDateWidget('le-year')
[5488]351    grok.template('form_edit_pde')
[5484]352
[5941]353    def emitLockMessage(self):
[6105]354        self.flash('The requested form is locked (read-only).')
[5941]355        self.redirect(self.url(self.context))
356        return
[6078]357
[5686]358    def update(self):
[5941]359        if self.context.locked:
360            self.emitLockMessage()
361            return
[6040]362        datepicker.need() # Enable jQuery datepicker in date fields.
[5982]363        super(EditApplicantStudent, self).update()
[5686]364        return
[5952]365
366    def filteredWidgets(self):
367        for widget in self.widgets:
368            if widget.name == 'form.confirm_passport':
369                continue
370            yield widget
371
[5484]372    @property
373    def label(self):
374        # XXX: Use current/upcoming session
375        return 'Apply for Post UDE Screening Test (2009/2010)'
[5273]376    title = 'Edit Application'
[5845]377    pnav = 3
[5273]378
379    @grok.action('Save')
380    def save(self, **data):
[5941]381        if self.context.locked:
382            self.emitLockMessage()
383            return
[5273]384        self.applyData(self.context, **data)
385        self.context._p_changed = True
386        return
387
[5484]388    @grok.action('Final Submit')
389    def finalsubmit(self, **data):
[5941]390        if self.context.locked:
391            self.emitLockMessage()
392            return
[5273]393        self.applyData(self.context, **data)
[5484]394        self.context._p_changed = True
[5941]395        if not self.dataComplete():
396            self.flash('Data yet not complete.')
397            return
398        self.context.locked = True
[5273]399        return
[5941]400
401    def dataComplete(self):
[6082]402        if self.context.confirm_passport is not True:
[5941]403            return False
404        if len(self.errors) > 0:
405            return False
406        return True
[5982]407
408class EditApplicantFull(WAeUPEditFormPage):
409    """A full edit view for applicant data.
410
411    This one is meant to be used by officers only.
412    """
413    grok.context(IApplicant)
414    grok.name('edit_full')
415    grok.require('waeup.editFullApplication')
416    form_fields = grok.AutoFields(IApplicantPDEEditData).omit('locked')
417    form_fields['passport'].custom_widget = EncodingImageFileWidget
[6054]418    form_fields['date_of_birth'].custom_widget = FriendlyDateWidget('le-year')
[5982]419    grok.template('form_edit_full')
420
421    def update(self):
422        if self.context.locked:
423            self.emitLockMessage()
424            return
[6041]425        datepicker.need() # Enable jQuery datepicker in date fields.
[5982]426        super(EditApplicantFull, self).update()
427        return
428
429    def filteredWidgets(self):
430        for widget in self.widgets:
431            if widget.name == 'form.confirm_passport':
432                continue
433            yield widget
434
435    @property
436    def label(self):
437        return 'Application for %s' % self.context.access_code
438    title = 'Edit Application'
439    pnav = 3
440
441    @grok.action('Save')
442    def save(self, **data):
443        self.applyData(self.context, **data)
444        self.context._p_changed = True
445        return
Note: See TracBrowser for help on using the repository browser.