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

Last change on this file since 6110 was 6110, checked in by Henrik Bettermann, 13 years ago

Add attribute 'ac_prefix' to ApplicantsContainer? to preselect ac batches. Use this ac_prefix in loginapplicant.pt.

File size: 14.7 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('applicantsrootmanagepage')
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        datatable.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('applicantscontaineraddpage')
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.flash(
162                '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).omit('title')
216    form_fields['startdate'].custom_widget = FriendlyDateDisplayWidget('le')
217    form_fields['enddate'].custom_widget = FriendlyDateDisplayWidget('le')
218    form_fields['description'].custom_widget = ReSTDisplayWidget
219
220    @property
221    def title(self):
222        return "Applicants Container: %s" % self.context.title
223
224    @property
225    def label(self):
226        return self.context.title
227
228class ApplicantsContainerManageActionButton(ManageActionButton):
229    grok.context(IApplicantsContainer)
230    grok.view(ApplicantsContainerPage)
231    text = 'Manage applicants container'
232
233
234class ApplicantsContainerManageFormPage(WAeUPEditFormPage):
235    grok.context(IApplicantsContainer)
236    grok.name('manage')
237    grok.template('applicantscontainermanagepage')
238    form_fields = grok.AutoFields(IApplicantsContainer).omit('title')
239    taboneactions = ['Save','Cancel']
240    tabtwoactions = ['Add applicant', 'Remove selected','Cancel']
241    # Use friendlier date widget...
242    form_fields['startdate'].custom_widget = FriendlyDateWidget('le')
243    form_fields['enddate'].custom_widget = FriendlyDateWidget('le')
244
245    @property
246    def title(self):
247        return "Applicants Container: %s" % self.context.title
248
249    @property
250    def label(self):
251        return 'Manage applicants container'
252
253    pnav = 3
254
255    def update(self):
256        datepicker.need() # Enable jQuery datepicker in date fields.
257        tabs.need()
258        datatable.need()  # Enable jQurey datatables for contents listing
259        return super(ApplicantsContainerManageFormPage, self).update()
260
261    @grok.action('Save')
262    def apply(self, **data):
263        self.applyData(self.context, **data)
264        self.flash('Data saved.')
265        return
266
267    # ToDo: Show warning message before deletion
268    @grok.action('Remove selected')
269    def delApplicant(self, **data):
270        return self.flash('Removal of applicants is not yet implemented!')
271
272    @grok.action('Add applicant', validator=NullValidator)
273    def addApplicant(self, **data):
274        return self.flash('Manual addition of applicants not yet implemented!')
275
276    @grok.action('Cancel', validator=NullValidator)
277    def cancel(self, **data):
278        self.redirect(self.url(self.context))
279        return
280
281
282class LoginApplicant(WAeUPPage):
283    grok.context(IApplicantsContainer)
284    grok.name('login')
285    grok.require('zope.Public')
286
287    @property
288    def title(self):
289        return u"Applicant Login: %s" % self.context.title
290
291    @property
292    def label(self):
293        return u'Login for applicants only'
294
295    pnav = 3
296   
297    @property
298    def ac_prefix(self):
299        return self.context.ac_prefix
300
301    def update(self, SUBMIT=None):
302        self.ac_series = self.request.form.get('form.ac_series', None)
303        self.ac_number = self.request.form.get('form.ac_number', None)
304        if SUBMIT is None:
305            return
306
307        if self.request.principal.id == 'zope.anybody':
308            self.flash('Entered credentials are invalid.')
309            return
310
311        if not IApplicantPrincipal.providedBy(self.request.principal):
312            # Don't care if user is already authenticated as non-applicant
313            return
314
315        pin = self.request.principal.access_code
316        if pin not in self.context.keys():
317            # Create applicant record
318            applicant = Applicant()
319            applicant.access_code = pin
320            self.context[pin] = applicant
321
322        # Assign current principal the owner role on created applicant
323        # record
324        role_manager = IPrincipalRoleManager(self.context)
325        role_manager.assignRoleToPrincipal(
326            'waeup.local.ApplicationOwner', self.request.principal.id)
327        self.redirect(self.url(self.context[pin], 'edit'))
328        return
329
330class DisplayApplicant(WAeUPDisplayFormPage):
331    grok.context(IApplicant)
332    grok.name('index')
333    grok.require('waeup.viewApplication')
334    form_fields = grok.AutoFields(IApplicant).omit('locked')
335    form_fields['fst_sit_results'].custom_widget = list_results_display_widget
336    form_fields['passport'].custom_widget = ThumbnailWidget
337    form_fields['date_of_birth'].custom_widget = FriendlyDateDisplayWidget('le')
338    label = 'Applicant'
339    title = 'Applicant'
340    pnav = 3
341
342class EditApplicantStudent(WAeUPEditFormPage):
343    """An applicant-centered edit view for applicant data.
344    """
345    grok.context(IApplicant)
346    grok.name('edit')
347    grok.require('waeup.editApplication')
348    form_fields = grok.AutoFields(IApplicantPDEEditData).omit('locked')
349    form_fields['passport'].custom_widget = EncodingImageFileWidget
350    form_fields['date_of_birth'].custom_widget = FriendlyDateWidget('le-year')
351    grok.template('form_edit_pde')
352
353    def emitLockMessage(self):
354        self.flash('The requested form is locked (read-only).')
355        self.redirect(self.url(self.context))
356        return
357
358    def update(self):
359        if self.context.locked:
360            self.emitLockMessage()
361            return
362        datepicker.need() # Enable jQuery datepicker in date fields.
363        super(EditApplicantStudent, self).update()
364        return
365
366    def filteredWidgets(self):
367        for widget in self.widgets:
368            if widget.name == 'form.confirm_passport':
369                continue
370            yield widget
371
372    @property
373    def label(self):
374        # XXX: Use current/upcoming session
375        return 'Apply for Post UDE Screening Test (2009/2010)'
376    title = 'Edit Application'
377    pnav = 3
378
379    @grok.action('Save')
380    def save(self, **data):
381        if self.context.locked:
382            self.emitLockMessage()
383            return
384        self.applyData(self.context, **data)
385        self.context._p_changed = True
386        return
387
388    @grok.action('Final Submit')
389    def finalsubmit(self, **data):
390        if self.context.locked:
391            self.emitLockMessage()
392            return
393        self.applyData(self.context, **data)
394        self.context._p_changed = True
395        if not self.dataComplete():
396            self.flash('Data yet not complete.')
397            return
398        self.context.locked = True
399        return
400
401    def dataComplete(self):
402        if self.context.confirm_passport is not True:
403            return False
404        if len(self.errors) > 0:
405            return False
406        return True
407
408class EditApplicantFull(WAeUPEditFormPage):
409    """A full edit view for applicant data.
410
411    This one is meant to be used by officers only.
412    """
413    grok.context(IApplicant)
414    grok.name('edit_full')
415    grok.require('waeup.editFullApplication')
416    form_fields = grok.AutoFields(IApplicantPDEEditData).omit('locked')
417    form_fields['passport'].custom_widget = EncodingImageFileWidget
418    form_fields['date_of_birth'].custom_widget = FriendlyDateWidget('le-year')
419    grok.template('form_edit_full')
420
421    def update(self):
422        if self.context.locked:
423            self.emitLockMessage()
424            return
425        datepicker.need() # Enable jQuery datepicker in date fields.
426        super(EditApplicantFull, self).update()
427        return
428
429    def filteredWidgets(self):
430        for widget in self.widgets:
431            if widget.name == 'form.confirm_passport':
432                continue
433            yield widget
434
435    @property
436    def label(self):
437        return 'Application for %s' % self.context.access_code
438    title = 'Edit Application'
439    pnav = 3
440
441    @grok.action('Save')
442    def save(self, **data):
443        self.applyData(self.context, **data)
444        self.context._p_changed = True
445        return
Note: See TracBrowser for help on using the repository browser.