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

Last change on this file since 6103 was 6103, checked in by uli, 14 years ago
  • Make 'cancel' work in addform.
  • Shorten attribute value computation.
File size: 14.0 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 & Henrik Bettermann
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 sys
25import grok
26
27from zope.component import getUtility
28from zope.formlib.widget import CustomWidgetFactory
29from zope.interface import Invalid
30from zope.securitypolicy.interfaces import IPrincipalRoleManager
31
32from waeup.sirp.browser import (
33    WAeUPPage, WAeUPEditFormPage, WAeUPAddFormPage,
34    WAeUPDisplayFormPage, NullValidator)
35from waeup.sirp.browser.breadcrumbs import Breadcrumb
36from waeup.sirp.browser.layout import NullValidator
37from waeup.sirp.browser.resources import datepicker, tabs, datatable
38from waeup.sirp.browser.viewlets import ManageActionButton, PrimaryNavTab
39from waeup.sirp.image.browser.widget import (
40    ThumbnailWidget, EncodingImageFileWidget,
41    )
42from waeup.sirp.interfaces import IWAeUPObject
43from waeup.sirp.widgets.datewidget import (
44    FriendlyDateWidget, FriendlyDateDisplayWidget)
45from waeup.sirp.widgets.restwidget import ReSTDisplayWidget
46from waeup.sirp.widgets.objectwidget import (
47    WAeUPObjectWidget, WAeUPObjectDisplayWidget)
48from waeup.sirp.widgets.multilistwidget import (
49    MultiListWidget, MultiListDisplayWidget)
50
51from waeup.sirp.applicants import ResultEntry, Applicant
52from waeup.sirp.applicants.interfaces import (
53    IApplicant, IApplicantPrincipal, IApplicantPDEEditData,
54    IApplicantsRoot, IApplicantsContainer, IApplicantsContainerProvider,
55    IApplicantsContainerAdd, application_types_vocab
56    )
57
58results_widget = CustomWidgetFactory(
59    WAeUPObjectWidget, ResultEntry)
60
61results_display_widget = CustomWidgetFactory(
62    WAeUPObjectDisplayWidget, ResultEntry)
63
64list_results_widget = CustomWidgetFactory(
65    MultiListWidget, subwidget=results_widget)
66
67list_results_display_widget = CustomWidgetFactory(
68    MultiListDisplayWidget, subwidget=results_display_widget)
69
70class ApplicantsRootPage(WAeUPPage):
71    grok.context(IApplicantsRoot)
72    grok.name('index')
73    title = 'Applicants'
74    label = 'Application Section'
75    pnav = 3
76
77    def update(self):
78        super(ApplicantsRootPage, self).update()
79        datatable.need()
80        return
81
82class ManageApplicantsRootActionButton(ManageActionButton):
83    grok.context(IApplicantsRoot)
84    grok.view(ApplicantsRootPage)
85    grok.require('waeup.manageUniversity')
86    text = 'Manage application section'
87
88class ApplicantsRootManageFormPage(WAeUPEditFormPage):
89    grok.context(IApplicantsRoot)
90    grok.name('manage')
91    grok.template('applicantsrooteditpage')
92    title = 'Applicants'
93    label = 'Manage application section'
94    pnav = 3
95    grok.require('waeup.manageUniversity')
96    taboneactions = ['Add applicants container', 'Remove selected','Cancel']
97    subunits = 'Applicants Containers'
98
99    def update(self):
100        tabs.need()
101        #warning.need()
102        return super(ApplicantsRootManageFormPage, self).update()
103
104    # ToDo: Show warning message before deletion
105    @grok.action('Remove selected')
106    def delApplicantsContainers(self, **data):
107        form = self.request.form
108        child_id = form['val_id']
109        if not isinstance(child_id, list):
110            child_id = [child_id]
111        deleted = []
112        for id in child_id:
113            try:
114                del self.context[id]
115                deleted.append(id)
116            except:
117                self.flash('Could not delete %s: %s: %s' % (
118                        id, sys.exc_info()[0], sys.exc_info()[1]))
119        if len(deleted):
120            self.flash('Successfully removed: %s' % ', '.join(deleted))
121        self.redirect(self.url(self.context, '@@manage')+'#tab-1')
122        return
123
124    @grok.action('Add applicants container', validator=NullValidator)
125    def addApplicantsContainer(self, **data):
126        self.redirect(self.url(self.context, '@@add'))
127        return
128
129    @grok.action('Cancel', validator=NullValidator)
130    def cancel(self, **data):
131        self.redirect(self.url(self.context))
132        return
133
134class ApplicantsContainerAddFormPage(WAeUPAddFormPage):
135    grok.context(IApplicantsRoot)
136    grok.require('waeup.manageUniversity')
137    grok.name('add')
138    grok.template('applicantscontaineraddformpage')
139    title = 'Applicants'
140    label = 'Add applicants container'
141    pnav = 3
142
143    form_fields = grok.AutoFields(
144        IApplicantsContainerAdd).omit('code').omit('title')
145    form_fields['startdate'].custom_widget = FriendlyDateWidget('le')
146    form_fields['enddate'].custom_widget = FriendlyDateWidget('le')
147
148    def update(self):
149        datepicker.need() # Enable jQuery datepicker in date fields.
150        from waeup.sirp.browser.resources import jqueryui
151        jqueryui.need()
152        return super(ApplicantsContainerAddFormPage, self).update()
153
154    @grok.action('Add applicants container')
155    def addApplicantsContainer(self, **data):
156        year = data['year']
157        code = u'%s%s' % (data['prefix'], year)
158        prefix = application_types_vocab.getTerm(data['prefix'])
159        title = u'%s %s/%s' % (prefix.title, year, year + 1)
160        if code in self.context.keys():
161            self.status = Invalid(
162                'Error: An applicants container for the same application '
163                'type and entrance year exists already in the database')
164            return
165        # Add new applicants container...
166        provider = data['provider'][1]
167        container = provider.factory()
168        self.applyData(container, **data)
169        container.code = code
170        container.title = title
171        self.context[code] = container
172        self.flash('Added "%s".' % code)
173        self.redirect(self.url(self.context, u'@@manage')+'#tab-1')
174        return
175
176    @grok.action('Cancel', validator=NullValidator)
177    def cancel(self, **data):
178        self.redirect(self.url(self.context, '@@manage') + '#tab-1')
179
180class ApplicantsRootBreadcrumb(Breadcrumb):
181    """A breadcrumb for applicantsroot.
182    """
183    grok.context(IApplicantsRoot)
184    title = u'Applicants'
185
186class ApplicantsContainerBreadcrumb(Breadcrumb):
187    """A breadcrumb for applicantscontainers.
188    """
189    grok.context(IApplicantsContainer)
190
191class ApplicantsTab(PrimaryNavTab):
192    """Faculties-tab in primary navigation.
193    """
194
195    grok.context(IWAeUPObject)
196    grok.order(3)
197    grok.require('waeup.manageUniversity')
198    grok.template('primarynavtab')
199
200    pnav = 3
201    tab_title = u'Applicants'
202
203    @property
204    def link_target(self):
205        return self.view.application_url('applicants')
206
207class ApplicantsContainerPage(WAeUPDisplayFormPage):
208    """The standard view for regular applicant containers.
209    """
210    grok.context(IApplicantsContainer)
211    grok.name('index')
212    grok.template('applicantscontainerpage')
213    pnav = 3
214
215    form_fields = grok.AutoFields(IApplicantsContainer)
216    # Use friendlier date widget...
217    form_fields['startdate'].custom_widget = FriendlyDateDisplayWidget('le')
218    form_fields['enddate'].custom_widget = FriendlyDateDisplayWidget('le')
219    form_fields['description'].custom_widget = ReSTDisplayWidget
220
221    @property
222    def title(self):
223        return "Applicants Container: %s" % self.context.title
224
225    @property
226    def label(self):
227        return self.context.title
228
229class ManageApplicantsContainerActionButton(ManageActionButton):
230    grok.context(IApplicantsContainer)
231    grok.view(ApplicantsContainerPage)
232    text = 'Manage applicants container'
233
234
235class ManageApplicantsContainer(WAeUPEditFormPage):
236    grok.context(IApplicantsContainer)
237    grok.name('manage')
238    grok.template('form_manage_applicants_container')
239    form_fields = grok.AutoFields(IApplicantsContainer)
240    # Use friendlier date widget...
241    form_fields['startdate'].custom_widget = FriendlyDateWidget('le')
242    form_fields['enddate'].custom_widget = FriendlyDateWidget('le')
243
244    @property
245    def title(self):
246        return "Applicants Container: %s" % self.context.title
247
248    @property
249    def label(self):
250        return 'Manage applicants container'
251
252    pnav = 3
253
254    def update(self):
255        datepicker.need() # Enable jQuery datepicker in date fields.
256        tabs.need()
257        datatable.need()  # Enable jQurey datatables for contents listing
258        return super(ManageApplicantsContainer, self).update()
259
260    @grok.action('Save')
261    def apply(self, **data):
262        self.applyData(self.context, **data)
263        self.flash('Data saved.')
264        return
265
266    @grok.action('Back')
267    def cancel(self, **data):
268        self.redirect(self.url(self.context))
269        return
270
271class LoginApplicant(WAeUPPage):
272    grok.context(IApplicantsContainer)
273    grok.name('login')
274    grok.require('zope.Public')
275
276    title = u'Login'
277
278    @property
279    def label(self):
280        return self.title
281
282    pnav = 3
283    prefix = u'APP'
284
285    def update(self, SUBMIT=None):
286        self.ac_series = self.request.form.get('form.ac_series', None)
287        self.ac_number = self.request.form.get('form.ac_number', None)
288        if SUBMIT is None:
289            return
290
291        if self.request.principal.id == 'zope.anybody':
292            self.flash('Entered credentials are invalid')
293            return
294
295        if not IApplicantPrincipal.providedBy(self.request.principal):
296            # Don't care if user is already authenticated as non-applicant
297            return
298
299        pin = self.request.principal.access_code
300        if pin not in self.context.keys():
301            # Create applicant record
302            applicant = Applicant()
303            applicant.access_code = pin
304            self.context[pin] = applicant
305
306        # Assign current principal the owner role on created applicant
307        # record
308        role_manager = IPrincipalRoleManager(self.context)
309        role_manager.assignRoleToPrincipal(
310            'waeup.local.ApplicationOwner', self.request.principal.id)
311        self.redirect(self.url(self.context[pin], 'edit'))
312        return
313
314class DisplayApplicant(WAeUPDisplayFormPage):
315    grok.context(IApplicant)
316    grok.name('index')
317    grok.require('waeup.viewApplication')
318    form_fields = grok.AutoFields(IApplicant).omit('locked')
319    form_fields['fst_sit_results'].custom_widget = list_results_display_widget
320    form_fields['passport'].custom_widget = ThumbnailWidget
321    form_fields['date_of_birth'].custom_widget = FriendlyDateDisplayWidget('le')
322    label = 'Applicant'
323    title = 'Applicant'
324    pnav = 3
325
326class EditApplicantStudent(WAeUPEditFormPage):
327    """An applicant-centered edit view for applicant data.
328    """
329    grok.context(IApplicant)
330    grok.name('edit')
331    grok.require('waeup.editApplication')
332    form_fields = grok.AutoFields(IApplicantPDEEditData).omit('locked')
333    form_fields['passport'].custom_widget = EncodingImageFileWidget
334    form_fields['date_of_birth'].custom_widget = FriendlyDateWidget('le-year')
335    grok.template('form_edit_pde')
336
337    def emitLockMessage(self):
338        self.flash('The requested form is locked (read-only)')
339        self.redirect(self.url(self.context))
340        return
341
342    def update(self):
343        if self.context.locked:
344            self.emitLockMessage()
345            return
346        datepicker.need() # Enable jQuery datepicker in date fields.
347        super(EditApplicantStudent, self).update()
348        return
349
350    def filteredWidgets(self):
351        for widget in self.widgets:
352            if widget.name == 'form.confirm_passport':
353                continue
354            yield widget
355
356    @property
357    def label(self):
358        # XXX: Use current/upcoming session
359        return 'Apply for Post UDE Screening Test (2009/2010)'
360    title = 'Edit Application'
361    pnav = 3
362
363    @grok.action('Save')
364    def save(self, **data):
365        if self.context.locked:
366            self.emitLockMessage()
367            return
368        self.applyData(self.context, **data)
369        self.context._p_changed = True
370        return
371
372    @grok.action('Final Submit')
373    def finalsubmit(self, **data):
374        if self.context.locked:
375            self.emitLockMessage()
376            return
377        self.applyData(self.context, **data)
378        self.context._p_changed = True
379        if not self.dataComplete():
380            self.flash('Data yet not complete.')
381            return
382        self.context.locked = True
383        return
384
385    def dataComplete(self):
386        if self.context.confirm_passport is not True:
387            return False
388        if len(self.errors) > 0:
389            return False
390        return True
391
392class EditApplicantFull(WAeUPEditFormPage):
393    """A full edit view for applicant data.
394
395    This one is meant to be used by officers only.
396    """
397    grok.context(IApplicant)
398    grok.name('edit_full')
399    grok.require('waeup.editFullApplication')
400    form_fields = grok.AutoFields(IApplicantPDEEditData).omit('locked')
401    form_fields['passport'].custom_widget = EncodingImageFileWidget
402    form_fields['date_of_birth'].custom_widget = FriendlyDateWidget('le-year')
403    grok.template('form_edit_full')
404
405    def update(self):
406        if self.context.locked:
407            self.emitLockMessage()
408            return
409        datepicker.need() # Enable jQuery datepicker in date fields.
410        super(EditApplicantFull, self).update()
411        return
412
413    def filteredWidgets(self):
414        for widget in self.widgets:
415            if widget.name == 'form.confirm_passport':
416                continue
417            yield widget
418
419    @property
420    def label(self):
421        return 'Application for %s' % self.context.access_code
422    title = 'Edit Application'
423    pnav = 3
424
425    @grok.action('Save')
426    def save(self, **data):
427        self.applyData(self.context, **data)
428        self.context._p_changed = True
429        return
Note: See TracBrowser for help on using the repository browser.