Ignore:
Timestamp:
12 Dec 2014, 18:28:54 (10 years ago)
Author:
Henrik Bettermann
Message:

Add DocumentFileNameChooser? and DocumentFileStoreHandler? with functional tests.

Location:
main/waeup.ikoba/trunk/src/waeup/ikoba/documents
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • main/waeup.ikoba/trunk/src/waeup/ikoba/documents/document.py

    r12200 r12204  
    1919These are the document tickets.
    2020"""
     21import os
    2122import grok
    2223from time import time
     
    2829from zope.interface import implementedBy
    2930from zope.i18n import translate
    30 from waeup.ikoba.interfaces import IIkobaUtils, IObjectHistory
     31
     32from waeup.ikoba.image import IkobaImageFile
     33from waeup.ikoba.imagestorage import DefaultFileStoreHandler
     34from waeup.ikoba.interfaces import (
     35    IIkobaUtils, IObjectHistory,
     36    IFileStoreNameChooser, IFileStoreHandler, IExtFileStore)
    3137from waeup.ikoba.interfaces import MessageFactory as _
    3238from waeup.ikoba.utils.helpers import attrs_to_fields, get_current_principal
     
    163169        return implementedBy(HTMLDocument)
    164170
     171#: The file id marker for files
     172DOCUMENT_FILE_STORE_NAME = 'file-document'
     173
     174
     175class DocumentFileNameChooser(grok.Adapter):
     176    """A file id chooser for :class:`Document` objects.
     177
     178    `context` is an :class:`Document` instance.
     179
     180    The delivered file_id contains the file id marker for
     181    :class:`Document` objects in the central :class:`DocumentsContainer`.
     182
     183    This chooser is registered as an adapter providing
     184    :class:`waeup.ikoba.interfaces.IFileStoreNameChooser`.
     185
     186    File store name choosers like this one are only convenience
     187    components to ease the task of creating file ids for customer document
     188    objects. You are nevertheless encouraged to use them instead of
     189    manually setting up filenames for customer documents.
     190
     191    .. seealso:: :mod:`waeup.ikoba.imagestorage`
     192
     193    """
     194
     195    grok.context(IDocument)
     196    grok.implements(IFileStoreNameChooser)
     197
     198    def checkName(self, name=None, attr=None):
     199        """Check whether the given name is a valid file id for the context.
     200
     201        Returns ``True`` only if `name` equals the result of
     202        :meth:`chooseName`.
     203
     204        """
     205        return name == self.chooseName()
     206
     207    def chooseName(self, attr, name=None):
     208        """Get a valid file id for customer document context.
     209
     210        *Example:*
     211
     212        For document with id 'd123'
     213        with attr ``'nice_image.jpeg'`` stored in
     214        the documents container this chooser would create:
     215
     216          ``'__file-document__documents/nice_image_d123.jpeg'``
     217
     218        meaning that the nice image of this document would be
     219        stored in the site-wide file storage in path:
     220
     221          ``documents/nice_image_d123.jpeg``
     222
     223        """
     224        basename, ext = os.path.splitext(attr)
     225        doc_id = self.context.document_id
     226        marked_filename = '__%s__documents/%s_%s%s' % (
     227            DOCUMENT_FILE_STORE_NAME,
     228            basename, doc_id, ext)
     229        return marked_filename
     230
     231
     232class DocumentFileStoreHandler(DefaultFileStoreHandler, grok.GlobalUtility):
     233    """ Document specific file handling.
     234
     235    This handler knows in which path in a filestore to store document
     236    files and how to turn this kind of data into some (browsable)
     237    file object.
     238
     239    It is called from the global file storage, when it wants to
     240    get/store a file with a file id starting with
     241    ``__file-document__`` (the marker string for customer files).
     242
     243    Like each other file store handler it does not handle the files
     244    really (this is done by the global file store) but only computes
     245    paths and things like this.
     246    """
     247    grok.implements(IFileStoreHandler)
     248    grok.name(DOCUMENT_FILE_STORE_NAME)
     249
     250    def pathFromFileID(self, store, root, file_id):
     251        """All document files are put in directory ``documents``.
     252        """
     253        marker, filename, basename, ext = store.extractMarker(file_id)
     254        sub_root = os.path.join(root, 'documents')
     255        return super(DocumentFileStoreHandler, self).pathFromFileID(
     256            store, sub_root, basename)
     257
     258    def createFile(self, store, root, filename, file_id, file):
     259        """Create a browsable file-like object.
     260        """
     261        # call super method to ensure that any old files with
     262        # different filename extension are deleted.
     263        file, path, file_obj = super(
     264            DocumentFileStoreHandler, self).createFile(
     265            store, root,  filename, file_id, file)
     266        return file, path, IkobaImageFile(
     267            file_obj.filename, file_obj.data)
     268
    165269
    166270@grok.subscribe(IDocument, grok.IObjectAddedEvent)
  • main/waeup.ikoba/trunk/src/waeup/ikoba/documents/tests/test_document.py

    r12203 r12204  
    1919Tests for documents.
    2020"""
     21import shutil
     22import tempfile
     23from StringIO import StringIO
    2124from zope.interface.verify import verifyClass, verifyObject
    22 from zope.component import createObject
     25from zope.component import createObject, queryUtility
    2326from hurry.workflow.interfaces import (
    2427    IWorkflowInfo, IWorkflowState, InvalidTransitionError)
     28from waeup.ikoba.interfaces import (
     29    IObjectHistory, IFileStoreNameChooser, IFileStoreHandler)
     30from waeup.ikoba.imagestorage import DefaultStorage
    2531from waeup.ikoba.documents.interfaces import (
    2632    IDocumentsContainer, IDocument, IPDFDocument, IHTMLDocument)
    27 from waeup.ikoba.interfaces import IObjectHistory
    2833from waeup.ikoba.documents.container import DocumentsContainer
    2934from waeup.ikoba.documents.document import (
    30     Document, PDFDocument, HTMLDocument)
     35    Document, PDFDocument, HTMLDocument,
     36    DocumentFileNameChooser, DocumentFileStoreHandler)
    3137from waeup.ikoba.testing import (FunctionalLayer, FunctionalTestCase)
    3238
     
    108114        self.assertTrue('Document created by system' in messages)
    109115        return
     116
     117
     118class DocumentFileTests(FunctionalTestCase):
     119
     120    layer = FunctionalLayer
     121
     122    def setUp(self):
     123        super(DocumentFileTests, self).setUp()
     124        self.workdir = tempfile.mkdtemp()
     125        return
     126
     127    def tearDown(self):
     128        super(DocumentFileTests, self).tearDown()
     129        shutil.rmtree(self.workdir)
     130        return
     131
     132    def test_file_store_handler_util_accessible(self):
     133        # we can get an IFileStoreHandler utility for documents
     134        handler = queryUtility(IFileStoreHandler, name='file-document')
     135        self.assertTrue(
     136            isinstance(handler, DocumentFileStoreHandler))
     137        return
     138
     139    def test_file_store_handler(self):
     140        store = DefaultStorage()
     141        handler = queryUtility(IFileStoreHandler, name='file-document')
     142        result = handler.pathFromFileID(
     143            store, '/fake-root', '__any_marker__sample.jpg')
     144        self.assertEqual(
     145            result, '/fake-root/documents/sample')
     146        return
     147
     148    def test_file_store_handler_create(self):
     149        # we can create files in image store with the document file
     150        # store handler
     151        store = DefaultStorage(self.workdir)
     152        handler = queryUtility(IFileStoreHandler, name='file-document')
     153        file_obj, path, waeup_file = handler.createFile(
     154            store, store.root, 'sample.jpg', '__file_document__sample',
     155            StringIO('I am a JPG file'))
     156        self.assertEqual(path[-20:], 'documents/sample.jpg')
     157        return
     158
     159    def test_iface(self):
     160        # make sure we implement promised interfaces
     161        obj = DocumentFileNameChooser(None) # needs a context normally
     162        verifyClass(IFileStoreNameChooser, DocumentFileNameChooser)
     163        verifyObject(IFileStoreNameChooser, obj)
     164        return
     165
     166    def test_name_chooser_available(self):
     167        # we can get a name chooser for document objects as adapter
     168        doc = Document()
     169        chooser = IFileStoreNameChooser(doc)
     170        self.assertTrue(chooser is not None)
     171        return
     172
     173    def test_name_chooser_document(self):
     174        # we can get an image filename for documents not in a container
     175        doc = Document()
     176        chooser = IFileStoreNameChooser(doc)
     177        result = chooser.chooseName('sample.jpg')
     178        # the file would be stored in a ``_default`` directory.
     179        self.assertEqual(
     180            result, '__file-document__documents/sample_d123.jpg')
     181        return
Note: See TracChangeset for help on using the changeset viewer.