[gen] Pod field can now freeze and unfreeze any of its multiple templates.
This commit is contained in:
parent
ecc3a8c39b
commit
0834356487
149
fields/pod.py
149
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('''
|
||||
<table cellpadding="0" cellspacing="0">
|
||||
|
@ -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)
|
||||
# ------------------------------------------------------------------------------
|
||||
|
|
|
@ -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.'''
|
||||
|
|
|
@ -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.'''
|
||||
|
|
Loading…
Reference in a new issue