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

Last change on this file since 5847 was 5847, checked in by Henrik Bettermann, 14 years ago

Also save name attribute. Otherwise the breadcrumb remains empty.

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