## ## browser.py ## Login : ## Started on Sun Jun 27 11:03:10 2010 Uli Fouquet & Henrik Bettermann ## $Id$ ## ## Copyright (C) 2010 Uli Fouquet & Henrik Bettermann ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; if not, write to the Free Software ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ## """UI components for basic applicants and related components. """ import sys import grok from zope.component import getUtility from zope.formlib.widget import CustomWidgetFactory from zope.interface import Invalid from zope.securitypolicy.interfaces import IPrincipalRoleManager from zope.traversing.browser import absoluteURL from waeup.sirp.browser import ( WAeUPPage, WAeUPEditFormPage, WAeUPAddFormPage, WAeUPDisplayFormPage, NullValidator) from waeup.sirp.browser.breadcrumbs import Breadcrumb from waeup.sirp.browser.layout import NullValidator from waeup.sirp.browser.resources import datepicker, tabs, datatable from waeup.sirp.browser.viewlets import ( ManageActionButton, PrimaryNavTab, LeftSidebarLink ) from waeup.sirp.image.browser.widget import ( ThumbnailWidget, EncodingImageFileWidget, ) from waeup.sirp.interfaces import IWAeUPObject from waeup.sirp.widgets.datewidget import ( FriendlyDateWidget, FriendlyDateDisplayWidget) from waeup.sirp.widgets.restwidget import ReSTDisplayWidget from waeup.sirp.widgets.objectwidget import ( WAeUPObjectWidget, WAeUPObjectDisplayWidget) from waeup.sirp.widgets.multilistwidget import ( MultiListWidget, MultiListDisplayWidget) from waeup.sirp.applicants import ResultEntry, Applicant, get_applicant_data from waeup.sirp.applicants.interfaces import ( IApplicant, IApplicantPrincipal, IApplicantPDEEditData, IApplicantsRoot, IApplicantsContainer, IApplicantsContainerProvider, IApplicantsContainerAdd, application_types_vocab ) results_widget = CustomWidgetFactory( WAeUPObjectWidget, ResultEntry) results_display_widget = CustomWidgetFactory( WAeUPObjectDisplayWidget, ResultEntry) list_results_widget = CustomWidgetFactory( MultiListWidget, subwidget=results_widget) list_results_display_widget = CustomWidgetFactory( MultiListDisplayWidget, subwidget=results_display_widget) class ApplicantsRootPage(WAeUPPage): grok.context(IApplicantsRoot) grok.name('index') grok.require('waeup.Public') title = 'Applicants' label = 'Application Section' pnav = 3 def update(self): super(ApplicantsRootPage, self).update() datatable.need() return class ManageApplicantsRootActionButton(ManageActionButton): grok.context(IApplicantsRoot) grok.view(ApplicantsRootPage) grok.require('waeup.manageUniversity') text = 'Manage application section' class ApplicantsRootManageFormPage(WAeUPEditFormPage): grok.context(IApplicantsRoot) grok.name('manage') grok.template('applicantsrootmanagepage') title = 'Applicants' label = 'Manage application section' pnav = 3 grok.require('waeup.manageUniversity') taboneactions = ['Add applicants container', 'Remove selected','Cancel'] subunits = 'Applicants Containers' def update(self): tabs.need() datatable.need() return super(ApplicantsRootManageFormPage, self).update() # ToDo: Show warning message before deletion @grok.action('Remove selected') def delApplicantsContainers(self, **data): form = self.request.form child_id = form['val_id'] if not isinstance(child_id, list): child_id = [child_id] deleted = [] for id in child_id: try: del self.context[id] deleted.append(id) except: self.flash('Could not delete %s: %s: %s' % ( id, sys.exc_info()[0], sys.exc_info()[1])) if len(deleted): self.flash('Successfully removed: %s' % ', '.join(deleted)) self.redirect(self.url(self.context, '@@manage')+'#tab-1') return @grok.action('Add applicants container', validator=NullValidator) def addApplicantsContainer(self, **data): self.redirect(self.url(self.context, '@@add')) return @grok.action('Cancel', validator=NullValidator) def cancel(self, **data): self.redirect(self.url(self.context)) return class ApplicantsContainerAddFormPage(WAeUPAddFormPage): grok.context(IApplicantsRoot) grok.require('waeup.manageUniversity') grok.name('add') grok.template('applicantscontaineraddpage') title = 'Applicants' label = 'Add applicants container' pnav = 3 form_fields = grok.AutoFields( IApplicantsContainerAdd).omit('code').omit('title') form_fields['startdate'].custom_widget = FriendlyDateWidget('le') form_fields['enddate'].custom_widget = FriendlyDateWidget('le') def update(self): datepicker.need() # Enable jQuery datepicker in date fields. #from waeup.sirp.browser.resources import jqueryui #jqueryui.need() return super(ApplicantsContainerAddFormPage, self).update() @grok.action('Add applicants container') def addApplicantsContainer(self, **data): year = data['year'] code = u'%s%s' % (data['prefix'], year) prefix = application_types_vocab.getTerm(data['prefix']) title = u'%s %s/%s' % (prefix.title, year, year + 1) if code in self.context.keys(): self.flash( 'An applicants container for the same application ' 'type and entrance year exists already in the database.') return # Add new applicants container... provider = data['provider'][1] container = provider.factory() self.applyData(container, **data) container.code = code container.title = title self.context[code] = container self.flash('Added: "%s".' % code) self.redirect(self.url(self.context, u'@@manage')+'#tab-1') return @grok.action('Cancel', validator=NullValidator) def cancel(self, **data): self.redirect(self.url(self.context, '@@manage') + '#tab-1') class ApplicantsRootBreadcrumb(Breadcrumb): """A breadcrumb for applicantsroot. """ grok.context(IApplicantsRoot) title = u'Application Section' class ApplicantsContainerBreadcrumb(Breadcrumb): """A breadcrumb for applicantscontainers. """ grok.context(IApplicantsContainer) class ApplicantBreadcrumb(Breadcrumb): """A breadcrumb for applicants. """ grok.context(IApplicant) @property def title(self): """Get a title for a context. """ return self.context.access_code class ApplicantsTab(PrimaryNavTab): """Applicants tab in primary navigation. """ grok.context(IWAeUPObject) grok.order(3) grok.require('waeup.manageUniversity') grok.template('primarynavtab') pnav = 3 tab_title = u'Applicants' @property def link_target(self): return self.view.application_url('applicants') class ApplicantsContainerPage(WAeUPDisplayFormPage): """The standard view for regular applicant containers. """ grok.context(IApplicantsContainer) grok.name('index') grok.require('waeup.Public') grok.template('applicantscontainerpage') pnav = 3 form_fields = grok.AutoFields(IApplicantsContainer).omit('title') form_fields['startdate'].custom_widget = FriendlyDateDisplayWidget('le') form_fields['enddate'].custom_widget = FriendlyDateDisplayWidget('le') form_fields['description'].custom_widget = ReSTDisplayWidget @property def title(self): return "Applicants Container: %s" % self.context.title @property def label(self): return self.context.title class ApplicantsContainerManageActionButton(ManageActionButton): grok.context(IApplicantsContainer) grok.view(ApplicantsContainerPage) text = 'Manage applicants container' class ApplicantsContainerManageFormPage(WAeUPEditFormPage): grok.context(IApplicantsContainer) grok.name('manage') grok.template('applicantscontainermanagepage') form_fields = grok.AutoFields(IApplicantsContainer).omit('title') taboneactions = ['Save','Cancel'] tabtwoactions = ['Add applicant', 'Remove selected','Cancel'] # Use friendlier date widget... form_fields['startdate'].custom_widget = FriendlyDateWidget('le') form_fields['enddate'].custom_widget = FriendlyDateWidget('le') grok.require('waeup.manageUniversity') @property def title(self): return "Applicants Container: %s" % self.context.title @property def label(self): return 'Manage applicants container' pnav = 3 def update(self): datepicker.need() # Enable jQuery datepicker in date fields. tabs.need() datatable.need() # Enable jQurey datatables for contents listing return super(ApplicantsContainerManageFormPage, self).update() @grok.action('Save') def apply(self, **data): self.applyData(self.context, **data) self.flash('Data saved.') return # ToDo: Show warning message before deletion @grok.action('Remove selected') def delApplicant(self, **data): return self.flash('Removal of applicants is not yet implemented!') @grok.action('Add applicant', validator=NullValidator) def addApplicant(self, **data): return self.flash('Manual addition of applicants not yet implemented!') @grok.action('Cancel', validator=NullValidator) def cancel(self, **data): self.redirect(self.url(self.context)) return class LoginApplicant(WAeUPPage): grok.context(IApplicantsContainer) grok.name('login') grok.require('waeup.Public') @property def title(self): return u"Applicant Login: %s" % self.context.title @property def label(self): return u'Login for applicants only' pnav = 3 @property def ac_prefix(self): return self.context.ac_prefix def update(self, SUBMIT=None): self.ac_series = self.request.form.get('form.ac_series', None) self.ac_number = self.request.form.get('form.ac_number', None) if SUBMIT is None: return if self.request.principal.id == 'zope.anybody': self.flash('Entered credentials are invalid.') return if not IApplicantPrincipal.providedBy(self.request.principal): # Don't care if user is already authenticated as non-applicant return pin = self.request.principal.access_code if pin not in self.context.keys(): # Create applicant record applicant = Applicant() applicant.access_code = pin self.context[pin] = applicant # Assign current principal the owner role on created applicant # record role_manager = IPrincipalRoleManager(self.context) role_manager.assignRoleToPrincipal( 'waeup.local.ApplicationOwner', self.request.principal.id) self.redirect(self.url(self.context[pin], 'edit')) return class AccessCodeLink(LeftSidebarLink): grok.order(1) grok.require('waeup.Public') def render(self): if not IApplicantPrincipal.providedBy(self.request.principal): return '' access_code = getattr(self.request.principal,'access_code',None) if access_code: applicant_object = get_applicant_data(access_code) url = absoluteURL(applicant_object, self.request) return u'
%s
' % ( url,access_code) return '' class DisplayApplicant(WAeUPDisplayFormPage): grok.context(IApplicant) grok.name('index') grok.require('waeup.viewApplication') form_fields = grok.AutoFields(IApplicant).omit('locked') form_fields['fst_sit_results'].custom_widget = list_results_display_widget form_fields['passport'].custom_widget = ThumbnailWidget form_fields['date_of_birth'].custom_widget = FriendlyDateDisplayWidget('le') label = 'Applicant' title = 'Applicant' pnav = 3 class EditApplicantStudent(WAeUPEditFormPage): """An applicant-centered edit view for applicant data. """ grok.context(IApplicant) grok.name('edit') grok.require('waeup.editApplication') form_fields = grok.AutoFields(IApplicantPDEEditData).omit('locked') form_fields['passport'].custom_widget = EncodingImageFileWidget form_fields['date_of_birth'].custom_widget = FriendlyDateWidget('le-year') grok.template('form_edit_pde') def emitLockMessage(self): self.flash('The requested form is locked (read-only).') self.redirect(self.url(self.context)) return def update(self): if self.context.locked: self.emitLockMessage() return datepicker.need() # Enable jQuery datepicker in date fields. super(EditApplicantStudent, self).update() return def filteredWidgets(self): for widget in self.widgets: if widget.name == 'form.confirm_passport': continue yield widget @property def label(self): # XXX: Use current/upcoming session return 'Apply for Post UDE Screening Test (2009/2010)' title = 'Edit Application' pnav = 3 @grok.action('Save') def save(self, **data): if self.context.locked: self.emitLockMessage() return self.applyData(self.context, **data) self.context._p_changed = True return @grok.action('Final Submit') def finalsubmit(self, **data): if self.context.locked: self.emitLockMessage() return self.applyData(self.context, **data) self.context._p_changed = True if not self.dataComplete(): self.flash('Data yet not complete.') return self.context.locked = True return def dataComplete(self): if self.context.confirm_passport is not True: return False if len(self.errors) > 0: return False return True class EditApplicantFull(WAeUPEditFormPage): """A full edit view for applicant data. This one is meant to be used by officers only. """ grok.context(IApplicant) grok.name('edit_full') grok.require('waeup.editFullApplication') form_fields = grok.AutoFields(IApplicantPDEEditData).omit('locked') form_fields['passport'].custom_widget = EncodingImageFileWidget form_fields['date_of_birth'].custom_widget = FriendlyDateWidget('le-year') grok.template('form_edit_full') def update(self): if self.context.locked: self.emitLockMessage() return datepicker.need() # Enable jQuery datepicker in date fields. super(EditApplicantFull, self).update() return def filteredWidgets(self): for widget in self.widgets: if widget.name == 'form.confirm_passport': continue yield widget @property def label(self): return 'Application for %s' % self.context.access_code title = 'Edit Application' pnav = 3 @grok.action('Save') def save(self, **data): self.applyData(self.context, **data) self.context._p_changed = True return