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

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

Remove trailing whitespaces.

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