source: main/waeup.ikoba/trunk/src/waeup/ikoba/documents/document.py @ 12229

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

Setup html documents. This technique replaces the usage of the HTMLDisplayWidget.

  • Property svn:keywords set to Id
File size: 9.0 KB
RevLine 
[12004]1## $Id: document.py 12227 2014-12-14 14:59:41Z henrik $
[11982]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"""
19These are the document tickets.
20"""
[12204]21import os
[11982]22import grok
23from grok import index
24from hurry.workflow.interfaces import IWorkflowInfo, IWorkflowState
25from zope.event import notify
26from zope.component import getUtility
27from zope.component.interfaces import IFactory
28from zope.interface import implementedBy
29from zope.i18n import translate
[12204]30
31from waeup.ikoba.image import IkobaImageFile
32from waeup.ikoba.imagestorage import DefaultFileStoreHandler
33from waeup.ikoba.interfaces import (
34    IIkobaUtils, IObjectHistory,
35    IFileStoreNameChooser, IFileStoreHandler, IExtFileStore)
[11982]36from waeup.ikoba.interfaces import MessageFactory as _
37from waeup.ikoba.utils.helpers import attrs_to_fields, get_current_principal
[12032]38from waeup.ikoba.documents.interfaces import (
[12213]39    IDocument, IPublicDocument, IDocumentsUtils,
[12200]40    IPDFDocument, IHTMLDocument)
[12005]41from waeup.ikoba.documents.utils import generate_document_id
[11982]42
[12063]43class Document(grok.Container):
[11982]44    """This is a document.
45    """
46    grok.implements(IDocument)
47    grok.provides(IDocument)
48    grok.baseclass()
49
[12214]50    form_fields_interface = None
51
[12211]52    local_roles = [
53        'waeup.local.DocumentManager',
54        ]
55
[12126]56    user_id = None
[12213]57    state = None
58    translated_state = None
[12214]59    translated_class_name = None
[12126]60
[11982]61    def __init__(self):
62        super(Document, self).__init__()
[12005]63        # The site doesn't exist in unit tests
64        try:
65            self.document_id = generate_document_id()
66        except AttributeError:
67            self.document_id = u'd123'
[11982]68        return
69
[11983]70    @property
71    def history(self):
72        history = IObjectHistory(self)
73        return history
74
[12017]75    @property
[12056]76    def class_name(self):
[12053]77        return self.__class__.__name__
78
79    @property
80    def formatted_transition_date(self):
81        try:
[12210]82            return self.history.messages[-1].split(' - ')[0]
83        except IndexError:
[12053]84            return
[12160]85
86    @property
87    def connected_files(self):
88        return
89
[12168]90    @property
91    def is_verifiable(self):
92        return True, None
93
[12161]94    def setMD5(self):
95        """Determine md5 checksum of all files and store checksums as
96        document attributes.
[12160]97        """
98        return
[12053]99       
[12213]100class PublicDocumentBase(Document):
101    """This is a customer document baseclass.
102    """
103    grok.implements(IPublicDocument)
104    grok.provides(IPublicDocument)
105    grok.baseclass()
[11982]106
[12213]107    @property
108    def state(self):
109        state = IWorkflowState(self).getState()
110        return state
[12161]111
[12213]112    @property
113    def translated_state(self):
114        try:
115            TRANSLATED_STATES = getUtility(
116                IDocumentsUtils).TRANSLATED_DOCUMENT_STATES
117            return TRANSLATED_STATES[self.state]
118        except KeyError:
119            return
120
[12214]121    @property
122    def translated_class_name(self):
123        try:
124            DOCTYPES_DICT = getUtility(IDocumentsUtils).DOCTYPES_DICT
125            return DOCTYPES_DICT[self.class_name]
126        except KeyError:
127            return
[12213]128
[12225]129    def writeLogMessage(self, view, message):
130        ob_class = view.__implemented__.__name__.replace('waeup.ikoba.','')
131        self.__parent__.__parent__.logger.info(
132            '%s - %s - %s' % (ob_class, self.__name__, message))
133        return
[12214]134
[12225]135
[12213]136class PDFDocument(PublicDocumentBase):
[12200]137    """This is a  document for a single pdf upload file.
138    """
139    grok.implements(IPDFDocument)
140    grok.provides(IPDFDocument)
141
[12214]142    form_fields_interface = IPDFDocument
143
[12200]144PDFDocument = attrs_to_fields(PDFDocument)
145
146
[12213]147class HTMLDocument(PublicDocumentBase):
[12200]148    """This is a  document to render html-coded text.
149    """
150    grok.implements(IHTMLDocument)
151    grok.provides(IHTMLDocument)
152
[12214]153    form_fields_interface = IHTMLDocument
154
[12227]155    def __init__(self, *args, **kw):
156        super(HTMLDocument, self).__init__(*args, **kw)
157        self.html_dict = None
158
[12200]159HTMLDocument = attrs_to_fields(HTMLDocument)
160
161
162class PDFDocumentFactory(grok.GlobalUtility):
163    """A factory for documents.
164    """
165    grok.implements(IFactory)
166    grok.name(u'waeup.PDFDocument')
167    title = u"Create a new PDF document.",
168    description = u"This factory instantiates new PDF documents."
169
170    def __call__(self, *args, **kw):
171        return PDFDocument(*args, **kw)
172
173    def getInterfaces(self):
174        return implementedBy(PDFDocument)
175
176
177class HTMLDocumentFactory(grok.GlobalUtility):
178    """A factory for HTML documents.
179    """
180    grok.implements(IFactory)
181    grok.name(u'waeup.HTMLDocument')
182    title = u"Create a new HTML document.",
183    description = u"This factory instantiates new HTML documents."
184
185    def __call__(self, *args, **kw):
186        return HTMLDocument(*args, **kw)
187
188    def getInterfaces(self):
189        return implementedBy(HTMLDocument)
190
[12204]191#: The file id marker for files
192DOCUMENT_FILE_STORE_NAME = 'file-document'
[12200]193
[12204]194
195class DocumentFileNameChooser(grok.Adapter):
196    """A file id chooser for :class:`Document` objects.
197
198    `context` is an :class:`Document` instance.
199
200    The delivered file_id contains the file id marker for
201    :class:`Document` objects in the central :class:`DocumentsContainer`.
202
203    This chooser is registered as an adapter providing
204    :class:`waeup.ikoba.interfaces.IFileStoreNameChooser`.
205
206    File store name choosers like this one are only convenience
207    components to ease the task of creating file ids for customer document
208    objects. You are nevertheless encouraged to use them instead of
209    manually setting up filenames for customer documents.
210
211    .. seealso:: :mod:`waeup.ikoba.imagestorage`
212
213    """
214
215    grok.context(IDocument)
216    grok.implements(IFileStoreNameChooser)
217
218    def checkName(self, name=None, attr=None):
219        """Check whether the given name is a valid file id for the context.
220
221        Returns ``True`` only if `name` equals the result of
222        :meth:`chooseName`.
223
224        """
225        return name == self.chooseName()
226
227    def chooseName(self, attr, name=None):
228        """Get a valid file id for customer document context.
229
230        *Example:*
231
232        For document with id 'd123'
233        with attr ``'nice_image.jpeg'`` stored in
234        the documents container this chooser would create:
235
236          ``'__file-document__documents/nice_image_d123.jpeg'``
237
238        meaning that the nice image of this document would be
239        stored in the site-wide file storage in path:
240
241          ``documents/nice_image_d123.jpeg``
242
243        """
244        basename, ext = os.path.splitext(attr)
245        doc_id = self.context.document_id
246        marked_filename = '__%s__documents/%s_%s%s' % (
247            DOCUMENT_FILE_STORE_NAME,
248            basename, doc_id, ext)
249        return marked_filename
250
251
252class DocumentFileStoreHandler(DefaultFileStoreHandler, grok.GlobalUtility):
253    """ Document specific file handling.
254
255    This handler knows in which path in a filestore to store document
256    files and how to turn this kind of data into some (browsable)
257    file object.
258
259    It is called from the global file storage, when it wants to
260    get/store a file with a file id starting with
261    ``__file-document__`` (the marker string for customer files).
262
263    Like each other file store handler it does not handle the files
264    really (this is done by the global file store) but only computes
265    paths and things like this.
266    """
267    grok.implements(IFileStoreHandler)
268    grok.name(DOCUMENT_FILE_STORE_NAME)
269
270    def pathFromFileID(self, store, root, file_id):
271        """All document files are put in directory ``documents``.
272        """
273        marker, filename, basename, ext = store.extractMarker(file_id)
274        sub_root = os.path.join(root, 'documents')
275        return super(DocumentFileStoreHandler, self).pathFromFileID(
276            store, sub_root, basename)
277
278    def createFile(self, store, root, filename, file_id, file):
279        """Create a browsable file-like object.
280        """
281        # call super method to ensure that any old files with
282        # different filename extension are deleted.
283        file, path, file_obj = super(
284            DocumentFileStoreHandler, self).createFile(
285            store, root,  filename, file_id, file)
286        return file, path, IkobaImageFile(
287            file_obj.filename, file_obj.data)
288
289
[11982]290@grok.subscribe(IDocument, grok.IObjectAddedEvent)
291def handle_document_added(document, event):
292    """If a document is added the transition create is fired.
293    The latter produces a logging message.
294    """
295    if IWorkflowState(document).getState() is None:
296        IWorkflowInfo(document).fireTransition('create')
297    return
Note: See TracBrowser for help on using the repository browser.