source: main/waeup.ikoba/trunk/src/waeup/ikoba/customers/documents.py @ 12131

Last change on this file since 12131 was 12128, checked in by Henrik Bettermann, 10 years ago

user_id is customer_id.

  • Property svn:keywords set to Id
File size: 8.8 KB
Line 
1## $Id: documents.py 12128 2014-12-03 18:10:43Z henrik $
2##
3## Copyright (C) 2014 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##
18"""
19Customer document components.
20"""
21import os
22import grok
23from zope.component import queryUtility, getUtility
24from zope.component.interfaces import IFactory
25from zope.interface import implementedBy
26
27from waeup.ikoba.image import IkobaImageFile
28from waeup.ikoba.imagestorage import DefaultFileStoreHandler
29from waeup.ikoba.interfaces import MessageFactory as _
30from waeup.ikoba.interfaces import (
31    IFileStoreNameChooser, IFileStoreHandler,
32    IIkobaUtils, IExtFileStore)
33from waeup.ikoba.customers.interfaces import (
34    ICustomerDocumentsContainer, ICustomerNavigation, ICustomerDocument,
35    ICustomersUtils, ICustomerPDFDocument)
36from waeup.ikoba.documents import DocumentsContainer, Document
37from waeup.ikoba.documents.interfaces import IDocumentsUtils
38from waeup.ikoba.utils.helpers import attrs_to_fields
39
40from waeup.ikoba.customers.utils import path_from_custid
41
42class CustomerDocumentsContainer(DocumentsContainer):
43    """This is a container for customer documents.
44    """
45    grok.implements(ICustomerDocumentsContainer, ICustomerNavigation)
46    grok.provides(ICustomerDocumentsContainer)
47
48    def __init__(self):
49        super(CustomerDocumentsContainer, self).__init__()
50        return
51
52    @property
53    def customer(self):
54        return self.__parent__
55
56    def writeLogMessage(self, view, message):
57        return self.__parent__.writeLogMessage(view, message)
58
59CustomerDocumentsContainer = attrs_to_fields(CustomerDocumentsContainer)
60
61class CustomerDocumentBase(Document):
62    """This is a customer document baseclass.
63    """
64    grok.implements(ICustomerDocument, ICustomerNavigation)
65    grok.provides(ICustomerDocument)
66    grok.baseclass()
67
68    @property
69    def customer(self):
70        try:
71            return self.__parent__.__parent__
72        except AttributeError:
73            return None
74
75    @property
76    def user_id(self):
77        if self.customer is not None:
78            return self.customer.customer_id
79        return
80
81    def writeLogMessage(self, view, message):
82        return self.__parent__.__parent__.writeLogMessage(view, message)
83
84    @property
85    def is_editable(self):
86        try:
87            # Customer must be approved
88            cond1 = self.customer.state in getUtility(
89                ICustomersUtils).DOCMANAGE_CUSTOMER_STATES
90            # Document must be in state created
91            cond2 = self.state in getUtility(
92                ICustomersUtils).DOCMANAGE_DOCUMENT_STATES
93            if not (cond1 and cond2):
94                return False
95        except AttributeError:
96            pass
97        return True
98
99    @property
100    def translated_class_name(self):
101        try:
102            DOCTYPES_DICT = getUtility(ICustomersUtils).DOCTYPES_DICT
103            return DOCTYPES_DICT[self.class_name]
104        except KeyError:
105            return
106
107
108class CustomerSampleDocument(CustomerDocumentBase):
109    """This is a sample customer document.
110    """
111
112CustomerSampleDocument = attrs_to_fields(CustomerSampleDocument)
113
114
115class CustomerPDFDocument(CustomerDocumentBase):
116    """This is a customer document for a single pdf upload file.
117    """
118    grok.implements(ICustomerPDFDocument, ICustomerNavigation)
119    grok.provides(ICustomerPDFDocument)
120
121CustomerPDFDocument = attrs_to_fields(CustomerPDFDocument)
122
123
124# Customer documents must be importable. So we might need a factory.
125class CustomerDocumentFactory(grok.GlobalUtility):
126    """A factory for customer documents.
127    """
128    grok.implements(IFactory)
129    grok.name(u'waeup.CustomerSampleDocument')
130    title = u"Create a new document.",
131    description = u"This factory instantiates new sample document instances."
132
133    def __call__(self, *args, **kw):
134        return CustomerSampleDocument(*args, **kw)
135
136    def getInterfaces(self):
137        return implementedBy(CustomerSampleDocument)
138
139# Customer documents must be importable. So we might need a factory.
140class CustomerPDFDocumentFactory(grok.GlobalUtility):
141    """A factory for customer pdf documents.
142    """
143    grok.implements(IFactory)
144    grok.name(u'waeup.CustomerPDFDocument')
145    title = u"Create a new document.",
146    description = u"This factory instantiates new pdf document instances."
147
148    def __call__(self, *args, **kw):
149        return CustomerPDFDocument(*args, **kw)
150
151    def getInterfaces(self):
152        return implementedBy(CustomerPDFDocument)
153
154#: The file id marker for customer files
155CUSTOMERDOCUMENT_FILE_STORE_NAME = 'file-customerdocument'
156
157
158class CustomerDocumentFileNameChooser(grok.Adapter):
159    """A file id chooser for :class:`CustomerDocument` objects.
160
161    `context` is an :class:`CustomerDocument` instance.
162
163    The :class:`CustomerDocumentFileNameChooser` can build/check file ids for
164    :class:`Customer` objects suitable for use with
165    :class:`ExtFileStore` instances. The delivered file_id contains
166    the file id marker for :class:`CustomerDocument` object and the customer id
167    of the context customer.
168
169    This chooser is registered as an adapter providing
170    :class:`waeup.ikoba.interfaces.IFileStoreNameChooser`.
171
172    File store name choosers like this one are only convenience
173    components to ease the task of creating file ids for customer document
174    objects. You are nevertheless encouraged to use them instead of
175    manually setting up filenames for customer documents.
176
177    .. seealso:: :mod:`waeup.ikoba.imagestorage`
178
179    """
180
181    grok.context(ICustomerDocument)
182    grok.implements(IFileStoreNameChooser)
183
184    def checkName(self, name=None, attr=None):
185        """Check whether the given name is a valid file id for the context.
186
187        Returns ``True`` only if `name` equals the result of
188        :meth:`chooseName`.
189
190        """
191        return name == self.chooseName()
192
193    def chooseName(self, attr, name=None):
194        """Get a valid file id for customer document context.
195
196        *Example:*
197
198        For a customer with customer id ``'A123456'``
199        and document with id 'd123'
200        with attr ``'nice_image.jpeg'`` stored in
201        the customers container this chooser would create:
202
203          ``'__file-customerdocument__customers/A/A123456/nice_image_d123_A123456.jpeg'``
204
205        meaning that the nice image of this customer document would be
206        stored in the site-wide file storage in path:
207
208          ``customers/A/A123456/nice_image_d123_A123456.jpeg``
209
210        """
211        basename, ext = os.path.splitext(attr)
212        cust_id = self.context.customer.customer_id
213        doc_id = self.context.document_id
214        marked_filename = '__%s__%s/%s_%s_%s%s' % (
215            CUSTOMERDOCUMENT_FILE_STORE_NAME, path_from_custid(cust_id),
216            basename, doc_id, cust_id, ext)
217        return marked_filename
218
219
220class CustomerDocumentFileStoreHandler(DefaultFileStoreHandler, grok.GlobalUtility):
221    """Customer document specific file handling.
222
223    This handler knows in which path in a filestore to store customer document
224    files and how to turn this kind of data into some (browsable)
225    file object.
226
227    It is called from the global file storage, when it wants to
228    get/store a file with a file id starting with
229    ``__file-customerdocument__`` (the marker string for customer files).
230
231    Like each other file store handler it does not handle the files
232    really (this is done by the global file store) but only computes
233    paths and things like this.
234    """
235    grok.implements(IFileStoreHandler)
236    grok.name(CUSTOMERDOCUMENT_FILE_STORE_NAME)
237
238    def pathFromFileID(self, store, root, file_id):
239        """All customer document files are put in directory ``customers``.
240        """
241        marker, filename, basename, ext = store.extractMarker(file_id)
242        sub_root = os.path.join(root, 'customers')
243        return super(CustomerDocumentFileStoreHandler, self).pathFromFileID(
244            store, sub_root, basename)
245
246    def createFile(self, store, root, filename, file_id, file):
247        """Create a browsable file-like object.
248        """
249        # call super method to ensure that any old files with
250        # different filename extension are deleted.
251        file, path, file_obj = super(
252            CustomerDocumentFileStoreHandler, self).createFile(
253            store, root,  filename, file_id, file)
254        return file, path, IkobaImageFile(
255            file_obj.filename, file_obj.data)
256
Note: See TracBrowser for help on using the repository browser.