diff --git a/fields/pod.py b/fields/pod.py
index 807bf23..25f9c60 100644
--- a/fields/pod.py
+++ b/fields/pod.py
@@ -33,12 +33,15 @@ class Pod(Field):
want to put in it. It is the way gen uses pod.'''
# Layout for rendering a POD field for exporting query results.
rLayouts = {'view': Table('fl', width=None)}
+ allFormats = ('pdf', 'doc', 'odt')
POD_ERROR = 'An error occurred while generating the document. Please ' \
'contact the system administrator.'
- DELETE_TEMP_DOC_ERROR = 'A temporary document could not be removed. %s.'
NO_TEMPLATE = 'Please specify a pod template in field "template".'
UNAVAILABLE_TEMPLATE = 'You are not allow to perform this action.'
TEMPLATE_NOT_FOUND = 'Template not found at %s.'
+ FREEZE_ERROR = 'Error while trying to freeze a "%s" file in pod field ' \
+ '"%s" (%s).'
+ FREEZE_FATAL_ERROR = 'Server error. Please contact the administrator.'
pxView = pxCell = Px('''
@@ -68,8 +71,7 @@ class Pod(Field):
maxChars=None, colspan=1, master=None, masterValue=None,
focus=False, historized=False, mapping=None, label=None,
template=None, templateName=None, showTemplate=None,
- context=None, stylesMapping={}, formats=None,
- freezeFormat='pdf'):
+ context=None, stylesMapping={}, formats=None):
# Param "template" stores the path to the pod template(s).
if not template: raise Exception(Pod.NO_TEMPLATE)
if isinstance(template, basestring):
@@ -107,8 +109,6 @@ class Pod(Field):
self.formats = ('xls', 'ods')
else:
self.formats = ('pdf', 'doc', 'odt')
- # Freeze format is PDF by default.
- self.freezeFormat = freezeFormat
Field.__init__(self, None, (0,1), default, show, page, group, layouts,
move, indexed, searchable, specificReadPermission,
specificWritePermission, width, height, None, colspan,
@@ -118,18 +118,12 @@ class Pod(Field):
# field is determined by freezing.
self.validable = False
- def isFrozen(self, obj):
- '''Is there a frozen document for p_self on p_obj?'''
- value = getattr(obj.o.aq_base, self.name, None)
- return isinstance(value, obj.o.getProductConfig().File)
-
def getOutputFormats(self, obj):
'''Returns self.formats, excepted if there is a frozen document: in
this case, only the format of the frozen doc is returned.'''
- if not self.isFrozen(obj): return self.formats
- # The only available format is the one from the frozen document
- fileName = getattr(obj.o.aq_base, self.name).filename
- return (os.path.splitext(fileName)[1][1:],)
+ if not obj.user.has_role('Manager'): return self.formats
+ # A manager can have all formats
+ return self.allFormats
def getTemplateName(self, obj, fileName):
'''Gets the name of a template given its p_fileName.'''
@@ -143,6 +137,16 @@ class Pod(Field):
res = gutils.produceNiceMessage(name)
return res
+ def getDownloadName(self, obj, template, format, queryRelated):
+ '''Gets the name of the pod result as will be seen by the user that will
+ download it.'''
+ fileName = self.getTemplateName(obj, template)
+ if not queryRelated:
+ # This is a POD for a single object: personalize the file name with
+ # the object title.
+ fileName = '%s-%s' % (obj.title, fileName)
+ return obj.tool.normalize(fileName) + '.' + format
+
def getVisibleTemplates(self, obj):
'''Returns, among self.template, the template(s) that can be shown.'''
if not self.showTemplate: return self.template # Show them all.
@@ -152,23 +156,30 @@ class Pod(Field):
res.append(template)
return res
- def getValue(self, obj):
+ def getValue(self, obj, template=None, format=None, result=None):
'''For a pod field, getting its value means computing a pod document or
returning a frozen one. A pod field differs from other field types
because there can be several ways to produce the field value (ie:
self.template can hold various templates; output file format can be
odt, pdf,.... We get those precisions about the way to produce the
- file from the request object. If we don't find the request object (or
- if it does not exist, ie, when Zope runs in test mode), we use
- default values.'''
- rq = getattr(obj, 'REQUEST') or Object()
+ file, either:
+ - from params p_template and p_format;
+ - from the request object;
+ - from default values (the request object may not be present, ie,
+ when Zope runs in test mode).'''
obj = obj.appy()
- template = rq.get('template') or self.template[0]
+ rq = obj.request
+ template = template or rq.get('template') or self.template[0]
+ format = format or rq.get('podFormat') or 'odt'
# Security check.
if not self.showTemplate(obj, template):
raise Exception(self.UNAVAILABLE_TEMPLATE)
# Return the frozen document if frozen.
- # if ...
+ frozen = self.isFrozen(obj, template, format)
+ if frozen:
+ print 'RETURN FROZEN'
+ fileName = self.getDownloadName(obj, template, format, False)
+ return FileInfo(frozen, inDb=False, uploadName=fileName)
# We must call pod to compute a pod document from "template".
tool = obj.tool
diskFolder = tool.getDiskFolder()
@@ -176,17 +187,16 @@ class Pod(Field):
templatePath = os.path.join(diskFolder, template)
if not os.path.isfile(templatePath):
raise Exception(self.TEMPLATE_NOT_FOUND % templatePath)
- # Get the output format
- outputFormat = rq.get('podFormat', 'odt')
# Get or compute the specific POD context
specificContext = None
if callable(self.context):
specificContext = self.callMethod(obj, self.context)
else:
specificContext = self.context
- # Temporary file where to generate the result
- tempFileName = '%s/%s_%f.%s' % (
- sutils.getOsTempFolder(), obj.uid, time.time(), outputFormat)
+ # Compute the name of the result file.
+ if not result:
+ result = '%s/%s_%f.%s' % (sutils.getOsTempFolder(),
+ obj.uid, time.time(), format)
# Define parameters to give to the appy.pod renderer
podContext = {'tool': tool, 'user': obj.user, 'self': obj, 'field':self,
'now': obj.o.getProductConfig().DateTime(),
@@ -209,7 +219,7 @@ class Pod(Field):
if specificContext:
podContext.update(specificContext)
# If a custom param comes from the request, add it to the context. A
- # custom param must have format "name:value". Custom params override any
+ # custom param must have form "name:value". Custom params override any
# other value in the request, including values from the field-specific
# context.
customParams = rq.get('customParams', None)
@@ -222,8 +232,9 @@ class Pod(Field):
else:
stylesMapping = self.stylesMapping
rendererParams = {'template': templatePath, 'context': podContext,
- 'result': tempFileName, 'stylesMapping':stylesMapping,
- 'imageResolver': tool.o.getApp()}
+ 'result': result, 'stylesMapping': stylesMapping,
+ 'imageResolver': tool.o.getApp(),
+ 'overwriteExisting': True}
if tool.unoEnabledPython:
rendererParams['pythonWithUnoPath'] = tool.unoEnabledPython
if tool.openOfficePort:
@@ -233,31 +244,71 @@ class Pod(Field):
renderer = Renderer(**rendererParams)
renderer.run()
except PodError, pe:
- if not os.path.exists(tempFileName):
+ if not os.path.exists(result):
# In some (most?) cases, when OO returns an error, the result is
# nevertheless generated.
obj.log(str(pe).strip(), type='error')
return Pod.POD_ERROR
# Give a friendly name for this file
- fileName = self.getTemplateName(obj, template)
- if not isQueryRelated:
- # This is a POD for a single object: personalize the file name with
- # the object title.
- fileName = '%s-%s' % (obj.title, fileName)
- fileName = tool.normalize(fileName) + '.' + outputFormat
- # Get a FileInfo instance to manipulate the temp file on the filesystem.
- return FileInfo(tempFileName, inDb=False, uploadName=fileName)
+ fileName = self.getDownloadName(obj, template, format, isQueryRelated)
+ # Get a FileInfo instance to manipulate the file on the filesystem.
+ return FileInfo(result, inDb=False, uploadName=fileName)
- # Returns the doc and removes the temp file
- try:
- os.remove(tempFileName)
- except Exception, e:
- obj.log(Pod.DELETE_TEMP_DOC_ERROR % str(e).strip(), type='warning')
- return res
+ def getFreezeName(self, template=None, format='pdf'):
+ '''Gets the name on disk on the frozen document corresponding to this
+ pod field, p_template and p_format.'''
+ template = template or self.template[0]
+ templateName = os.path.splitext(template)[0].replace(os.sep, '_')
+ return '%s_%s.%s' % (self.name, templateName, format)
- def store(self, obj, value):
- '''Stores (=freezes) a document (in p_value) in the field.'''
- if isinstance(value, sutils.FileWrapper):
- value = value._zopeFile
- setattr(obj, self.name, value)
+ def isFrozen(self, obj, template=None, format='pdf'):
+ '''Is there a frozen document for thid pod field, on p_obj, for
+ p_template in p_format? If yes, it returns the absolute path to the
+ frozen doc.'''
+ template = template or self.template[0]
+ dbFolder, folder = obj.o.getFsFolder()
+ fileName = self.getFreezeName(template, format)
+ res = os.path.join(dbFolder, folder, fileName)
+ if os.path.exists(res): return res
+
+ def freeze(self, obj, template=None, format='pdf'):
+ '''Freezes, on p_obj, a document for this pod field, for p_template in
+ p_format.'''
+ # Compute the absolute path where to store the frozen document in the
+ # database.
+ dbFolder, folder = obj.o.getFsFolder(create=True)
+ fileName = self.getFreezeName(template, format)
+ result = os.path.join(dbFolder, folder, fileName)
+ if os.path.exists(result):
+ obj.log('Freeze: overwriting %s...' % result)
+ # Generate the document.
+ doc = self.getValue(obj, template=template, format=format,
+ result=result)
+ if isinstance(doc, basestring):
+ # An error occurred, the document was not generated.
+ obj.log(self.FREEZE_ERROR % (format, self.name, doc), type='error')
+ if format == 'odt': raise Exception(self.FREEZE_FATAL_ERROR)
+ obj.log('Trying to freeze the ODT version...')
+ # Try to freeze the ODT version of the document, which does not
+ # require to call LibreOffice: the risk of error is smaller.
+ fileName = self.getFreezeName(template, 'odt')
+ result = os.path.join(dbFolder, folder, fileName)
+ if os.path.exists(result):
+ obj.log('Freeze: overwriting %s...' % result)
+ doc = self.getValue(obj, template=template, format='odt',
+ result=result)
+ if isinstance(doc, basestring):
+ self.log(self.FREEZE_ERROR % ('odt', self.name, doc),
+ type='error')
+ raise Exception(self.FREEZE_FATAL_ERROR)
+ return doc
+
+ def unfreeze(self, obj, template=None, format='pdf'):
+ '''Unfreezes, on p_obj, the document for this pod field, for p_template
+ in p_format.'''
+ # Compute the absolute path to the frozen doc.
+ dbFolder, folder = obj.o.getFsFolder()
+ fileName = self.getFreezeName(template, format)
+ frozenName = os.path.join(dbFolder, folder, fileName)
+ if os.path.exists(frozenName): os.remove(frozenName)
# ------------------------------------------------------------------------------
diff --git a/gen/mixins/ToolMixin.py b/gen/mixins/ToolMixin.py
index 6607524..f16daf5 100644
--- a/gen/mixins/ToolMixin.py
+++ b/gen/mixins/ToolMixin.py
@@ -115,6 +115,7 @@ class ToolMixin(BaseMixin):
# Get the object on which a document must be generated.
obj = self.getObject(rq.get('objectUid'), appy=True)
fieldName = rq.get('fieldName')
+ # Get the document by accessing the value of the pod field.
res = getattr(obj, fieldName)
if isinstance(res, basestring):
# An error has occurred, and p_res contains the error message
@@ -122,8 +123,6 @@ class ToolMixin(BaseMixin):
return self.goto(rq.get('HTTP_REFERER'))
# res contains a FileInfo instance.
res.writeResponse(rq.RESPONSE)
- # (Try to) delete the temp file on disk.
- res.removeFile()
def getAppName(self):
'''Returns the name of the application.'''
diff --git a/gen/wrappers/__init__.py b/gen/wrappers/__init__.py
index 6d588a8..0e7ac92 100644
--- a/gen/wrappers/__init__.py
+++ b/gen/wrappers/__init__.py
@@ -13,12 +13,6 @@ from appy.shared.utils import getOsTempFolder, executeCommand, \
from appy.shared.xml_parser import XmlMarshaller
from appy.shared.csv_parser import CsvMarshaller
-# Some error messages ----------------------------------------------------------
-FREEZE_ERROR = 'Error while trying to freeze a "%s" file in POD field ' \
- '"%s" (%s).'
-FREEZE_FATAL_ERROR = 'A server error occurred. Please contact the system ' \
- 'administrator.'
-
# ------------------------------------------------------------------------------
class AbstractWrapper(object):
'''Any real Appy-managed Zope object has a companion object that is an
@@ -797,38 +791,19 @@ class AbstractWrapper(object):
zopeObj.reindex()
return appyObj
- def freeze(self, fieldName):
- '''This method freezes a POD document. TODO: allow to freeze Computed
- fields.'''
- rq = self.request
+ def freeze(self, fieldName, template=None, format='pdf'):
+ '''This method freezes the content of pod field named p_fieldName, for
+ the given p_template (several templates can be given in
+ podField.template), in the given p_format ("pdf" by default).'''
field = self.o.getAppyType(fieldName)
- if field.type != 'Pod': raise 'Cannot freeze non-Pod field.'
- # Set the freeze format
- rq.set('podFormat', field.freezeFormat)
- # Generate the document.
- doc = field.getValue(self.o)
- if isinstance(doc, basestring):
- self.log(FREEZE_ERROR % (field.freezeFormat, field.name, doc),
- type='error')
- if field.freezeFormat == 'odt': raise FREEZE_FATAL_ERROR
- self.log('Trying to freeze the ODT version...')
- # Try to freeze the ODT version of the document, which does not
- # require to call OpenOffice/LibreOffice, so the risk of error is
- # smaller.
- self.request.set('podFormat', 'odt')
- doc = field.getValue(self.o)
- if isinstance(doc, basestring):
- self.log(FREEZE_ERROR % ('odt', field.name, doc), type='error')
- raise FREEZE_FATAL_ERROR
- field.store(self.o, doc)
+ if field.type!= 'Pod': raise Exception('Cannot freeze non-Pod field.')
+ return field.freeze(self, template, format)
- def unFreeze(self, fieldName):
- '''This method un freezes a POD document. TODO: allow to unfreeze
- Computed fields.'''
- rq = self.request
+ def unfreeze(self, fieldName, template=None, format='pdf'):
+ '''This method unfreezes a pod field.'''
field = self.o.getAppyType(fieldName)
- if field.type != 'Pod': raise 'Cannot unFreeze non-Pod field.'
- field.store(self.o, None)
+ if field.type!= 'Pod': raise Exception('Cannot unfreeze non-Pod field.')
+ field.unfreeze(self, template, format)
def delete(self):
'''Deletes myself.'''