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