From afdf69df3084036085dea5bc7e107f5da518511b Mon Sep 17 00:00:00 2001
From: Nicolas Delaby <nicolas@nexedi.com>
Date: Wed, 12 May 2010 13:53:48 +0000
Subject: [PATCH] Use mixin

git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@35222 20353a03-c40f-0410-a6d1-a30d3c3de9de
---
 product/ERP5/Document/Document.py | 157 +++---------------------------
 1 file changed, 14 insertions(+), 143 deletions(-)

diff --git a/product/ERP5/Document/Document.py b/product/ERP5/Document/Document.py
index 82e68ac93c..750e368781 100644
--- a/product/ERP5/Document/Document.py
+++ b/product/ERP5/Document/Document.py
@@ -27,7 +27,7 @@
 #
 ##############################################################################
 
-import re, sys
+import re, sys, os
 from operator import add
 from zLOG import LOG
 from AccessControl import ClassSecurityInfo, getSecurityManager
@@ -38,9 +38,9 @@ from Products.ERP5Type.Globals import get_request
 from Products.CMFCore.utils import getToolByName, _checkPermission
 from Products.ERP5Type import Permissions, PropertySheet, interfaces
 from Products.ERP5Type.XMLObject import XMLObject
-from Products.ERP5Type.DateUtils import convertDateToHour, number_of_hours_in_day, number_of_hours_in_year
+from Products.ERP5Type.DateUtils import convertDateToHour,\
+                                number_of_hours_in_day, number_of_hours_in_year
 from Products.ERP5Type.Utils import convertToUpperCase
-from Products.ERP5Type.Base import WorkflowMethod
 from Products.ERP5Type.TransactionalVariable import getTransactionalVariable
 from Products.ERP5Type.ExtensibleTraversable import ExtensibleTraversableMixIn
 from Products.ERP5Type.Cache import getReadOnlyTransactionCache
@@ -50,12 +50,14 @@ from Products.ERP5Type.UnrestrictedMethod import unrestricted_apply
 from Products.ZSQLCatalog.SQLCatalog import SQLQuery
 from AccessControl import Unauthorized
 import zope.interface
-import cStringIO
-from OFS.Image import Pdata
 from Products.PythonScripts.Utility import allow_class
+import tempfile
+from subprocess import Popen, PIPE
 
 # Mixin Import
 from Products.ERP5.mixin.cached_convertable import CachedConvertableMixin
+from Products.ERP5.mixin.text_convertable import TextConvertableMixin
+from Products.ERP5.mixin.downloadable import DownloadableMixin
 
 _MARKER = []
 VALID_ORDER_KEY_LIST = ('user_login', 'content', 'file_name', 'input')
@@ -314,7 +316,9 @@ class UpdateMixIn:
     return method()
 
 
-class Document(PermanentURLMixIn, XMLObject, UrlMixIn, CachedConvertableMixin, SnapshotMixin, UpdateMixIn):
+class Document(PermanentURLMixIn, XMLObject, UrlMixIn, CachedConvertableMixin,
+               SnapshotMixin, UpdateMixIn, TextConvertableMixin,
+               DownloadableMixin):
   """Document is an abstract class with all methods related to document
   management in ERP5. This includes searchable text, explicit relations,
   implicit relations, metadata, versions, languages, etc.
@@ -519,38 +523,9 @@ class Document(PermanentURLMixIn, XMLObject, UrlMixIn, CachedConvertableMixin, S
                     )
 
   searchable_property_list = ('asText', 'title', 'description', 'id', 'reference',
-                              'version', 'short_title',
-                              'subject', 'source_reference',)
-
-  ### Content processing methods
-  security.declareProtected(Permissions.View, 'index_html')
-  def index_html(self, REQUEST, RESPONSE, format=None, **kw):
-    """
-      We follow here the standard Zope API for files and images
-      and extend it to support format conversion. The idea
-      is that an image which ID is "something.jpg" should
-      ne directly accessible through the URL
-      /a/b/something.jpg. The same is true for a file and
-      for any document type which primary purpose is to
-      be used by a helper application rather than displayed
-      as HTML in a web browser. Exceptions to this approach
-      include Web Pages which are intended to be primarily rendered
-      withing the layout of a Web Site or withing a standard ERP5 page.
-      Please refer to the index_html of TextDocument.
-
-      Should return appropriate format (calling convert
-      if necessary) and set headers.
-
-      format -- the format specied in the form of an extension
-      string (ex. jpeg, html, text, txt, etc.)
+                              'version', 'short_title', 'subject',
+                              'source_reference', 'source_project_title')
 
-      **kw -- can be various things - e.g. resolution
-
-      TODO:
-      - implement guards API so that conversion to certain
-        formats require certain permission
-    """
-    raise NotImplementedError
 
   security.declareProtected(Permissions.View, 'getSearchableText')
   def getSearchableText(self, md=None):
@@ -594,6 +569,8 @@ class Document(PermanentURLMixIn, XMLObject, UrlMixIn, CachedConvertableMixin, S
   # Compatibility with CMF Catalog
   SearchableText = getSearchableText
 
+  index_html = DownloadableMixin.index_html
+
   security.declareProtected(Permissions.AccessContentsInformation, 'isExternalDocument')
   def isExternalDocument(self):
     """
@@ -1014,16 +991,6 @@ class Document(PermanentURLMixIn, XMLObject, UrlMixIn, CachedConvertableMixin, S
                             # disappear within a given transaction
     return kw
 
-  security.declareProtected(Permissions.AccessContentsInformation, 'getStandardFileName')
-  def getStandardFileName(self):
-    """
-    Returns the document coordinates as a standard file name. This
-    method is the reverse of getPropertyDictFromFileName.
-    """
-    method = self._getTypeBasedMethod('getStandardFileName',
-        fallback_script_id = 'Document_getStandardFileName')
-    return method()
-
   ### Metadata disovery and ingestion methods
   security.declareProtected(Permissions.ModifyPortalContent, 'discoverMetadata')
   def discoverMetadata(self, file_name=None, user_login=None):
@@ -1107,10 +1074,6 @@ class Document(PermanentURLMixIn, XMLObject, UrlMixIn, CachedConvertableMixin, S
       - implement guards API so that conversion to certain
         formats require certain permission
     """
-    if format == 'html':
-      return 'text/html', '' # XXX - Why ?
-    if format in ('text', 'txt'):
-      return 'text/plain', '' # XXX - Why ?
     raise NotImplementedError
 
   security.declareProtected(Permissions.View, 'asSubjectText')
@@ -1124,15 +1087,6 @@ class Document(PermanentURLMixIn, XMLObject, UrlMixIn, CachedConvertableMixin, S
       subject = self.getTitle('')
     return str(subject)
 
-  security.declareProtected(Permissions.View, 'asText')
-  def asText(self, **kw):
-    """
-      Converts the content of the document to a textual representation.
-    """
-    kw['format'] = 'txt'
-    mime, data = self.convert(**kw)
-    return str(data)
-
   security.declareProtected(Permissions.View, 'asEntireHTML')
   def asEntireHTML(self, **kw):
     """
@@ -1160,8 +1114,6 @@ class Document(PermanentURLMixIn, XMLObject, UrlMixIn, CachedConvertableMixin, S
       A private method which converts to HTML. This method
       is the one to override in subclasses.
     """
-    if not self.hasBaseData():
-      raise ConversionError('This document has not been processed yet.')
     kw['format'] = 'html'
     mime, html = self.convert(**kw)
     return html
@@ -1264,11 +1216,6 @@ class Document(PermanentURLMixIn, XMLObject, UrlMixIn, CachedConvertableMixin, S
       message = ''
     return message
 
-  def _convertToBaseFormat(self):
-    """
-    """
-    raise NotImplementedError
-
   security.declareProtected(Permissions.AccessContentsInformation,
                             'isSupportBaseDataConversion')
   def isSupportBaseDataConversion(self):
@@ -1276,12 +1223,6 @@ class Document(PermanentURLMixIn, XMLObject, UrlMixIn, CachedConvertableMixin, S
     """
     return False
 
-  def convertFile(self, **kw): # XXX - It it really useful to explicitly define ?
-    """
-    Workflow transition invoked when conversion occurs.
-    """
-  convertFile = WorkflowMethod(convertFile)
-
   security.declareProtected(Permissions.AccessContentsInformation,
                             'getMetadataMappingDict')
   def getMetadataMappingDict(self):
@@ -1298,18 +1239,6 @@ class Document(PermanentURLMixIn, XMLObject, UrlMixIn, CachedConvertableMixin, S
     else:
       return {}
 
-  security.declareProtected(Permissions.ModifyPortalContent, 'updateBaseMetadata')
-  def updateBaseMetadata(self, **kw):
-    """
-    Update the base format data with the latest properties entered
-    by the user. For example, if title is changed in ERP5 interface,
-    the base format file should be updated accordingly.
-
-    Default implementation does nothing. Refer to OOoDocument class
-    for an example of implementation.
-    """
-    pass
-
   # Transformation API
   security.declareProtected(Permissions.ModifyPortalContent, 'populateContent')
   def populateContent(self):
@@ -1390,61 +1319,3 @@ class Document(PermanentURLMixIn, XMLObject, UrlMixIn, CachedConvertableMixin, S
         # but not in http://www.some.site/at
         base_url = '/'.join(base_url_list[:-1])
     return base_url
-
-  security.declareProtected(Permissions.ModifyPortalContent, '_setBaseData')
-  def _setBaseData(self, data):
-    """
-      XXX - it is really wrong to put this method here since not
-      all documents are subclasses of "File". Instead, there should
-      be a interface for all classes which can convert their data
-      to a base format.
-    """
-    if not isinstance(data, Pdata) and data is not None:
-      file = cStringIO.StringIO(data)
-      data, size = self._read_data(file)
-    self._baseSetBaseData(data)
-
-  security.declareProtected(Permissions.AccessContentsInformation,
-                            'getBaseData')
-  def getBaseData(self, default=None):
-    """return BaseData as str."""
-    base_data = self._baseGetBaseData()
-    if base_data is None:
-      return None
-    else:
-      return str(base_data)
-
-  security.declareProtected(Permissions.ModifyPortalContent, '_setData')
-  def _setData(self, data):
-    """
-      XXX - it is really wrong to put this method here since not
-      all documents are subclasses of "File". Instead, there should
-      be a interface for all classes which can act as a File.
-    """
-    size = None
-    # update_data use len(data) when size is None, which breaks this method.
-    # define size = 0 will prevent len be use and keep the consistency of 
-    # getData() and setData()
-    if data is None:
-      size = 0
-    if not isinstance(data, Pdata) and data is not None:
-      file = cStringIO.StringIO(data)
-      data, size = self._read_data(file)
-    if getattr(self, 'update_data', None) is not None:
-      # We call this method to make sure size is set and caches reset
-      self.update_data(data, size=size)
-    else:
-      self._baseSetData(data) # XXX - It would be better to always use this accessor
-      self.size=size # Using accessor or caching method would be better
-      self.ZCacheable_invalidate()
-      self.ZCacheable_set(None)
-      self.http__refreshEtag()
-
-  security.declareProtected(Permissions.AccessContentsInformation, 'getData')
-  def getData(self, default=None):
-    """return Data as str."""
-    data = self._baseGetData()
-    if data is None:
-      return None
-    else:
-      return str(data)
-- 
2.30.9