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

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