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

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

Remove trailing whitespaces.

File size: 16.6 KB
Line 
1##
2## browser.py
3## Login : <uli@pu.smp.net>
4## Started on  Sun Jun 27 11:03:10 2010 Uli Fouquet
5## $Id$
6##
7## Copyright (C) 2010 Uli Fouquet & Henrik Bettermann
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.
12##
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.
17##
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##
22"""UI components for basic applicants and related components.
23"""
24import grok
25
26from datetime import datetime
27from hurry.jquery import jquery
28from hurry.jqueryui import jqueryui
29from zope.component import getUtility, getAllUtilitiesRegisteredFor, createObject
30from zope.formlib.widgets import FileWidget, DateWidget
31from zope.securitypolicy.interfaces import IPrincipalRoleManager
32from waeup.sirp.browser import (
33    WAeUPPage, WAeUPEditFormPage, WAeUPAddFormPage,
34    WAeUPDisplayFormPage, NullValidator)
35from waeup.sirp.browser.pages import LoginPage
36from waeup.sirp.interfaces import IWAeUPObject
37from waeup.sirp.browser.resources import datepicker, tabs, datatable
38from waeup.sirp.browser.viewlets import (
39    AddActionButton, ManageActionButton, PrimaryNavTab,
40    )
41from waeup.sirp.browser.breadcrumbs import Breadcrumb
42from waeup.sirp.applicants import get_applicant_data, ResultEntry, Applicant
43from waeup.sirp.applicants.interfaces import (
44    IApplicant, IApplicantPrincipal, IApplicantPDEEditData,
45    IApplicantsRoot, IApplicantsContainer, IApplicantsContainerProvider,
46    IApplicantsContainerAdd
47    )
48from waeup.sirp.widgets.passportwidget import (
49    PassportWidget, PassportDisplayWidget
50    )
51from waeup.sirp.widgets.datewidget import (
52    FriendlyDateWidget, FriendlyDateDisplayWidget)
53
54from waeup.sirp.widgets.restwidget import ReSTWidget
55
56#from zope.formlib.objectwidget import ObjectWidget
57from zope.formlib.sequencewidget import ListSequenceWidget, SequenceDisplayWidget
58from zope.formlib.widget import CustomWidgetFactory
59from waeup.sirp.utils.helpers import ReST2HTML
60from waeup.sirp.widgets.objectwidget import (
61    WAeUPObjectWidget, WAeUPObjectDisplayWidget)
62from waeup.sirp.widgets.multilistwidget import (
63    MultiListWidget, MultiListDisplayWidget)
64from waeup.sirp.image.browser.widget import (
65    ThumbnailWidget, EncodingImageFileWidget,
66    )
67
68results_widget = CustomWidgetFactory(
69    WAeUPObjectWidget, ResultEntry)
70
71results_display_widget = CustomWidgetFactory(
72    WAeUPObjectDisplayWidget, ResultEntry)
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
83class ApplicantsRootPage(WAeUPPage):
84    grok.context(IApplicantsRoot)
85    grok.name('index')
86    title = 'Applicants'
87    label = 'Application Section'
88    pnav = 3
89
90    def update(self):
91        super(ApplicantsRootPage, self).update()
92        datatable.need()
93        return
94
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))
101
102class ManageApplicantsRootActionButton(ManageActionButton):
103    grok.context(IApplicantsRoot)
104    grok.view(ApplicantsRootPage)
105    grok.require('waeup.manageUniversity')
106    text = 'Manage application section'
107
108class ApplicantsRootManageFormPage(WAeUPEditFormPage):
109    grok.context(IApplicantsRoot)
110    grok.name('manage')
111    grok.template('applicantsrooteditpage')
112    title = 'Applicants'
113    label = 'Manage application section'
114    pnav = 3
115    grok.require('waeup.manageUniversity')
116    taboneactions = ['Add applicants container', 'Remove selected','Cancel']
117    subunits = 'Applicants Containers'
118
119    def update(self):
120        tabs.need()
121        #warning.need()
122        return super(ApplicantsRootManageFormPage, self).update()
123
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))
141        self.redirect(self.url(self.context, '@@manage')+'#tab-1')
142        return
143
144    @grok.action('Add applicants container', validator=NullValidator)
145    def addApplicantsContainer(self, **data):
146        self.redirect(self.url(self.context, '@@add'))
147        return
148
149    @grok.action('Cancel', validator=NullValidator)
150    def cancel(self, **data):
151        self.redirect(self.url(self.context))
152        return
153
154class ApplicantsContainerAddFormPage(WAeUPAddFormPage):
155    grok.context(IApplicantsRoot)
156    grok.require('waeup.manageUniversity')
157    grok.name('add')
158    grok.template('applicantscontaineraddformpage')
159    title = 'Applicants'
160    label = 'Add applicants container'
161    pnav = 3
162
163    form_fields = grok.AutoFields(IApplicantsContainerAdd)
164    form_fields['startdate'].custom_widget = FriendlyDateDisplayWidget('le')
165    form_fields['enddate'].custom_widget = FriendlyDateDisplayWidget('le')
166    form_fields['description'].custom_widget = ReSTWidget
167
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')
173            return
174        # Add new applicants container...
175        provider = getUtility(IApplicantsContainerProvider,
176                              name=getattr(data['provider'],
177                                   'grokcore.component.directive.name'))
178        container = provider.factory()
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')
183        return
184
185    @grok.action('Cancel')
186    def cancel(self, **data):
187        self.redirect(self.url(self.context))
188
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
217
218class ApplicantsRootBreadcrumb(Breadcrumb):
219    """A breadcrumb for applicantsroot.
220    """
221    grok.context(IApplicantsRoot)
222    title = u'Applicants'
223
224class ApplicantsContainerBreadcrumb(Breadcrumb):
225    """A breadcrumb for applicantscontainers.
226    """
227    grok.context(IApplicantsContainer)
228
229class ApplicantsTab(PrimaryNavTab):
230    """Faculties-tab in primary navigation.
231    """
232
233    grok.context(IWAeUPObject)
234    grok.order(3)
235    grok.require('waeup.manageUniversity')
236    grok.template('primarynavtab')
237
238    pnav = 3
239    tab_title = u'Applicants'
240
241    @property
242    def link_target(self):
243        return self.view.application_url('applicants')
244
245class ApplicantsContainerPage(WAeUPDisplayFormPage):
246    """The standard view for regular applicant containers.
247    """
248    grok.context(IApplicantsContainer)
249    grok.name('index')
250    grok.template('applicantscontainerpage')
251    pnav = 3
252
253    form_fields = grok.AutoFields(IApplicantsContainer)
254    # Use friendlier date widget...
255    form_fields['startdate'].custom_widget = FriendlyDateDisplayWidget('le')
256    form_fields['enddate'].custom_widget = FriendlyDateDisplayWidget('le')
257    form_fields['description'].custom_widget = ReSTWidget
258
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
267
268    #def descriptionToHTML(self):
269    #    if self.context.description:
270    #        return ReST2HTML(self.context.description)
271    #    else:
272    #        return
273
274
275
276class ManageApplicantsContainerActionButton(ManageActionButton):
277    grok.context(IApplicantsContainer)
278    grok.view(ApplicantsContainerPage)
279    text = 'Manage applicants container'
280
281
282class ManageApplicantsContainer(WAeUPEditFormPage):
283    grok.context(IApplicantsContainer)
284    grok.name('manage')
285    grok.template('form_manage_applicants_container')
286    form_fields = grok.AutoFields(IApplicantsContainer)
287    # Use friendlier date widget...
288    form_fields['startdate'].custom_widget = FriendlyDateWidget('le')
289    form_fields['enddate'].custom_widget = FriendlyDateWidget('le')
290
291    @property
292    def title(self):
293        return "Manage applicants container: %s" % getattr(
294            self.context, '__name__', 'unnamed')
295
296    @property
297    def label(self):
298        return self.title
299
300    pnav = 3
301
302    def update(self):
303        datepicker.need() # Enable jQuery datepicker in date fields.
304        tabs.need()
305        datatable.need()  # Enable jQurey datatables for contents listing
306        return super(ManageApplicantsContainer, self).update()
307
308    @grok.action('Save')
309    def apply(self, **data):
310        self.applyData(self.context, **data)
311        self.flash('Data saved.')
312        return
313
314    @grok.action('Back')
315    def cancel(self, **data):
316        self.redirect(self.url(self.context))
317        return
318
319class LoginApplicant(WAeUPPage):
320    grok.context(IApplicantsContainer)
321    grok.name('login')
322    grok.require('zope.Public')
323
324    title = u'Login'
325
326    @property
327    def label(self):
328        return self.title
329
330    pnav = 3
331    prefix = u'APP'
332
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)
336        if SUBMIT is None:
337            return
338
339        if self.request.principal.id == 'zope.anybody':
340            self.flash('Entered credentials are invalid')
341            return
342
343        if not IApplicantPrincipal.providedBy(self.request.principal):
344            # Don't care if user is already authenticated as non-applicant
345            return
346
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
353
354        # Assign current principal the owner role on created applicant
355        # record
356        role_manager = IPrincipalRoleManager(self.context)
357        role_manager.assignRoleToPrincipal(
358            'waeup.local.ApplicationOwner', self.request.principal.id)
359        self.redirect(self.url(self.context[pin], 'edit'))
360        return
361
362#class AddApplicant(WAeUPAddFormPage):
363#    grok.context(IApplicantsContainer)
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))
385
386class DisplayApplicant(WAeUPDisplayFormPage):
387    grok.context(IApplicant)
388    grok.name('index')
389    grok.require('waeup.viewApplication')
390    form_fields = grok.AutoFields(IApplicant).omit('locked')
391    form_fields['fst_sit_results'].custom_widget = list_results_display_widget
392    form_fields['passport'].custom_widget = ThumbnailWidget
393    form_fields['date_of_birth'].custom_widget = FriendlyDateDisplayWidget('le')
394    label = 'Applicant'
395    title = 'Applicant'
396    pnav = 3
397
398class EditApplicantStudent(WAeUPEditFormPage):
399    """An applicant-centered edit view for applicant data.
400    """
401    grok.context(IApplicant)
402    grok.name('edit')
403    grok.require('waeup.editApplication')
404    form_fields = grok.AutoFields(IApplicantPDEEditData).omit('locked')
405    form_fields['passport'].custom_widget = EncodingImageFileWidget
406    form_fields['date_of_birth'].custom_widget = FriendlyDateWidget('le-year')
407    grok.template('form_edit_pde')
408
409    def emitLockMessage(self):
410        self.flash('The requested form is locked (read-only)')
411        self.redirect(self.url(self.context))
412        return
413
414    def update(self):
415        if self.context.locked:
416            self.emitLockMessage()
417            return
418        datepicker.need() # Enable jQuery datepicker in date fields.
419        super(EditApplicantStudent, self).update()
420        return
421
422    def filteredWidgets(self):
423        for widget in self.widgets:
424            if widget.name == 'form.confirm_passport':
425                continue
426            yield widget
427
428    @property
429    def label(self):
430        # XXX: Use current/upcoming session
431        return 'Apply for Post UDE Screening Test (2009/2010)'
432    title = 'Edit Application'
433    pnav = 3
434
435    @grok.action('Save')
436    def save(self, **data):
437        if self.context.locked:
438            self.emitLockMessage()
439            return
440        self.applyData(self.context, **data)
441        self.context._p_changed = True
442        return
443
444    @grok.action('Final Submit')
445    def finalsubmit(self, **data):
446        if self.context.locked:
447            self.emitLockMessage()
448            return
449        self.applyData(self.context, **data)
450        self.context._p_changed = True
451        if not self.dataComplete():
452            self.flash('Data yet not complete.')
453            return
454        self.context.locked = True
455        return
456
457    def dataComplete(self):
458        if context.confirm_passport is not True:
459            return False
460        if len(self.errors) > 0:
461            return False
462        return True
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
474    form_fields['date_of_birth'].custom_widget = FriendlyDateWidget('le-year')
475    grok.template('form_edit_full')
476
477    def update(self):
478        if self.context.locked:
479            self.emitLockMessage()
480            return
481        datepicker.need() # Enable jQuery datepicker in date fields.
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.