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
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
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 waeup.sirp.browser import (
32    WAeUPPage, WAeUPEditFormPage, WAeUPAddFormPage,
33    WAeUPDisplayFormPage, NullValidator)
34from waeup.sirp.browser.pages import LoginPage
35from waeup.sirp.interfaces import IWAeUPObject
36from waeup.sirp.browser.resources import datepicker
37from waeup.sirp.browser.viewlets import (
38    AddActionButton, ManageActionButton, PrimaryNavTab,
39    )
40from waeup.sirp.applicants import get_applicant_data, ResultEntry
41from waeup.sirp.applicants.interfaces import (
42    IApplicant, IApplicantPrincipal, IApplicantPDEEditData,
43    IApplicantsRoot, IApplicantsContainer, IApplicantContainerProvider,
44    )
45from waeup.sirp.widgets.passportwidget import (
46    PassportWidget, PassportDisplayWidget
47    )
48#from zope.formlib.objectwidget import ObjectWidget
49from zope.formlib.sequencewidget import ListSequenceWidget, SequenceDisplayWidget
50from zope.formlib.widget import CustomWidgetFactory
51from waeup.sirp.widgets.objectwidget import (
52    WAeUPObjectWidget, WAeUPObjectDisplayWidget)
53from waeup.sirp.widgets.multilistwidget import (
54    MultiListWidget, MultiListDisplayWidget)
55from waeup.sirp.image.browser.widget import (
56    ThumbnailWidget, EncodingImageFileWidget,
57    )
58
59results_widget = CustomWidgetFactory(
60    WAeUPObjectWidget, ResultEntry)
61
62results_display_widget = CustomWidgetFactory(
63    WAeUPObjectDisplayWidget, ResultEntry)
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
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
80class ApplicationsPage(WAeUPPage):
81    grok.context(IApplicantsRoot)
82    grok.name('index')
83    title = 'Applicants'
84    pnav = 3
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))
92
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'
103    pnav = 3
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
127class AddApplicantsContainerActionButton(AddActionButton):
128    grok.context(IApplicantsRoot)
129    grok.view(ApplicantsRootEditPage)
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'
137    pnav = 3
138
139    def update(self, providername=None, name=None, title=None,
140               description=None, ADD=None, CANCEL=None):
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()
156        if title:
157            container.title = title
158        if description:
159            container.description = description
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):
166        """Get a list of applicants container providers.
167
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        """
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
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
203    pnav = 3
204    tab_title = u'Applicants'
205
206    @property
207    def link_target(self):
208        return self.view.application_url('applicants')
209
210class ApplicantsContainerPage(WAeUPPage):
211    """The standard view for regular applicant containers.
212    """
213    grok.context(IApplicantsContainer)
214    grok.name('index')
215
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
224    pnav = 3
225
226class ManageApplicantsContainerActionButton(ManageActionButton):
227    grok.context(IApplicantsContainer)
228    grok.view(ApplicantsContainerPage)
229    text = 'Manage'
230
231class ApplicantsContainerEditPage(WAeUPPage):
232    """Manage/edit a container for regular applicants.
233    """
234    grok.context(IApplicantsContainer)
235    grok.name('manage')
236
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
246    pnav = 3
247
248    def update(self, CANCEL=None, SAVE=None,
249               title=None, description=None, startdate=None, enddate=None):
250        datepicker.need()
251
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)
295    # Use friendlier date widget...
296    form_fields['startdate'].custom_widget = FriendlyDateWidget
297    form_fields['enddate'].custom_widget = FriendlyDateWidget
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   
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))
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
346    #form_fields['passport'].custom_widget = PassportDisplayWidget
347    form_fields['passport'].custom_widget = ThumbnailWidget
348    label = 'Applicant'
349    title = 'Applicant'
350    pnav = 3
351
352class EditApplicant(WAeUPEditFormPage):
353    grok.context(IApplicant)
354    grok.name('edit')
355    form_fields = grok.AutoFields(IApplicantPDEEditData)
356    #form_fields['passport'].custom_widget = FileWidget
357    #form_fields['passport'].custom_widget = PassportWidget
358    form_fields['passport'].custom_widget = EncodingImageFileWidget
359    grok.template('form_edit_pde')
360
361    def update(self):
362        super(EditApplicant, self).update()
363        print self.request.form
364        return
365   
366    @property
367    def label(self):
368        # XXX: Use current/upcoming session
369        return 'Apply for Post UDE Screening Test (2009/2010)'
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
379    @grok.action('Final Submit')
380    def finalsubmit(self, **data):
381        self.applyData(self.context, **data)
382        self.context._p_changed = True
383        # XXX: Lock the form for editing...
384        return
Note: See TracBrowser for help on using the repository browser.