## ## browser.py ## Login : ## Started on Sun Jun 27 11:03:10 2010 Uli Fouquet ## $Id$ ## ## Copyright (C) 2010 Uli Fouquet ## 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 grok from datetime import datetime from hurry.jquery import jquery from hurry.jqueryui import jqueryui from zope.component import getUtility, getAllUtilitiesRegisteredFor from zope.formlib.widgets import FileWidget, DateWidget from zope.securitypolicy.interfaces import IPrincipalRoleManager from waeup.sirp.browser import ( WAeUPPage, WAeUPEditFormPage, WAeUPAddFormPage, WAeUPDisplayFormPage, NullValidator) from waeup.sirp.browser.pages import LoginPage from waeup.sirp.interfaces import IWAeUPObject from waeup.sirp.browser.resources import datepicker, tabs, datatable from waeup.sirp.browser.viewlets import ( AddActionButton, ManageActionButton, PrimaryNavTab, ) from waeup.sirp.browser.breadcrumbs import Breadcrumb from waeup.sirp.applicants import get_applicant_data, ResultEntry, Applicant from waeup.sirp.applicants.interfaces import ( IApplicant, IApplicantPrincipal, IApplicantPDEEditData, IApplicantsRoot, IApplicantsContainer, IApplicantsContainerProvider, ) from waeup.sirp.widgets.passportwidget import ( PassportWidget, PassportDisplayWidget ) from waeup.sirp.widgets.datewidget import ( FriendlyDateWidget, FriendlyDateDisplayWidget) #from zope.formlib.objectwidget import ObjectWidget from zope.formlib.sequencewidget import ListSequenceWidget, SequenceDisplayWidget from zope.formlib.widget import CustomWidgetFactory from waeup.sirp.utils.helpers import ReST2HTML from waeup.sirp.widgets.objectwidget import ( WAeUPObjectWidget, WAeUPObjectDisplayWidget) from waeup.sirp.widgets.multilistwidget import ( MultiListWidget, MultiListDisplayWidget) from waeup.sirp.image.browser.widget import ( ThumbnailWidget, EncodingImageFileWidget, ) results_widget = CustomWidgetFactory( WAeUPObjectWidget, ResultEntry) results_display_widget = CustomWidgetFactory( WAeUPObjectDisplayWidget, ResultEntry) #list_results_widget = CustomWidgetFactory( # ListSequenceWidget, subwidget=results_widget) list_results_widget = CustomWidgetFactory( MultiListWidget, subwidget=results_widget) list_results_display_widget = CustomWidgetFactory( MultiListDisplayWidget, subwidget=results_display_widget) class ApplicationsPage(WAeUPPage): grok.context(IApplicantsRoot) grok.name('index') title = 'Applicants' pnav = 3 def update(self): super(ApplicationsPage, self).update() datatable.need() return def getApplications(self): """Get a list of all stored applicant containers. """ for key, val in self.context.items(): url = self.url(val) yield(dict(url=url, name=key, container=val)) class ManageApplicantsRootActionButton(ManageActionButton): grok.context(IApplicantsRoot) grok.view(ApplicationsPage) text = 'Manage applicant containers' class ApplicantsRootEditPage(WAeUPPage): grok.context(IApplicantsRoot) grok.name('manage') grok.template('applicantsrooteditpage') title = 'Edit applicants containers' pnav = 3 def update(self, entries=None, DELETE=None, CANCEL=None): if CANCEL is not None: self.redirect(self.url(self.context)) return if DELETE is None: return if entries is None: return if not isinstance(entries, list): entries = [entries] for name in entries: del self.context[name] self.flash('Deleted "%s"' % name) return def getApplications(self): """Get a list of all stored applicant containers. """ for key, val in self.context.items(): url = self.url(val) yield(dict(url=url, name=key)) class AddApplicantsContainerActionButton(AddActionButton): grok.context(IApplicantsRoot) grok.view(ApplicantsRootEditPage) text = 'Add applicants container' class AddApplicantsContainer(WAeUPPage): grok.context(IApplicantsRoot) grok.name('add') grok.template('addcontainer') title = 'Add applicants container' pnav = 3 def update(self, providername=None, name=None, title=None, description=None, ADD=None, CANCEL=None): if CANCEL is not None: self.redirect(self.url(self.context)) return if ADD is None: return if not name: self.flash('Error: you must give a name') return if name in self.context.keys(): self.flash('A container of the given name already exists') return # Add new applicants container... provider = getUtility(IApplicantsContainerProvider, name=providername) container = provider.factory() if title: container.title = title if description: container.description = description self.context[name] = container self.flash('Added "%s".' % name) self.redirect(self.url(self.context)) return def getContainerProviders(self): """Get a list of applicants container providers. Applicants container providers are named utilities that help to create applicants containers of different types (JAMB-based, non-JAMB-based, etc.). The list returned contains dicts:: {'name': , 'provider': } where `utility_name` is the name under which the respective provider utility is registered and `provider` is the real provider instance. The `utility_name` can be used to lookup the utility anew (for instance after submitting a form) and the `provider` instance can be used to create new instances of the respective applicants container type. """ providers = getAllUtilitiesRegisteredFor(IApplicantsContainerProvider) result = [ {'name': getattr(x, 'grokcore.component.directive.name'), 'provider': x} for x in providers ] return result class ApplicantsRootBreadcrumb(Breadcrumb): """A breadcrumb for applicantsroot. """ grok.context(IApplicantsRoot) title = u'Applicants' class ApplicantsContainerBreadcrumb(Breadcrumb): """A breadcrumb for applicantscontainers. """ grok.context(IApplicantsContainer) class ApplicantsTab(PrimaryNavTab): """Faculties-tab in primary navigation. """ grok.context(IWAeUPObject) grok.order(3) grok.require('waeup.View') 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.template('applicantscontainerpage') pnav = 3 form_fields = grok.AutoFields(IApplicantsContainer) # Use friendlier date widget... form_fields['startdate'].custom_widget = FriendlyDateDisplayWidget('le') form_fields['enddate'].custom_widget = FriendlyDateDisplayWidget('le') @property def title(self): return "Applicants Container: %s" % getattr( self.context, '__name__', 'unnamed') @property def label(self): return self.title def descriptionToHTML(self): if self.context.description: return ReST2HTML(self.context.description) else: return class ManageApplicantsContainerActionButton(ManageActionButton): grok.context(IApplicantsContainer) grok.view(ApplicantsContainerPage) text = 'Manage' class ManageApplicantsContainer(WAeUPEditFormPage): grok.context(IApplicantsContainer) grok.name('manage') grok.template('form_manage_applicants_container') form_fields = grok.AutoFields(IApplicantsContainer) # Use friendlier date widget... form_fields['startdate'].custom_widget = FriendlyDateWidget('le') form_fields['enddate'].custom_widget = FriendlyDateWidget('le') @property def title(self): return "Manage applicants container: %s" % getattr( self.context, '__name__', 'unnamed') @property def label(self): return self.title 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(ManageApplicantsContainer, self).update() @grok.action('Save') def apply(self, **data): self.applyData(self.context, **data) self.flash('Data saved.') return @grok.action('Back') def cancel(self, **data): self.redirect(self.url(self.context)) return class LoginApplicant(WAeUPPage): grok.context(IApplicantsContainer) grok.name('login') grok.require('zope.Public') title = u'Login' @property def label(self): return self.title pnav = 3 prefix = u'APP' 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 AddApplicant(WAeUPAddFormPage): # grok.context(IApplicantsContainer) # grok.name('add') # form_fields = grok.AutoFields(IApplicant) # form_fields['fst_sit_results'].custom_widget = list_results_widget # form_fields['passport'].custom_widget = EncodingImageFileWidget # label = 'Add Applicant' # title = 'Add Applicant' # pnav = 1 # # @grok.action('Add applicant') # def addApplicant(self, **data): # from waeup.sirp.jambtables.applicants import Applicant # applicant = Applicant() # self.applyData(applicant, **data) # # XXX: temporarily disabled. # #self.context[applicant.reg_no] = applicant # try: # self.context[applicant.access_code] = applicant # except KeyError: # self.flash('The given access code is already in use!') # return # self.redirect(self.url(self.context)) 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 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