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

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

Rename views and page templates according to the convention in the university package.

File size: 14.5 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        #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('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    title = u'Login'
288
289    @property
290    def label(self):
291        return self.title
292
293    pnav = 3
294    prefix = u'APP'
295
296    def update(self, SUBMIT=None):
297        self.ac_series = self.request.form.get('form.ac_series', None)
298        self.ac_number = self.request.form.get('form.ac_number', None)
299        if SUBMIT is None:
300            return
301
302        if self.request.principal.id == 'zope.anybody':
303            self.flash('Entered credentials are invalid.')
304            return
305
306        if not IApplicantPrincipal.providedBy(self.request.principal):
307            # Don't care if user is already authenticated as non-applicant
308            return
309
310        pin = self.request.principal.access_code
311        if pin not in self.context.keys():
312            # Create applicant record
313            applicant = Applicant()
314            applicant.access_code = pin
315            self.context[pin] = applicant
316
317        # Assign current principal the owner role on created applicant
318        # record
319        role_manager = IPrincipalRoleManager(self.context)
320        role_manager.assignRoleToPrincipal(
321            'waeup.local.ApplicationOwner', self.request.principal.id)
322        self.redirect(self.url(self.context[pin], 'edit'))
323        return
324
325class DisplayApplicant(WAeUPDisplayFormPage):
326    grok.context(IApplicant)
327    grok.name('index')
328    grok.require('waeup.viewApplication')
329    form_fields = grok.AutoFields(IApplicant).omit('locked')
330    form_fields['fst_sit_results'].custom_widget = list_results_display_widget
331    form_fields['passport'].custom_widget = ThumbnailWidget
332    form_fields['date_of_birth'].custom_widget = FriendlyDateDisplayWidget('le')
333    label = 'Applicant'
334    title = 'Applicant'
335    pnav = 3
336
337class EditApplicantStudent(WAeUPEditFormPage):
338    """An applicant-centered edit view for applicant data.
339    """
340    grok.context(IApplicant)
341    grok.name('edit')
342    grok.require('waeup.editApplication')
343    form_fields = grok.AutoFields(IApplicantPDEEditData).omit('locked')
344    form_fields['passport'].custom_widget = EncodingImageFileWidget
345    form_fields['date_of_birth'].custom_widget = FriendlyDateWidget('le-year')
346    grok.template('form_edit_pde')
347
348    def emitLockMessage(self):
349        self.flash('The requested form is locked (read-only).')
350        self.redirect(self.url(self.context))
351        return
352
353    def update(self):
354        if self.context.locked:
355            self.emitLockMessage()
356            return
357        datepicker.need() # Enable jQuery datepicker in date fields.
358        super(EditApplicantStudent, self).update()
359        return
360
361    def filteredWidgets(self):
362        for widget in self.widgets:
363            if widget.name == 'form.confirm_passport':
364                continue
365            yield widget
366
367    @property
368    def label(self):
369        # XXX: Use current/upcoming session
370        return 'Apply for Post UDE Screening Test (2009/2010)'
371    title = 'Edit Application'
372    pnav = 3
373
374    @grok.action('Save')
375    def save(self, **data):
376        if self.context.locked:
377            self.emitLockMessage()
378            return
379        self.applyData(self.context, **data)
380        self.context._p_changed = True
381        return
382
383    @grok.action('Final Submit')
384    def finalsubmit(self, **data):
385        if self.context.locked:
386            self.emitLockMessage()
387            return
388        self.applyData(self.context, **data)
389        self.context._p_changed = True
390        if not self.dataComplete():
391            self.flash('Data yet not complete.')
392            return
393        self.context.locked = True
394        return
395
396    def dataComplete(self):
397        if self.context.confirm_passport is not True:
398            return False
399        if len(self.errors) > 0:
400            return False
401        return True
402
403class EditApplicantFull(WAeUPEditFormPage):
404    """A full edit view for applicant data.
405
406    This one is meant to be used by officers only.
407    """
408    grok.context(IApplicant)
409    grok.name('edit_full')
410    grok.require('waeup.editFullApplication')
411    form_fields = grok.AutoFields(IApplicantPDEEditData).omit('locked')
412    form_fields['passport'].custom_widget = EncodingImageFileWidget
413    form_fields['date_of_birth'].custom_widget = FriendlyDateWidget('le-year')
414    grok.template('form_edit_full')
415
416    def update(self):
417        if self.context.locked:
418            self.emitLockMessage()
419            return
420        datepicker.need() # Enable jQuery datepicker in date fields.
421        super(EditApplicantFull, self).update()
422        return
423
424    def filteredWidgets(self):
425        for widget in self.widgets:
426            if widget.name == 'form.confirm_passport':
427                continue
428            yield widget
429
430    @property
431    def label(self):
432        return 'Application for %s' % self.context.access_code
433    title = 'Edit Application'
434    pnav = 3
435
436    @grok.action('Save')
437    def save(self, **data):
438        self.applyData(self.context, **data)
439        self.context._p_changed = True
440        return
Note: See TracBrowser for help on using the repository browser.