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

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

Adding some attributes to ApplicantsContainer?. Generate title and code of containers automatically.

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