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
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    )
[5845]40from waeup.sirp.browser.breadcrumbs import Breadcrumb
[5806]41from waeup.sirp.applicants import get_applicant_data, ResultEntry
[5758]42from waeup.sirp.applicants.interfaces import (
[5822]43    IApplicant, IApplicantPrincipal, IApplicantPDEEditData,
[5846]44    IApplicantsRoot, IApplicantsContainer, IApplicantsContainerProvider,
[5822]45    )
[5686]46from waeup.sirp.widgets.passportwidget import (
47    PassportWidget, PassportDisplayWidget
48    )
[5273]49#from zope.formlib.objectwidget import ObjectWidget
50from zope.formlib.sequencewidget import ListSequenceWidget, SequenceDisplayWidget
51from zope.formlib.widget import CustomWidgetFactory
[5850]52from waeup.sirp.utils.helpers import ReST2HTML
[5303]53from waeup.sirp.widgets.objectwidget import (
[5301]54    WAeUPObjectWidget, WAeUPObjectDisplayWidget)
[5303]55from waeup.sirp.widgets.multilistwidget import (
[5273]56    MultiListWidget, MultiListDisplayWidget)
[5686]57from waeup.sirp.image.browser.widget import (
58    ThumbnailWidget, EncodingImageFileWidget,
59    )
[5320]60
[5273]61results_widget = CustomWidgetFactory(
[5301]62    WAeUPObjectWidget, ResultEntry)
[5273]63
64results_display_widget = CustomWidgetFactory(
[5301]65    WAeUPObjectDisplayWidget, ResultEntry)
[5273]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
[5844]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
[5822]82class ApplicationsPage(WAeUPPage):
83    grok.context(IApplicantsRoot)
84    grok.name('index')
85    title = 'Applicants'
[5843]86    pnav = 3
[5822]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))
[5273]94
[5828]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'
[5843]105    pnav = 3
[5828]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
[5822]129class AddApplicantsContainerActionButton(AddActionButton):
130    grok.context(IApplicantsRoot)
[5828]131    grok.view(ApplicantsRootEditPage)
[5822]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'
[5843]139    pnav = 3
[5822]140
[5828]141    def update(self, providername=None, name=None, title=None,
142               description=None, ADD=None, CANCEL=None):
[5822]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...
[5846]155        provider = getUtility(IApplicantsContainerProvider,
[5822]156                              name=providername)
157        container = provider.factory()
[5847]158        container.name = name
[5828]159        if title:
160            container.title = title
161        if description:
162            container.description = description
[5822]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):
[5825]169        """Get a list of applicants container providers.
[5822]170
[5825]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        """
[5846]189        providers = getAllUtilitiesRegisteredFor(IApplicantsContainerProvider)
[5822]190        result = [
191            {'name': getattr(x, 'grokcore.component.directive.name'),
192             'provider': x}
193             for x in providers
194            ]
195        return result
[5828]196
[5845]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)
[5828]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
[5843]216    pnav = 3
[5828]217    tab_title = u'Applicants'
218
219    @property
220    def link_target(self):
221        return self.view.application_url('applicants')
222
[5830]223class ApplicantsContainerPage(WAeUPPage):
224    """The standard view for regular applicant containers.
225    """
226    grok.context(IApplicantsContainer)
227    grok.name('index')
[5850]228    pnav = 3
229   
[5837]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
[5830]238
[5850]239    def descriptionToHTML(self):
240        return ReST2HTML(self.context.description)
241
[5832]242class ManageApplicantsContainerActionButton(ManageActionButton):
243    grok.context(IApplicantsContainer)
244    grok.view(ApplicantsContainerPage)
245    text = 'Manage'
246
247class ApplicantsContainerEditPage(WAeUPPage):
[5837]248    """Manage/edit a container for regular applicants.
249    """
[5832]250    grok.context(IApplicantsContainer)
[5850]251    grok.name('manage2')
[5832]252
[5837]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
[5843]262    pnav = 3
[5832]263
[5837]264    def update(self, CANCEL=None, SAVE=None,
265               title=None, description=None, startdate=None, enddate=None):
266        datepicker.need()
[5832]267
[5837]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)
[5850]309    grok.name('manage')
[5837]310    form_fields = grok.AutoFields(IApplicantsContainer)
[5844]311    # Use friendlier date widget...
312    form_fields['startdate'].custom_widget = FriendlyDateWidget
313    form_fields['enddate'].custom_widget = FriendlyDateWidget
[5850]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
[5845]324    pnav = 3
[5837]325
326    def update(self):
[5850]327        datepicker.need() # Enable jQuery datepicker in date fields.
[5837]328        return super(ManageApplicantsContainer, self).update()
329
[5850]330    @grok.action('Save')
[5837]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   
[5758]341#class AddApplicant(WAeUPAddFormPage):
[5846]342#    grok.context(IApplicantsContainer)
[5758]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))
[5273]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
[5686]370    #form_fields['passport'].custom_widget = PassportDisplayWidget
371    form_fields['passport'].custom_widget = ThumbnailWidget
[5273]372    label = 'Applicant'
373    title = 'Applicant'
[5843]374    pnav = 3
[5273]375
376class EditApplicant(WAeUPEditFormPage):
377    grok.context(IApplicant)
378    grok.name('edit')
[5484]379    form_fields = grok.AutoFields(IApplicantPDEEditData)
[5686]380    #form_fields['passport'].custom_widget = FileWidget
381    #form_fields['passport'].custom_widget = PassportWidget
382    form_fields['passport'].custom_widget = EncodingImageFileWidget
[5488]383    grok.template('form_edit_pde')
[5484]384
[5686]385    def update(self):
386        super(EditApplicant, self).update()
387        print self.request.form
388        return
389   
[5484]390    @property
391    def label(self):
392        # XXX: Use current/upcoming session
393        return 'Apply for Post UDE Screening Test (2009/2010)'
[5273]394    title = 'Edit Application'
[5845]395    pnav = 3
[5273]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
[5484]403    @grok.action('Final Submit')
404    def finalsubmit(self, **data):
[5273]405        self.applyData(self.context, **data)
[5484]406        self.context._p_changed = True
407        # XXX: Lock the form for editing...
[5273]408        return
Note: See TracBrowser for help on using the repository browser.