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

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

Start renaming the views in the applicants package according to the naming convention made in the university package.

The getApplications method is not really necessary since we only store ApplicantsContainers? here.

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