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

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

Set value Id for property svn:keywords in all Python files.

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