source: main/waeup.sirp/trunk/src/waeup/sirp/applicants/applicant.py @ 7196

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

Adjust copyright statement and svn keyword in applicants.

  • Property svn:keywords set to Id
File size: 7.5 KB
Line 
1## $Id: applicant.py 7192 2011-11-25 07:15:50Z henrik $
2##
3## Copyright (C) 2011 Uli Fouquet & Henrik Bettermann
4## This program is free software; you can redistribute it and/or modify
5## it under the terms of the GNU General Public License as published by
6## the Free Software Foundation; either version 2 of the License, or
7## (at your option) any later version.
8##
9## This program is distributed in the hope that it will be useful,
10## but WITHOUT ANY WARRANTY; without even the implied warranty of
11## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12## GNU General Public License for more details.
13##
14## You should have received a copy of the GNU General Public License
15## along with this program; if not, write to the Free Software
16## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17##
18import os
19import grok
20from grok import index
21from zope.component.interfaces import IFactory
22from zope.interface import implementedBy
23from hurry.workflow.interfaces import IWorkflowInfo, IWorkflowState
24from waeup.sirp.app import University
25from waeup.sirp.image import WAeUPImageFile
26from waeup.sirp.imagestorage import DefaultFileStoreHandler
27from waeup.sirp.interfaces import (
28    IObjectHistory, IFileStoreHandler, IFileStoreNameChooser)
29from waeup.sirp.utils.helpers import attrs_to_fields
30from waeup.sirp.applicants.interfaces import (
31    IResultEntry, IApplicant, IApplicantEdit,
32    )
33
34
35def get_regno_or_ac(context):
36    reg_no = getattr(context, 'reg_no', None)
37    if reg_no is None:
38        return getattr(context, 'access_code', None)
39    return reg_no
40
41class ResultEntry(grok.Context):
42    grok.implements(IResultEntry)
43
44    def __init__(self, subject=None, score=None):
45        self.subject = subject
46        self.score = score
47
48class Applicant(grok.Model):
49    grok.implements(IApplicant,IApplicantEdit)
50    grok.provides(IApplicant)
51
52    def __init__(self):
53        super(Applicant, self).__init__()
54        IWorkflowInfo(self).fireTransition('init')
55        self.application_date = None
56        return
57
58    def loggerInfo(self, ob_class, comment=None):
59        target = self.__name__
60        return grok.getSite()['applicants'].logger_info(ob_class,target,comment)
61
62    @property
63    def state(self):
64        state = IWorkflowState(self).getState()
65        return state
66
67    @property
68    def history(self):
69        history = IObjectHistory(self)
70        return history
71
72# Set all attributes of Applicant required in IApplicant as field
73# properties. Doing this, we do not have to set initial attributes
74# ourselves and as a bonus we get free validation when an attribute is
75# set.
76Applicant = attrs_to_fields(Applicant)
77
78class ApplicantCatalog(grok.Indexes):
79    """A catalog indexing :class:`Applicant` instances in the ZODB.
80    """
81    grok.site(University)
82    grok.name('applicants_catalog')
83    grok.context(IApplicant)
84
85    access_code = index.Field(attribute='access_code')
86
87class ApplicantFactory(grok.GlobalUtility):
88    """A factory for applicants.
89    """
90    grok.implements(IFactory)
91    grok.name(u'waeup.Applicant')
92    title = u"Create a new applicant.",
93    description = u"This factory instantiates new applicant instances."
94
95    def __call__(self, *args, **kw):
96        return Applicant()
97
98    def getInterfaces(self):
99        return implementedBy(Applicant)
100
101
102#: The file id marker for applicant passport images
103APPLICANT_IMAGE_STORE_NAME = 'img-applicant'
104
105class ApplicantImageNameChooser(grok.Adapter):
106    """A file id chooser for :class:`Applicant` objects.
107
108    `context` is an :class:`Applicant` instance.
109
110    The :class:`ApplicantImageNameChooser` can build/check file ids
111    for :class:`Applicant` objects suitable for use with
112    :class:`ExtFileStore` instances. The delivered file_id contains
113    the file id marker for :class:`Applicant` object and the
114    registration number or access code of the context applicant. Also
115    the name of the connected applicant container will be part of the
116    generated file id.
117
118    This chooser is registered as an adapter providing
119    :class:`waeup.sirp.interfaces.IFileStoreNameChooser`.
120
121    File store name choosers like this one are only convenience
122    components to ease the task of creating file ids for applicant
123    objects. You are nevertheless encouraged to use them instead of
124    manually setting up filenames for applicants.
125
126    .. seealso:: :mod:`waeup.sirp.imagestorage`
127
128    """
129    grok.context(IApplicant)
130    grok.implements(IFileStoreNameChooser)
131
132    def checkName(self, name=None, attr=None):
133        """Check whether the given name is a valid file id for the context.
134
135        Returns ``True`` only if `name` equals the result of
136        :meth:`chooseName`.
137
138        The `attr` parameter is not taken into account for
139        :class:`Applicant` context as the single passport image is the
140        only file we store for applicants.
141        """
142        return name == self.chooseName()
143
144    def chooseName(self, name=None, attr=None):
145        """Get a valid file id for applicant context.
146
147        *Example:*
148
149        For an applicant with registration no. ``'My_reg_no_1234'``
150        and stored in an applicants container called
151        ``'mycontainer'``, this chooser would create:
152
153          ``'__img-applicant__mycontainer/My_reg_no_1234.jpg'``
154
155        meaning that the passport image of this applicant would be
156        stored in the site-wide file storage in path:
157
158          ``mycontainer/My_reg_no_1234.jpg``
159
160        If the context applicant has no parent, ``'_default'`` is used
161        as parent name.
162
163        The `attr` parameter is not taken into account for
164        :class:`Applicant` context as the single passport image is the
165        only file we store for applicants.
166
167        """
168        parent_name = getattr(
169            getattr(self.context, '__parent__', None),
170            '__name__', '_default')
171        marked_filename = '__%s__%s/%s.jpg' % (
172            APPLICANT_IMAGE_STORE_NAME,
173            parent_name, get_regno_or_ac(self.context))
174        return marked_filename
175
176
177class ApplicantImageStoreHandler(DefaultFileStoreHandler, grok.GlobalUtility):
178    """Applicant specific image handling.
179
180    This handler knows in which path in a filestore to store applicant
181    images and how to turn this kind of data into some (browsable)
182    file object.
183
184    It is called from the global file storage, when it wants to
185    get/store a file with a file id starting with
186    ``__img-applicant__`` (the marker string for applicant images).
187
188    Like each other file store handler it does not handle the files
189    really (this is done by the global file store) but only computes
190    paths and things like this.
191    """
192    grok.implements(IFileStoreHandler)
193    grok.name(APPLICANT_IMAGE_STORE_NAME)
194
195    def pathFromFileID(self, store, root, file_id):
196        """All applicants images are filed in directory ``applicants``.
197        """
198        marker, filename, basename, ext = store.extractMarker(file_id)
199        sub_root = os.path.join(root, 'applicants')
200        return super(ApplicantImageStoreHandler, self).pathFromFileID(
201            store, sub_root, basename)
202
203    def createFile(self, store, root, filename, file_id, file):
204        """Create a browsable file-like object.
205        """
206        ext = os.path.splitext(filename)[1].lower()
207        if ext not in ['.jpg', '.png']:
208            raise ValueError('Only .jpg and .png allowed')
209        # call super method to ensure that any old files with
210        # different filename extension are deleted.
211        file, path, file_obj =  super(
212            ApplicantImageStoreHandler, self).createFile(
213            store, root,  filename, file_id, file)
214        return file, path, WAeUPImageFile(
215            file_obj.filename, file_obj.data)
Note: See TracBrowser for help on using the repository browser.