Changeset 12204 for main/waeup.ikoba/trunk/src/waeup/ikoba
- Timestamp:
- 12 Dec 2014, 18:28:54 (10 years ago)
- 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 19 19 These are the document tickets. 20 20 """ 21 import os 21 22 import grok 22 23 from time import time … … 28 29 from zope.interface import implementedBy 29 30 from zope.i18n import translate 30 from waeup.ikoba.interfaces import IIkobaUtils, IObjectHistory 31 32 from waeup.ikoba.image import IkobaImageFile 33 from waeup.ikoba.imagestorage import DefaultFileStoreHandler 34 from waeup.ikoba.interfaces import ( 35 IIkobaUtils, IObjectHistory, 36 IFileStoreNameChooser, IFileStoreHandler, IExtFileStore) 31 37 from waeup.ikoba.interfaces import MessageFactory as _ 32 38 from waeup.ikoba.utils.helpers import attrs_to_fields, get_current_principal … … 163 169 return implementedBy(HTMLDocument) 164 170 171 #: The file id marker for files 172 DOCUMENT_FILE_STORE_NAME = 'file-document' 173 174 175 class 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 232 class 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 165 269 166 270 @grok.subscribe(IDocument, grok.IObjectAddedEvent) -
main/waeup.ikoba/trunk/src/waeup/ikoba/documents/tests/test_document.py
r12203 r12204 19 19 Tests for documents. 20 20 """ 21 import shutil 22 import tempfile 23 from StringIO import StringIO 21 24 from zope.interface.verify import verifyClass, verifyObject 22 from zope.component import createObject 25 from zope.component import createObject, queryUtility 23 26 from hurry.workflow.interfaces import ( 24 27 IWorkflowInfo, IWorkflowState, InvalidTransitionError) 28 from waeup.ikoba.interfaces import ( 29 IObjectHistory, IFileStoreNameChooser, IFileStoreHandler) 30 from waeup.ikoba.imagestorage import DefaultStorage 25 31 from waeup.ikoba.documents.interfaces import ( 26 32 IDocumentsContainer, IDocument, IPDFDocument, IHTMLDocument) 27 from waeup.ikoba.interfaces import IObjectHistory28 33 from waeup.ikoba.documents.container import DocumentsContainer 29 34 from waeup.ikoba.documents.document import ( 30 Document, PDFDocument, HTMLDocument) 35 Document, PDFDocument, HTMLDocument, 36 DocumentFileNameChooser, DocumentFileStoreHandler) 31 37 from waeup.ikoba.testing import (FunctionalLayer, FunctionalTestCase) 32 38 … … 108 114 self.assertTrue('Document created by system' in messages) 109 115 return 116 117 118 class 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.