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

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

Enable jQuery datepicker in a form (where we, in contrast to views or
pages, do not render HTML ourselves but use widgets for that job).

File size: 12.4 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$
6##
7## Copyright (C) 2010 Uli Fouquet
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##
[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
[5822]29from zope.component import getUtility, getAllUtilitiesRegisteredFor
[5844]30from zope.formlib.widgets import FileWidget, DateWidget
[5273]31from waeup.sirp.browser import (
32    WAeUPPage, WAeUPEditFormPage, WAeUPAddFormPage,
33    WAeUPDisplayFormPage, NullValidator)
[5442]34from waeup.sirp.browser.pages import LoginPage
[5320]35from waeup.sirp.interfaces import IWAeUPObject
[5837]36from waeup.sirp.browser.resources import datepicker
[5828]37from waeup.sirp.browser.viewlets import (
38    AddActionButton, ManageActionButton, PrimaryNavTab,
39    )
[5806]40from waeup.sirp.applicants import get_applicant_data, ResultEntry
[5758]41from waeup.sirp.applicants.interfaces import (
[5822]42    IApplicant, IApplicantPrincipal, IApplicantPDEEditData,
43    IApplicantsRoot, IApplicantsContainer, IApplicantContainerProvider,
44    )
[5686]45from waeup.sirp.widgets.passportwidget import (
46    PassportWidget, PassportDisplayWidget
47    )
[5273]48#from zope.formlib.objectwidget import ObjectWidget
49from zope.formlib.sequencewidget import ListSequenceWidget, SequenceDisplayWidget
50from zope.formlib.widget import CustomWidgetFactory
[5303]51from waeup.sirp.widgets.objectwidget import (
[5301]52    WAeUPObjectWidget, WAeUPObjectDisplayWidget)
[5303]53from waeup.sirp.widgets.multilistwidget import (
[5273]54    MultiListWidget, MultiListDisplayWidget)
[5686]55from waeup.sirp.image.browser.widget import (
56    ThumbnailWidget, EncodingImageFileWidget,
57    )
[5320]58
[5273]59results_widget = CustomWidgetFactory(
[5301]60    WAeUPObjectWidget, ResultEntry)
[5273]61
62results_display_widget = CustomWidgetFactory(
[5301]63    WAeUPObjectDisplayWidget, ResultEntry)
[5273]64
65#list_results_widget = CustomWidgetFactory(
66#    ListSequenceWidget, subwidget=results_widget)
67
68list_results_widget = CustomWidgetFactory(
69    MultiListWidget, subwidget=results_widget)
70
71list_results_display_widget = CustomWidgetFactory(
72    MultiListDisplayWidget, subwidget=results_display_widget)
73
[5844]74#: A date widget that renders with CSS class `datepicker` thus
75#  enabling : the jQuery datepicker for this field if the form loaded
76#  the jQuery code.
77FriendlyDateWidget = CustomWidgetFactory(
78    DateWidget, cssClass='datepicker')
79
[5822]80class ApplicationsPage(WAeUPPage):
81    grok.context(IApplicantsRoot)
82    grok.name('index')
83    title = 'Applicants'
[5843]84    pnav = 3
[5822]85   
86    def getApplications(self):
87        """Get a list of all stored applicant containers.
88        """
89        for key, val in self.context.items():
90            url = self.url(val)
91            yield(dict(url=url, name=key))
[5273]92
[5828]93class ManageApplicantsRootActionButton(ManageActionButton):
94    grok.context(IApplicantsRoot)
95    grok.view(ApplicationsPage)
96    text = 'Manage applicant containers'
97
98class ApplicantsRootEditPage(WAeUPPage):
99    grok.context(IApplicantsRoot)
100    grok.name('manage')
101    grok.template('applicantsrooteditpage')
102    title = 'Edit applicants containers'
[5843]103    pnav = 3
[5828]104
105    def update(self, entries=None, DELETE=None, CANCEL=None):
106        if CANCEL is not None:
107            self.redirect(self.url(self.context))
108            return
109        if DELETE is None:
110            return
111        if entries is None:
112            return
113        if not isinstance(entries, list):
114            entries = [entries]
115        for name in entries:
116            del self.context[name]
117            self.flash('Deleted "%s"' % name)
118        return
119
120    def getApplications(self):
121        """Get a list of all stored applicant containers.
122        """
123        for key, val in self.context.items():
124            url = self.url(val)
125            yield(dict(url=url, name=key))
126
[5822]127class AddApplicantsContainerActionButton(AddActionButton):
128    grok.context(IApplicantsRoot)
[5828]129    grok.view(ApplicantsRootEditPage)
[5822]130    text = 'Add applicants container'
131
132class AddApplicantsContainer(WAeUPPage):
133    grok.context(IApplicantsRoot)
134    grok.name('add')
135    grok.template('addcontainer')
136    title = 'Add applicants container'
[5843]137    pnav = 3
[5822]138
[5828]139    def update(self, providername=None, name=None, title=None,
140               description=None, ADD=None, CANCEL=None):
[5822]141        if CANCEL is not None:
142            self.redirect(self.url(self.context))
143            return
144        if ADD is None:
145            return
146        if not name:
147            self.flash('Error: you must give a name')
148            return
149        if name in self.context.keys():
150            self.flash('A container of the given name already exists')
151            return
152        # Add new applicants container...
153        provider = getUtility(IApplicantContainerProvider,
154                              name=providername)
155        container = provider.factory()
[5828]156        if title:
157            container.title = title
158        if description:
159            container.description = description
[5822]160        self.context[name] = container
161        self.flash('Added "%s".' % name)
162        self.redirect(self.url(self.context))
163        return
164       
165    def getContainerProviders(self):
[5825]166        """Get a list of applicants container providers.
[5822]167
[5825]168        Applicants container providers are named utilities that help
169        to create applicants containers of different types
170        (JAMB-based, non-JAMB-based, etc.).
171
172        The list returned contains dicts::
173
174          {'name': <utility_name>,
175           'provider': <provider instance>}
176
177        where `utility_name` is the name under which the respective
178        provider utility is registered and `provider` is the real
179        provider instance.
180
181        The `utility_name` can be used to lookup the utility anew (for
182        instance after submitting a form) and the `provider` instance
183        can be used to create new instances of the respective
184        applicants container type.
185        """
[5822]186        providers = getAllUtilitiesRegisteredFor(IApplicantContainerProvider)
187        result = [
188            {'name': getattr(x, 'grokcore.component.directive.name'),
189             'provider': x}
190             for x in providers
191            ]
192        return result
[5828]193
194
195class ApplicantsTab(PrimaryNavTab):
196    """Faculties-tab in primary navigation.
197    """
198    grok.context(IWAeUPObject)
199    grok.order(3)
200    grok.require('waeup.View')
201    grok.template('primarynavtab')
202
[5843]203    pnav = 3
[5828]204    tab_title = u'Applicants'
205
206    @property
207    def link_target(self):
208        return self.view.application_url('applicants')
209
[5830]210class ApplicantsContainerPage(WAeUPPage):
211    """The standard view for regular applicant containers.
212    """
213    grok.context(IApplicantsContainer)
214    grok.name('index')
[5828]215
[5837]216    @property
217    def title(self):
218        return "Applicants Container: %s" % getattr(
219            self.context, '__name__', 'unnamed')
220
221    @property
222    def label(self):
223        return self.title
[5843]224    pnav = 3
[5830]225
[5832]226class ManageApplicantsContainerActionButton(ManageActionButton):
227    grok.context(IApplicantsContainer)
228    grok.view(ApplicantsContainerPage)
229    text = 'Manage'
230
231class ApplicantsContainerEditPage(WAeUPPage):
[5837]232    """Manage/edit a container for regular applicants.
233    """
[5832]234    grok.context(IApplicantsContainer)
235    grok.name('manage')
236
[5837]237    @property
238    def title(self):
239        return "Manage applicants container: %s" % getattr(
240            self.context, '__name__', 'unnamed')
241   
242    @property
243    def label(self):
244        return self.title
245
[5843]246    pnav = 3
[5832]247
[5837]248    def update(self, CANCEL=None, SAVE=None,
249               title=None, description=None, startdate=None, enddate=None):
250        datepicker.need()
[5832]251
[5837]252        if CANCEL is not None:
253            self.redirect(self.url(self.context))
254            return
255        if SAVE is None:
256            return
257        self.context.title = title
258        self.context.description = description
259        try:
260            self.context.startdate = datetime.strptime(startdate, '%Y-%m-%d')
261        except ValueError:
262            pass
263        try:
264            self.context.enddate = datetime.strptime(enddate, '%Y-%m-%d')
265        except ValueError:
266            pass
267        self.flash('Data saved.')
268        return
269
270    def getFormattedDates(self):
271        """Returns a dict with formatted start- and enddate.
272
273        Returns dates of form ``YYYY-MM-DD`` based on the start and
274        enddates of the context container. The result dict has
275        format::
276
277          { 'start': '<YYYY-MM-DD>',
278            'end': '<YYYY-MM-DD>'}
279
280        Each value can also be ``''`` (empty string) if unset.
281        """
282        start = ''
283        if self.context.startdate is not None:
284            start = datetime.strftime(self.context.startdate, '%Y-%m-%d')
285        end = ''
286        if self.context.enddate is not None:
287            end = datetime.strftime(self.context.enddate, '%Y-%m-%d')
288        return {'start' : start, 'end' : end }
289
290
291class ManageApplicantsContainer(WAeUPEditFormPage):
292    grok.context(IApplicantsContainer)
293    grok.name('edit')
294    form_fields = grok.AutoFields(IApplicantsContainer)
[5844]295    # Use friendlier date widget...
296    form_fields['startdate'].custom_widget = FriendlyDateWidget
297    form_fields['enddate'].custom_widget = FriendlyDateWidget
[5837]298    label = 'Edit container'
299    title = label
300    pnav = 2
301
302    def update(self):
303        datepicker.need()
304        return super(ManageApplicantsContainer, self).update()
305
306    @grok.action('Apply')
307    def apply(self, **data):
308        self.applyData(self.context, **data)
309        self.flash('Data saved.')
310        return
311       
312    @grok.action('Back')
313    def cancel(self, **data):
314        self.redirect(self.url(self.context))
315        return
316   
[5758]317#class AddApplicant(WAeUPAddFormPage):
318#    grok.context(IApplicantContainer)
319#    grok.name('add')
320#    form_fields = grok.AutoFields(IApplicant)
321#    form_fields['fst_sit_results'].custom_widget = list_results_widget
322#    form_fields['passport'].custom_widget = EncodingImageFileWidget
323#    label = 'Add Applicant'
324#    title = 'Add Applicant'
325#    pnav = 1
326#
327#    @grok.action('Add applicant')
328#    def addApplicant(self, **data):
329#        from waeup.sirp.jambtables.applicants import Applicant
330#        applicant = Applicant()
331#        self.applyData(applicant, **data)
332#        # XXX: temporarily disabled.
333#        #self.context[applicant.reg_no] = applicant
334#        try:
335#            self.context[applicant.access_code] = applicant
336#        except KeyError:
337#            self.flash('The given access code is already in use!')
338#            return
339#        self.redirect(self.url(self.context))
[5273]340
341class DisplayApplicant(WAeUPDisplayFormPage):
342    grok.context(IApplicant)
343    grok.name('index')
344    form_fields = grok.AutoFields(IApplicant)
345    form_fields['fst_sit_results'].custom_widget = list_results_display_widget
[5686]346    #form_fields['passport'].custom_widget = PassportDisplayWidget
347    form_fields['passport'].custom_widget = ThumbnailWidget
[5273]348    label = 'Applicant'
349    title = 'Applicant'
[5843]350    pnav = 3
[5273]351
352class EditApplicant(WAeUPEditFormPage):
353    grok.context(IApplicant)
354    grok.name('edit')
[5484]355    form_fields = grok.AutoFields(IApplicantPDEEditData)
[5686]356    #form_fields['passport'].custom_widget = FileWidget
357    #form_fields['passport'].custom_widget = PassportWidget
358    form_fields['passport'].custom_widget = EncodingImageFileWidget
[5488]359    grok.template('form_edit_pde')
[5484]360
[5686]361    def update(self):
362        super(EditApplicant, self).update()
363        print self.request.form
364        return
365   
[5484]366    @property
367    def label(self):
368        # XXX: Use current/upcoming session
369        return 'Apply for Post UDE Screening Test (2009/2010)'
[5273]370    title = 'Edit Application'
371    pnav = 1
372
373    @grok.action('Save')
374    def save(self, **data):
375        self.applyData(self.context, **data)
376        self.context._p_changed = True
377        return
378
[5484]379    @grok.action('Final Submit')
380    def finalsubmit(self, **data):
[5273]381        self.applyData(self.context, **data)
[5484]382        self.context._p_changed = True
383        # XXX: Lock the form for editing...
[5273]384        return
Note: See TracBrowser for help on using the repository browser.