## ## applicants.py ## Login : ## Started on Fri Jul 16 11:46:55 2010 Uli Fouquet ## $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 ## import os import grok from grok import index from zope.component.interfaces import IFactory from zope.interface import implementedBy from hurry.workflow.interfaces import IWorkflowInfo, IWorkflowState from waeup.sirp.app import University from waeup.sirp.image import WAeUPImageFile from waeup.sirp.imagestorage import DefaultFileStoreHandler from waeup.sirp.interfaces import ( IObjectHistory, IFileStoreHandler, IFileStoreNameChooser) from waeup.sirp.utils.helpers import attrs_to_fields from waeup.sirp.applicants.interfaces import ( IResultEntry, IApplicant, IApplicantEdit, ) def get_regno_or_ac(context): reg_no = getattr(context, 'reg_no', None) if reg_no is None: return getattr(context, 'access_code', None) return reg_no class ResultEntry(grok.Context): grok.implements(IResultEntry) def __init__(self, subject=None, score=None): self.subject = subject self.score = score class Applicant(grok.Model): grok.implements(IApplicant,IApplicantEdit) grok.provides(IApplicant) def __init__(self): super(Applicant, self).__init__() IWorkflowInfo(self).fireTransition('init') self.application_date = None return def loggerInfo(self, ob_class, comment=None): target = self.__name__ return grok.getSite()['applicants'].logger_info(ob_class,target,comment) @property def state(self): state = IWorkflowState(self).getState() return state @property def history(self): history = IObjectHistory(self) return history # Set all attributes of Applicant required in IApplicant as field # properties. Doing this, we do not have to set initial attributes # ourselves and as a bonus we get free validation when an attribute is # set. Applicant = attrs_to_fields(Applicant) class ApplicantCatalog(grok.Indexes): """A catalog indexing :class:`Applicant` instances in the ZODB. """ grok.site(University) grok.name('applicants_catalog') grok.context(IApplicant) access_code = index.Field(attribute='access_code') class ApplicantFactory(grok.GlobalUtility): """A factory for applicants. """ grok.implements(IFactory) grok.name(u'waeup.Applicant') title = u"Create a new applicant.", description = u"This factory instantiates new applicant instances." def __call__(self, *args, **kw): return Applicant() def getInterfaces(self): return implementedBy(Applicant) #: The file id marker for applicant passport images APPLICANT_IMAGE_STORE_NAME = 'img-applicant' class ApplicantImageNameChooser(grok.Adapter): """A file id chooser for :class:`Applicant` objects. `context` is an :class:`Applicant` instance. The :class:`ApplicantImageNameChooser` can build/check file ids for :class:`Applicant` objects suitable for use with :class:`ExtFileStore` instances. The delivered file_id contains the file id marker for :class:`Applicant` object and the registration number or access code of the context applicant. Also the name of the connected applicant container will be part of the generated file id. This chooser is registered as an adapter providing :class:`waeup.sirp.interfaces.IFileStoreNameChooser`. File store name choosers like this one are only convenience components to ease the task of creating file ids for applicant objects. You are nevertheless encouraged to use them instead of manually setting up filenames for applicants. .. seealso:: :mod:`waeup.sirp.imagestorage` """ grok.context(IApplicant) grok.implements(IFileStoreNameChooser) def checkName(self, name=None, attr=None): """Check whether the given name is a valid file id for the context. Returns ``True`` only if `name` equals the result of :meth:`chooseName`. The `attr` parameter is not taken into account for :class:`Applicant` context as the single passport image is the only file we store for applicants. """ return name == self.chooseName() def chooseName(self, name=None, attr=None): """Get a valid file id for applicant context. *Example:* For an applicant with registration no. ``'My_reg_no_1234'`` and stored in an applicants container called ``'mycontainer'``, this chooser would create: ``'__img-applicant__mycontainer/My_reg_no_1234.jpg'`` meaning that the passport image of this applicant would be stored in the site-wide file storage in path: ``mycontainer/My_reg_no_1234.jpg`` If the context applicant has no parent, ``'_default'`` is used as parent name. The `attr` parameter is not taken into account for :class:`Applicant` context as the single passport image is the only file we store for applicants. """ parent_name = getattr( getattr(self.context, '__parent__', None), '__name__', '_default') marked_filename = '__%s__%s/%s.jpg' % ( APPLICANT_IMAGE_STORE_NAME, parent_name, get_regno_or_ac(self.context)) return marked_filename class ApplicantImageStoreHandler(DefaultFileStoreHandler, grok.GlobalUtility): """Applicant specific image handling. This handler knows in which path in a filestore to store applicant images and how to turn this kind of data into some (browsable) file object. It is called from the global file storage, when it wants to get/store a file with a file id starting with ``__img-applicant__`` (the marker string for applicant images). Like each other file store handler it does not handle the files really (this is done by the global file store) but only computes paths and things like this. """ grok.implements(IFileStoreHandler) grok.name(APPLICANT_IMAGE_STORE_NAME) def pathFromFileID(self, store, root, file_id): """All applicants images are filed in directory ``applicants``. """ marker, filename, basename, ext = store.extractMarker(file_id) sub_root = os.path.join(root, 'applicants') return super(ApplicantImageStoreHandler, self).pathFromFileID( store, sub_root, basename) def createFile(self, store, root, filename, file_id, file): """Create a browsable file-like object. """ ext = os.path.splitext(filename)[1].lower() if ext not in ['.jpg', '.png']: raise ValueError('Only .jpg and .png allowed') # call super method to ensure that any old files with # different filename extension are deleted. file, path, file_obj = super( ApplicantImageStoreHandler, self).createFile( store, root, filename, file_id, file) return file, path, WAeUPImageFile( file_obj.filename, file_obj.data)