[Erp5-report] r8681 - in /erp5/trunk/products/ERP5OOo: Document/ PropertySheet/
nobody at svn.erp5.org
nobody at svn.erp5.org
Sat Jul 22 13:08:41 CEST 2006
Author: bartek
Date: Sat Jul 22 13:08:26 2006
New Revision: 8681
URL: http://svn.erp5.org?rev=8681&view=rev
Log:
Added OOoDocument class
Added:
erp5/trunk/products/ERP5OOo/Document/
erp5/trunk/products/ERP5OOo/Document/OOoDocument.py
erp5/trunk/products/ERP5OOo/PropertySheet/OOoDocument.py
Added: erp5/trunk/products/ERP5OOo/Document/OOoDocument.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5OOo/Document/OOoDocument.py?rev=8681&view=auto
==============================================================================
--- erp5/trunk/products/ERP5OOo/Document/OOoDocument.py (added)
+++ erp5/trunk/products/ERP5OOo/Document/OOoDocument.py Sat Jul 22 13:08:26 2006
@@ -1,0 +1,466 @@
+
+##############################################################################
+#
+# Copyright (c) 2002-2006 Nexedi SARL and Contributors. All Rights Reserved.
+#
+# WARNING: This program as such is intended to be used by professional
+# programmers who take the whole responsability of assessing all potential
+# consequences resulting from its eventual inadequacies and bugs
+# End users who are looking for a ready-to-use solution with commercial
+# garantees and support are strongly adviced to contract a Free Software
+# Service Company
+#
+# This program is Free Software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+##############################################################################
+
+from AccessControl import ClassSecurityInfo
+from OFS.Image import Pdata
+from Products.CMFCore.utils import getToolByName
+from Products.CMFCore.WorkflowCore import WorkflowMethod
+from Products.ERP5Type import Permissions, PropertySheet, Constraint, Interface
+from Products.ERP5Type.Message import Message
+from Products.ERP5Type.Cache import CachingMethod
+from Products.ERP5.Document.File import File
+from Products.ERP5Type.XMLObject import XMLObject
+from DateTime import DateTime
+import xmlrpclib, base64
+
+enc=base64.encodestring
+dec=base64.decodestring
+
+class ConvertionError(Exception):pass
+
+class OOoDocument(File, XMLObject):
+ """
+ A file document able to convert OOo compatible files to
+ any OOo supported format, to capture metadata and to
+ update metadata in OOo documents.
+
+ This class can be used:
+
+ - to create an OOo document database with powerful indexing (r/o)
+ and metadata handling (r/w) features (ex. change title in ERP5 ->
+ title is changed in OOo document)
+
+ - to massively convert MS Office documents to OOo format
+
+ - to easily keep snapshots (in PDF and/or OOo format) of OOo documents
+ generated from OOo templates
+
+ This class may be used in the future:
+
+ - to create editable OOo templates (ex. by adding tags in WYSIWYG mode
+ and using tags to make document dynamic - ask kevin for more info)
+
+ - to automatically sign / encrypt OOo documents based on user
+
+ - to automatically sign / encrypt PDF generated from OOo documents based on user
+
+ This class should not be used:
+
+ - to store files in formats not supported by OOo
+
+ - to stored pure images (use Image for that)
+
+ - as a general file conversion system (use portal_transforms for that)
+ """
+ # CMF Type Definition
+ meta_type = 'ERP5 OOo Document'
+ portal_type = 'OOo Document'
+ isPortalContent = 1
+ isRADContent = 1
+
+ # Global variables
+ snapshot=None
+ oo_data=None
+
+ # Declarative security
+ security = ClassSecurityInfo()
+ security.declareObjectProtected(Permissions.AccessContentsInformation)
+
+ # Default Properties
+ property_sheets = ( PropertySheet.Base
+ , PropertySheet.CategoryCore
+ , PropertySheet.DublinCore
+ , PropertySheet.Version
+ , PropertySheet.Reference
+ , PropertySheet.OOoDocument
+ )
+
+ # time of generation of various formats
+ cached_time={}
+ # generated files (cache)
+ cached_data={}
+ # XXX the above craves for a separate class, but I'm not sure how to handle
+ # it in ZODB, so for now let it be
+
+ security.declareProtected(Permissions.ModifyPortalContent,'clearCache')
+ def clearCache(self):
+ """
+ Clear cache (invoked by interaction workflow upon file upload
+ needed here to overwrite class attribute with instance attrs
+ """
+ self.cached_time={}
+ self.cached_data={}
+
+ def _getServerCoordinates(self):
+ """
+ Returns OOo conversion server data from some
+ preferences. NOT IMPLEMENTED YET - XXX
+ """
+ return '192.168.0.3',8080
+
+ def _mkProxy(self):
+ sp=xmlrpclib.ServerProxy('http://%s:%d' % self._getServerCoordinates(),allow_none=True)
+ return sp
+
+ def returnMessage(self,msg,code=0):
+ """
+ code may be used in the future to indicate a problem
+ we distinguish data return from message by checking if it is a tuple
+ """
+ m=Message(domain='ui',message=msg)
+ return (code,m)
+
+ security.declareProtected(Permissions.ModifyPortalContent,'convert')
+ def convert(self,REQUEST=None):
+ """
+ Converts from the initial format to OOo format;
+ communicates with the conversion server
+ and gets converted file as well as metadata
+ """
+ if not self.isFileUploaded():
+ return self.returnMessage('OOo file is up do date')
+ try:
+ self._convert()
+ except xmlrpclib.Fault,e:
+ return self.returnMessage('Problem: %s' % str(e))
+ self.setLastConvertTime(DateTime())
+ return self.returnMessage('converted')
+
+ security.declareProtected(Permissions.AccessContentsInformation,'getTargetFormatList')
+ def getTargetFormatItemList(self):
+ """
+ Returns a list of acceptable formats for conversion
+ in the form of tuples (for listfield in ERP5Form)
+
+ XXX - to be implemented better (with extended API to conversion server)
+ XXX - what does this mean? I don't understand
+ """
+ # Caching method implementation
+ def cached_getTargetFormatItemList(mimetype):
+ sp=self._mkProxy()
+ allowed=sp.getAllowedTargets(mimetype)
+ return allowed
+
+ cached_getTargetFormatItemList = CachingMethod(cached_getTargetFormatItemList,
+ id = "OOoDocument_getTargetFormatItemList" )
+
+ return cached_getTargetFormatItemList(self.getMimeType())
+
+
+ security.declareProtected(Permissions.AccessContentsInformation,'getTargetFormatList')
+ def getTargetFormatList(self):
+ """
+ Returns a list of acceptable formats for conversion
+ """
+ return map(lambda x: x[0], self.getTargetFormatItemList())
+
+
+ security.declareProtected(Permissions.ModifyPortalContent,'isAllowed')
+ def isAllowed(self, format):
+ """
+ Checks if the current document can be converted
+ into the specified format.
+
+ """
+ if not self.hasOOfile(): return False
+ allowed=self.getTargetFormatList()
+ self.log('allowed',allowed)
+ if allowed is None: return False
+ return (format in allowed)
+
+ security.declareProtected(Permissions.ModifyPortalContent,'editMetadata')
+ def editMetadata(self,newmeta):
+ """
+ Updates metadata information in the converted OOo document
+ based on the values provided by the user. This is implemented
+ through the invocation of the conversion server.
+ """
+ self.log('editMetadata',newmeta)
+ for k,v in newmeta.items():
+ # OOo uses capitalized meta names
+ newmeta[k.capitalize()]=v
+ newmeta.pop(k)
+ self.log('newmeta',newmeta)
+ sp=self._mkProxy()
+ meta,oo_data=sp.run_setmetadata(self.getTitle(),enc(self._unpackData(self.oo_data)),newmeta)
+ self.log('res editMetadata',meta)
+ self.oo_data=Pdata(dec(oo_data))
+ self._setMetaData(meta)
+ return True # XXX why return ? - why not?
+
+ security.declarePrivate('_convert')
+ def _convert(self):
+ """
+ Converts the original document into OOo document
+ by invoking the conversion server. Store the result
+ on the object. Update metadata information.
+ """
+ sp=self._mkProxy()
+ self.log('_convert',enc(self._unpackData(self.data))[:500])
+ meta,oo_data=sp.run_convert(self.getOriginalFilename(),enc(self._unpackData(self.data)))
+ self.oo_data=Pdata(dec(oo_data))
+ self._setMetaData(meta)
+ #self.refreshAllowedTargets()
+
+ security.declarePrivate('_setMetaData')
+ def _setMetaData(self,meta):
+ """
+ Sets metadata properties of the ERP5 object.
+
+ XXX - please double check that some properties
+ are not already defined in the Document class (which is used
+ for Web Page in ERP5)
+
+ XXX - it would be quite nice if the metadata structure
+ could also support user fields in OOo
+ (user fields are so useful actually...)
+ """
+ self.log('meta',meta)
+ for k,v in meta.items():
+ meta[k]=v.encode('utf-8')
+ self.log('meta',meta)
+ self.setTitle(meta.get('Title',''))
+ self.setSubject(meta.get('Subject',''))
+ self.setKeywords(meta.get('Keywords',''))
+ self.setDescription(meta.get('Description',''))
+ if meta.get('MIMEType',False):
+ self.setMimeType(meta['MIMEType'])
+ self.setReference(meta.get('Reference',''))
+
+ #security.declareProtected(Permissions.View,'getOOfile')
+ def getOOfile(self):
+ """
+ Return the converted OOo document.
+
+ XXX - use a propertysheet for this instead. We have a type
+ called data in property sheet. Look at File implementation
+ XXX - doesn't seem to be there...
+ """
+ data=self.oo_data
+ return data
+
+ security.declarePrivate('_unpackData')
+ def _unpackData(self,data):
+ """
+ Unpack Pdata into string
+ """
+ if isinstance(data,str):
+ return data
+ else:
+ data_list=[]
+ while data is not None:
+ data_list.append(data.data)
+ data=data.next
+ return ''.join(data_list)
+
+ security.declareProtected(Permissions.View,'hasFile')
+ def hasFile(self):
+ """
+ Checks whether we have an initial file
+ """
+ _marker=[]
+ if getattr(self,'data',_marker) is not _marker: # XXX - use propertysheet accessors
+ return getattr(self,'data') is not None
+ return False
+
+ security.declareProtected(Permissions.View,'hasOOfile')
+ def hasOOfile(self):
+ """
+ Checks whether we have an OOo converted file
+ """
+ _marker=[]
+ if getattr(self,'oo_data',_marker) is not _marker: # XXX - use propertysheet accessors
+ return getattr(self,'oo_data') is not None
+ return False
+
+ security.declareProtected(Permissions.View,'hasSnapshot')
+ def hasSnapshot(self):
+ """
+ Checks whether we have a snapshot.
+ """
+ _marker=[]
+ if getattr(self,'snapshot',_marker) is not _marker: # XXX - use propertysheet accessors
+ return getattr(self,'snapshot') is not None
+ return False
+
+ security.declareProtected(Permissions.ModifyPortalContent,'createSnapshot')
+ def createSnapshot(self,REQUEST=None):
+ """
+ Create a PDF snapshot
+
+ XXX - we should not create a snapshot if some error happened at conversion
+ is this checked ?
+ """
+ if self.hasSnapshot():
+ if REQUEST is not None:
+ return self.returnMessage('already has a snapshot')
+ raise ConvertionError('already has a snapshot')
+ # making snapshot
+ self.makeFile('pdf')
+ self.snapshot=Pdata(self._unpackData(self.cached_data['pdf'])) # XXX - use propertysheet accessors
+ return self.returnMessage('snapshot created')
+
+ security.declareProtected(Permissions.View,'getSnapshot')
+ def getSnapshot(self,REQUEST=None):
+ """
+ Returns the snapshot.
+ """
+ '''getSnapshot'''
+ if not self.hasSnapshot():
+ self.createSnapshot()
+ return self.getSnapshot() # XXX - use propertysheet accessors
+
+ security.declareProtected(Permissions.ManagePortal,'deleteSnapshot')
+ def deleteSnapshot(self):
+ """
+ Deletes the snapshot - in theory this should never be done
+ """
+ try:
+ del(self.snapshot)
+ except AttributeError:
+ pass
+
+ security.declareProtected(Permissions.View,'getTargetFile')
+ def getTargetFile(self,format,REQUEST=None):
+ """
+ Get (possibly generate) file in a given format
+ """
+ if not self.isAllowed(format):
+ return self.returnMessage('can not convert to '+format+' for some reason')
+ try:
+ self.makeFile(format)
+ return self.cached_data[format]
+ except ConvertionError,e:
+ return self.returnMessage(str(e))
+
+ security.declareProtected(Permissions.View,'isFileUploaded')
+ def isFileUploaded(self):
+ """
+ Checks whether the file was uploaded after the last conversion into OOo
+ """
+ if not self.hasOOfile():return True
+ return self.getLastUploadTime() > self.getLastConvertTime()
+
+ security.declareProtected(Permissions.View,'hasFileCache')
+ def hasFileCache(self,format):
+ """
+ Checks whether we have a version in this format
+ """
+ return self.cached_data.has_key(format)
+
+ def getCacheTime(self,format):
+ """
+ Checks when if ever was the file produced
+ """
+ return self.cached_time.get(format,0)
+
+ security.declareProtected(Permissions.View,'isFileChanged')
+ def isFileChanged(self,format):
+ """
+ Checks whether the file was converted (or uploaded) after last generation of
+ the target format
+ """
+ if self.isFileUploaded(): return True
+ if not self.hasFileCache(format):return True
+ return self.getLastConvertTime()>self.getCacheTime(format)
+
+ security.declareProtected(Permissions.ModifyPortalContent,'makeFile')
+ def makeFile(self,format,REQUEST=None):
+ """
+ This method implement the file conversion cache:
+ * check if the format is supported
+ * check date of last conversion to OOo, compare with date of last
+ * if necessary, create new file and cache
+ * update file generation time
+
+ TODO:
+ * support of images in html conversion (as subobjects for example)
+ """
+ if not self.isAllowed(format):
+ errstr='%s format is not supported' % format
+ if REQUEST is not None:
+ return self.returnMessage(errstr)
+ raise ConvertionError(errstr)
+ if self.isFileUploaded():
+ if REQUEST is not None:
+ return self.returnMessage('needs conversion')
+ raise ConvertionError('needs conversion')
+ if self.isFileChanged(format):
+ try:
+ self.cached_data[format]=self._makeFile(format)
+ self._p_changed=1 # XXX not sure it is necessary
+ except xmlrpclib.Fault,e:
+ if REQUEST is not None:
+ return self.returnMessage('Problem: %s' % str(e))
+ else:
+ raise ConvertionError(str(e))
+ self.cached_time[format]=DateTime()
+ if REQUEST is not None:
+ return self.returnMessage('%s created' % format)
+ else:
+ if REQUEST is not None:
+ return self.returnMessage('%s file is up to date' % format)
+ return ConvertionError('%s file is up to date' % format)
+
+ security.declarePrivate('_makeFile')
+ def _makeFile(self,format):
+ """
+ Communicates with server to convert a file
+ """
+ # real version:
+ sp=self._mkProxy()
+ meta,file=sp.run_generate(self.getOriginalFilename(),enc(self._unpackData(self.oo_data)),format)
+ return Pdata(dec(file))
+
+ security.declareProtected(Permissions.View,'getCacheInfo')
+ def getCacheInfo(self):
+ """
+ Get cache details as string (for debugging)
+ """
+ s='CACHE INFO:<br/><table><tr><td>format</td><td>size</td><td>time</td><td>is changed</td></tr>'
+ self.log('getCacheInfo',self.cached_time)
+ self.log('getCacheInfo',self.cached_data)
+ for f in self.cached_time.keys():
+ t=self.cached_time[f]
+ data=self.cached_data.get(f)
+ if data:
+ if isinstance(data,str):
+ ln=len(data)
+ else:
+ ln=0
+ while data is not None:
+ ln+=len(data.data)
+ data=data.next
+ else:
+ ln='no data!!!'
+ s+='<tr><td>%s</td><td>%s</td><td>%s</td><td>%s</td></tr>' % (f,str(ln),str(t),str(self.isFileChanged(f)))
+ s+='</table>'
+ return s
+
+# vim: syntax=python shiftwidth=2
+
Added: erp5/trunk/products/ERP5OOo/PropertySheet/OOoDocument.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5OOo/PropertySheet/OOoDocument.py?rev=8681&view=auto
==============================================================================
--- erp5/trunk/products/ERP5OOo/PropertySheet/OOoDocument.py (added)
+++ erp5/trunk/products/ERP5OOo/PropertySheet/OOoDocument.py Sat Jul 22 13:08:26 2006
@@ -1,0 +1,72 @@
+##############################################################################
+#
+## Copyright (c) 2002 Nexedi SARL and Contributors. All Rights Reserved.
+#
+## WARNING: This program as such is intended to be used by professional
+# programmers who take the whole responsability of assessing all potential
+# # consequences resulting from its eventual inadequacies and bugs
+# # End users who are looking for a ready-to-use solution with commercial
+# # garantees and support are strongly adviced to contract a Free Software
+# # Service Company
+# #
+# # This program is Free Software; you can redistribute it and/or
+# # modify it under the terms of the GNU General Public License
+# # as published by the Free Software Foundation; either version 2
+# # of the License, or (at your option) any later version.
+# #
+# # This program is distributed in the hope that it will be useful,
+# # but WITHOUT ANY WARRANTY; without even the implied warranty of
+# # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# # GNU General Public License for more details.
+# #
+# # You should have received a copy of the GNU General Public License
+# # along with this program; if not, write to the Free Software
+# # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+# #
+# ##############################################################################
+
+class OOoDocument:
+ """
+
+ """
+
+ _properties = (
+ { 'id' : 'original_filename',
+ 'description' : 'name of the uploaded file',
+ 'type' : 'string',
+ 'mode' : '' },
+ { 'id' : 'original_format',
+ 'description' : 'format of the uploaded file',
+ 'type' : 'string',
+ 'mode' : '' },
+ { 'id' : 'pdf_generation_time',
+ 'description' : 'when pdf was generated',
+ 'type' : 'date',
+ 'mode' : ''},
+ { 'id' : 'last_upload_time',
+ 'description' : 'when the file was last uploaded',
+ 'type' : 'date',
+ 'mode' : ''},
+ { 'id' : 'last_convert_time',
+ 'description' : 'when the file was last converted',
+ 'type' : 'date',
+ 'mode' : ''},
+ { 'id' : 'keywords',
+ 'description' : 'keywords',
+ 'type' : 'string',
+ 'mode' : ''},
+ { 'id' : 'allowed_targets',
+ 'description':'a list of formats we can generate from OOo doc we have',
+ 'type' : 'lines',
+ 'mode' : ''},
+ { 'id' : 'mime_type',
+ 'description' : 'mime type of OOo version',
+ 'type' : 'string',
+ 'mode' : ''},
+ )
+
+ _categories = ('destination','similar','source','source_project')
+
+
+# vim: shiftwidth=2
+
More information about the Erp5-report
mailing list