appy.gen: added the possibility to freeze, within Pod fields, documents that are normally generated with appy.pod.
This commit is contained in:
parent
a18be357f5
commit
fd896aebdc
173
gen/__init__.py
173
gen/__init__.py
|
@ -1,13 +1,15 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
import re, time, copy, sys, types, os, os.path, mimetypes
|
import re, time, copy, sys, types, os, os.path, mimetypes, StringIO
|
||||||
from appy.shared.utils import Traceback
|
|
||||||
from appy.gen.layout import Table
|
from appy.gen.layout import Table
|
||||||
from appy.gen.layout import defaultFieldLayouts
|
from appy.gen.layout import defaultFieldLayouts
|
||||||
from appy.gen.po import PoMessage
|
from appy.gen.po import PoMessage
|
||||||
from appy.gen.utils import sequenceTypes, GroupDescr, Keywords, FileWrapper, \
|
from appy.gen.utils import sequenceTypes, GroupDescr, Keywords, FileWrapper, \
|
||||||
getClassName, SomeObjects
|
getClassName, SomeObjects
|
||||||
|
import appy.pod
|
||||||
|
from appy.pod.renderer import Renderer
|
||||||
from appy.shared.data import languages
|
from appy.shared.data import languages
|
||||||
|
from appy.shared.utils import Traceback, getOsTempFolder
|
||||||
|
|
||||||
# Default Appy permissions -----------------------------------------------------
|
# Default Appy permissions -----------------------------------------------------
|
||||||
r, w, d = ('read', 'write', 'delete')
|
r, w, d = ('read', 'write', 'delete')
|
||||||
|
@ -1421,6 +1423,28 @@ class File(Type):
|
||||||
width, height, colspan, master, masterValue, focus,
|
width, height, colspan, master, masterValue, focus,
|
||||||
historized, True)
|
historized, True)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def getFileObject(filePath, fileName=None, zope=False):
|
||||||
|
'''Returns a File instance as can be stored in the database or
|
||||||
|
manipulated in code, filled with content from a file on disk,
|
||||||
|
located at p_filePath. If you want to give it a name that is more
|
||||||
|
sexy than the actual basename of filePath, specify it in
|
||||||
|
p_fileName.
|
||||||
|
|
||||||
|
If p_zope is True, it will be the raw Zope object = an instance of
|
||||||
|
OFS.Image.File. Else, it will be a FileWrapper instance from Appy.'''
|
||||||
|
f = file(filePath, 'rb')
|
||||||
|
if not fileName:
|
||||||
|
fileName = os.path.basename(filePath)
|
||||||
|
fileId = 'file.%f' % time.time()
|
||||||
|
import OFS.Image
|
||||||
|
res = OFS.Image.File(fileId, fileName, f)
|
||||||
|
res.filename = fileName
|
||||||
|
res.content_type = mimetypes.guess_type(fileName)[0]
|
||||||
|
f.close()
|
||||||
|
if not zope: res = FileWrapper(res)
|
||||||
|
return res
|
||||||
|
|
||||||
def getValue(self, obj):
|
def getValue(self, obj):
|
||||||
value = Type.getValue(self, obj)
|
value = Type.getValue(self, obj)
|
||||||
if value: value = FileWrapper(value)
|
if value: value = FileWrapper(value)
|
||||||
|
@ -1505,14 +1529,7 @@ class File(Type):
|
||||||
elif isinstance(value, FileWrapper):
|
elif isinstance(value, FileWrapper):
|
||||||
setattr(obj, self.name, value._atFile)
|
setattr(obj, self.name, value._atFile)
|
||||||
elif isinstance(value, basestring):
|
elif isinstance(value, basestring):
|
||||||
f = file(value)
|
setattr(obj, self.name, File.getFileObject(value, zope=True))
|
||||||
fileName = os.path.basename(value)
|
|
||||||
fileId = 'file.%f' % time.time()
|
|
||||||
zopeFile = OFSImageFile(fileId, fileName, f)
|
|
||||||
zopeFile.filename = fileName
|
|
||||||
zopeFile.content_type = mimetypes.guess_type(fileName)[0]
|
|
||||||
setattr(obj, self.name, zopeFile)
|
|
||||||
f.close()
|
|
||||||
elif type(value) in sequenceTypes:
|
elif type(value) in sequenceTypes:
|
||||||
# It should be a 2-tuple or 3-tuple
|
# It should be a 2-tuple or 3-tuple
|
||||||
fileName = None
|
fileName = None
|
||||||
|
@ -1913,6 +1930,9 @@ class Pod(Type):
|
||||||
'''A pod is a field allowing to produce a (PDF, ODT, Word, RTF...) document
|
'''A pod is a field allowing to produce a (PDF, ODT, Word, RTF...) document
|
||||||
from data contained in Appy class and linked objects or anything you
|
from data contained in Appy class and linked objects or anything you
|
||||||
want to put in it. It uses appy.pod.'''
|
want to put in it. It uses appy.pod.'''
|
||||||
|
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.'
|
||||||
def __init__(self, validator=None, index=None, default=None,
|
def __init__(self, validator=None, index=None, default=None,
|
||||||
optional=False, editDefault=False, show='view',
|
optional=False, editDefault=False, show='view',
|
||||||
page='main', group=None, layouts=None, move=0, indexed=False,
|
page='main', group=None, layouts=None, move=0, indexed=False,
|
||||||
|
@ -1920,7 +1940,7 @@ class Pod(Type):
|
||||||
specificWritePermission=False, width=None, height=None,
|
specificWritePermission=False, width=None, height=None,
|
||||||
colspan=1, master=None, masterValue=None, focus=False,
|
colspan=1, master=None, masterValue=None, focus=False,
|
||||||
historized=False, template=None, context=None, action=None,
|
historized=False, template=None, context=None, action=None,
|
||||||
askAction=False, stylesMapping=None):
|
askAction=False, stylesMapping={}, freezeFormat='pdf'):
|
||||||
# The following param stores the path to a POD template
|
# The following param stores the path to a POD template
|
||||||
self.template = template
|
self.template = template
|
||||||
# The context is a dict containing a specific pod context, or a method
|
# The context is a dict containing a specific pod context, or a method
|
||||||
|
@ -1934,6 +1954,8 @@ class Pod(Type):
|
||||||
self.askAction = askAction
|
self.askAction = askAction
|
||||||
# A global styles mapping that would apply to the whole template
|
# A global styles mapping that would apply to the whole template
|
||||||
self.stylesMapping = stylesMapping
|
self.stylesMapping = stylesMapping
|
||||||
|
# Freeze format is by PDF by default
|
||||||
|
self.freezeFormat = freezeFormat
|
||||||
Type.__init__(self, None, (0,1), index, default, optional,
|
Type.__init__(self, None, (0,1), index, default, optional,
|
||||||
False, show, page, group, layouts, move, indexed,
|
False, show, page, group, layouts, move, indexed,
|
||||||
searchable, specificReadPermission,
|
searchable, specificReadPermission,
|
||||||
|
@ -1941,6 +1963,135 @@ class Pod(Type):
|
||||||
masterValue, focus, historized, False)
|
masterValue, focus, historized, False)
|
||||||
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, self.name, None)
|
||||||
|
return isinstance(value, obj.o.getProductConfig().File)
|
||||||
|
|
||||||
|
def getToolInfo(self, obj):
|
||||||
|
'''Gets information related to this field (p_self) that is available in
|
||||||
|
the tool: the POD template and the available output formats. If this
|
||||||
|
field is frozen, available output formats are not available anymore:
|
||||||
|
only the format of the frozen doc is returned.'''
|
||||||
|
tool = obj.tool
|
||||||
|
appyClass = tool.o.getAppyClass(obj.o.meta_type)
|
||||||
|
# Get the output format(s)
|
||||||
|
if self.isFrozen(obj):
|
||||||
|
# The only available format is the one from the frozen document
|
||||||
|
fileName = getattr(obj.o, self.name).filename
|
||||||
|
formats = (os.path.splitext(fileName)[1][1:],)
|
||||||
|
else:
|
||||||
|
# Available formats are those which are selected in the tool.
|
||||||
|
name = tool.getAttributeName('formats', appyClass, self.name)
|
||||||
|
formats = getattr(tool, name)
|
||||||
|
# Get the POD template
|
||||||
|
name = tool.getAttributeName('podTemplate', appyClass, self.name)
|
||||||
|
template = getattr(tool, name)
|
||||||
|
return (template, formats)
|
||||||
|
|
||||||
|
def getValue(self, obj):
|
||||||
|
'''Gets, on_obj, the value conforming to self's type definition. For a
|
||||||
|
Pod field, if a file is stored in the field, it means that the
|
||||||
|
field has been frozen. Else, it means that the value must be
|
||||||
|
retrieved by calling pod to compute the result.'''
|
||||||
|
rq = getattr(obj, 'REQUEST', None)
|
||||||
|
res = getattr(obj, self.name, None)
|
||||||
|
if res and res.size:
|
||||||
|
print 'RETURNING FROZEN DOC'
|
||||||
|
return FileWrapper(res) # Return the frozen file.
|
||||||
|
# If we are here, it means that we must call pod to compute the file.
|
||||||
|
# A Pod field differs from other field types because there can be
|
||||||
|
# several ways to produce the field value (ie: output file format can be
|
||||||
|
# odt, pdf,...; self.action can be executed or not...). We get those
|
||||||
|
# precisions about the way to produce the file from the request object
|
||||||
|
# and from the tool. 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.
|
||||||
|
obj = obj.appy()
|
||||||
|
tool = obj.tool
|
||||||
|
# Get POD template and available formats from the tool.
|
||||||
|
template, availFormats = self.getToolInfo(obj)
|
||||||
|
# Get the output format
|
||||||
|
defaultFormat = 'pdf'
|
||||||
|
if defaultFormat not in availFormats: defaultFormat = availFormats[0]
|
||||||
|
outputFormat = getattr(rq, 'podFormat', defaultFormat)
|
||||||
|
# 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' % (
|
||||||
|
getOsTempFolder(), obj.uid, time.time(), outputFormat)
|
||||||
|
# Define parameters to give to the appy.pod renderer
|
||||||
|
podContext = {'tool': tool, 'user': obj.user, 'self': obj,
|
||||||
|
'now': obj.o.getProductConfig().DateTime(),
|
||||||
|
'projectFolder': tool.getDiskFolder()}
|
||||||
|
# If the POD document is related to a query, get it from the request,
|
||||||
|
# execute it and put the result in the context.
|
||||||
|
isQueryRelated = rq.get('queryData', None)
|
||||||
|
if isQueryRelated:
|
||||||
|
# Retrieve query params from the request
|
||||||
|
cmd = ', '.join(tool.o.queryParamNames)
|
||||||
|
cmd += " = rq['queryData'].split(';')"
|
||||||
|
exec cmd
|
||||||
|
# (re-)execute the query, but without any limit on the number of
|
||||||
|
# results; return Appy objects.
|
||||||
|
objs = tool.o.executeQuery(type_name, searchName=search,
|
||||||
|
sortBy=sortKey, sortOrder=sortOrder, filterKey=filterKey,
|
||||||
|
filterValue=filterValue, maxResults='NO_LIMIT')
|
||||||
|
podContext['objects'] = [o.appy() for o in objs['objects']]
|
||||||
|
if specificContext:
|
||||||
|
podContext.update(specificContext)
|
||||||
|
# Define a potential global styles mapping
|
||||||
|
if callable(self.stylesMapping):
|
||||||
|
stylesMapping = self.callMethod(obj, self.stylesMapping)
|
||||||
|
else:
|
||||||
|
stylesMapping = self.stylesMapping
|
||||||
|
rendererParams = {'template': StringIO.StringIO(template.content),
|
||||||
|
'context': podContext, 'result': tempFileName,
|
||||||
|
'stylesMapping': stylesMapping}
|
||||||
|
if tool.unoEnabledPython:
|
||||||
|
rendererParams['pythonWithUnoPath'] = tool.unoEnabledPython
|
||||||
|
if tool.openOfficePort:
|
||||||
|
rendererParams['ooPort'] = tool.openOfficePort
|
||||||
|
# Launch the renderer
|
||||||
|
try:
|
||||||
|
renderer = Renderer(**rendererParams)
|
||||||
|
renderer.run()
|
||||||
|
except appy.pod.PodError, pe:
|
||||||
|
if not os.path.exists(tempFileName):
|
||||||
|
# In some (most?) cases, when OO returns an error, the result is
|
||||||
|
# nevertheless generated.
|
||||||
|
obj.log(str(pe), type='error')
|
||||||
|
return Pod.POD_ERROR
|
||||||
|
# Give a friendly name for this file
|
||||||
|
fileName = obj.translate(self.labelId)
|
||||||
|
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 FileWrapper instance from the temp file on the filesystem
|
||||||
|
res = File.getFileObject(tempFileName, fileName)
|
||||||
|
# Execute the related action if relevant
|
||||||
|
doAction = getattr(rq, 'askAction', False) in ('True', True)
|
||||||
|
if doAction and self.action: self.action(obj, podContext)
|
||||||
|
# Returns the doc and removes the temp file
|
||||||
|
try:
|
||||||
|
os.remove(tempFileName)
|
||||||
|
except OSError, oe:
|
||||||
|
obj.log(Pod.DELETE_TEMP_DOC_ERROR % str(oe), type='warning')
|
||||||
|
except IOError, ie:
|
||||||
|
obj.log(Pod.DELETE_TEMP_DOC_ERROR % str(ie), type='warning')
|
||||||
|
return res
|
||||||
|
|
||||||
|
def store(self, obj, value):
|
||||||
|
'''Stores (=freezes) a document (in p_value) in the field.'''
|
||||||
|
if isinstance(value, FileWrapper):
|
||||||
|
value = value._atFile
|
||||||
|
setattr(obj, self.name, value)
|
||||||
|
|
||||||
# Workflow-specific types ------------------------------------------------------
|
# Workflow-specific types ------------------------------------------------------
|
||||||
class Role:
|
class Role:
|
||||||
'''Represents a role.'''
|
'''Represents a role.'''
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
import re, os, os.path, time, Cookie, StringIO, types
|
import re, os, os.path, time, Cookie, types
|
||||||
from appy.shared import mimeTypes
|
from appy.shared import mimeTypes
|
||||||
from appy.shared.utils import getOsTempFolder
|
from appy.shared.utils import getOsTempFolder
|
||||||
import appy.pod
|
|
||||||
from appy.pod.renderer import Renderer
|
|
||||||
import appy.gen
|
import appy.gen
|
||||||
from appy.gen import Type, Search, Selection
|
from appy.gen import Type, Search, Selection
|
||||||
from appy.gen.utils import SomeObjects, sequenceTypes, getClassName
|
from appy.gen.utils import SomeObjects, sequenceTypes, getClassName
|
||||||
|
@ -12,9 +10,6 @@ from appy.gen.plone25.wrappers import AbstractWrapper
|
||||||
from appy.gen.plone25.descriptors import ClassDescriptor
|
from appy.gen.plone25.descriptors import ClassDescriptor
|
||||||
|
|
||||||
# Errors -----------------------------------------------------------------------
|
# Errors -----------------------------------------------------------------------
|
||||||
DELETE_TEMP_DOC_ERROR = 'A temporary document could not be removed. %s.'
|
|
||||||
POD_ERROR = 'An error occurred while generating the document. Please ' \
|
|
||||||
'contact the system administrator.'
|
|
||||||
jsMessages = ('no_elem_selected', 'delete_confirm')
|
jsMessages = ('no_elem_selected', 'delete_confirm')
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
@ -32,127 +27,34 @@ class ToolMixin(BaseMixin):
|
||||||
res = '%s%s' % (elems[1], elems[4])
|
res = '%s%s' % (elems[1], elems[4])
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def getPodInfo(self, ploneObj, fieldName):
|
|
||||||
'''Returns POD-related information about Pod field p_fieldName defined
|
|
||||||
on class whose p_ploneObj is an instance of.'''
|
|
||||||
res = {}
|
|
||||||
appyClass = self.getAppyClass(ploneObj.meta_type)
|
|
||||||
appyTool = self.appy()
|
|
||||||
n = appyTool.getAttributeName('formats', appyClass, fieldName)
|
|
||||||
res['formats'] = getattr(appyTool, n)
|
|
||||||
n = appyTool.getAttributeName('podTemplate', appyClass, fieldName)
|
|
||||||
res['template'] = getattr(appyTool, n)
|
|
||||||
appyType = ploneObj.getAppyType(fieldName)
|
|
||||||
res['title'] = self.translate(appyType.labelId)
|
|
||||||
res['context'] = appyType.context
|
|
||||||
res['action'] = appyType.action
|
|
||||||
res['stylesMapping'] = appyType.stylesMapping
|
|
||||||
return res
|
|
||||||
|
|
||||||
def getSiteUrl(self):
|
def getSiteUrl(self):
|
||||||
'''Returns the absolute URL of this site.'''
|
'''Returns the absolute URL of this site.'''
|
||||||
return self.portal_url.getPortalObject().absolute_url()
|
return self.portal_url.getPortalObject().absolute_url()
|
||||||
|
|
||||||
|
def getPodInfo(self, obj, name):
|
||||||
|
'''Gets the available POD formats for Pod field named p_name on
|
||||||
|
p_obj.'''
|
||||||
|
podField = self.getAppyType(name, className=obj.meta_type)
|
||||||
|
return podField.getToolInfo(obj.appy())
|
||||||
|
|
||||||
def generateDocument(self):
|
def generateDocument(self):
|
||||||
'''Generates the document from field-related info. UID of object that
|
'''Generates the document from field-related info. UID of object that
|
||||||
is the template target is given in the request.'''
|
is the template target is given in the request.'''
|
||||||
rq = self.REQUEST
|
rq = self.REQUEST
|
||||||
appyTool = self.appy()
|
# Get the object on which a document must be generated.
|
||||||
# Get the object
|
obj = self.getObject(rq.get('objectUid'), appy=True)
|
||||||
objectUid = rq.get('objectUid')
|
|
||||||
obj = self.uid_catalog(UID=objectUid)[0].getObject()
|
|
||||||
appyObj = obj.appy()
|
|
||||||
# Get information about the document to render.
|
|
||||||
specificPodContext = None
|
|
||||||
fieldName = rq.get('fieldName')
|
fieldName = rq.get('fieldName')
|
||||||
format = rq.get('podFormat')
|
res = getattr(obj, fieldName)
|
||||||
podInfo = self.getPodInfo(obj, fieldName)
|
if isinstance(res, basestring):
|
||||||
template = podInfo['template'].content
|
# An error has occurred, and p_res contains the error message
|
||||||
podTitle = podInfo['title']
|
obj.say(res)
|
||||||
if podInfo['context']:
|
|
||||||
if callable(podInfo['context']):
|
|
||||||
specificPodContext = podInfo['context'](appyObj)
|
|
||||||
else:
|
|
||||||
specificPodContext = podInfo['context']
|
|
||||||
doAction = rq.get('askAction') == 'True'
|
|
||||||
# Temporary file where to generate the result
|
|
||||||
tempFileName = '%s/%s_%f.%s' % (
|
|
||||||
getOsTempFolder(), obj.UID(), time.time(), format)
|
|
||||||
# Define parameters to give to the appy.pod renderer
|
|
||||||
currentUser = self.portal_membership.getAuthenticatedMember()
|
|
||||||
podContext = {'tool': appyTool, 'user': currentUser, 'self': appyObj,
|
|
||||||
'now': self.getProductConfig().DateTime(),
|
|
||||||
'projectFolder': appyTool.getDiskFolder(),
|
|
||||||
}
|
|
||||||
# If the POD document is related to a query, get it from the request,
|
|
||||||
# execute it and put the result in the context.
|
|
||||||
if rq['queryData']:
|
|
||||||
# Retrieve query params from the request
|
|
||||||
cmd = ', '.join(self.queryParamNames)
|
|
||||||
cmd += " = rq['queryData'].split(';')"
|
|
||||||
exec cmd
|
|
||||||
# (re-)execute the query, but without any limit on the number of
|
|
||||||
# results; return Appy objects.
|
|
||||||
objs = self.executeQuery(type_name, searchName=search,
|
|
||||||
sortBy=sortKey, sortOrder=sortOrder, filterKey=filterKey,
|
|
||||||
filterValue=filterValue, maxResults='NO_LIMIT')
|
|
||||||
podContext['objects'] = [o.appy() for o in objs['objects']]
|
|
||||||
if specificPodContext:
|
|
||||||
podContext.update(specificPodContext)
|
|
||||||
# Define a potential global styles mapping
|
|
||||||
stylesMapping = None
|
|
||||||
if podInfo['stylesMapping']:
|
|
||||||
if callable(podInfo['stylesMapping']):
|
|
||||||
stylesMapping = podInfo['stylesMapping'](appyObj)
|
|
||||||
else:
|
|
||||||
stylesMapping = podInfo['stylesMapping']
|
|
||||||
rendererParams = {'template': StringIO.StringIO(template),
|
|
||||||
'context': podContext, 'result': tempFileName}
|
|
||||||
if stylesMapping:
|
|
||||||
rendererParams['stylesMapping'] = stylesMapping
|
|
||||||
if appyTool.unoEnabledPython:
|
|
||||||
rendererParams['pythonWithUnoPath'] = appyTool.unoEnabledPython
|
|
||||||
if appyTool.openOfficePort:
|
|
||||||
rendererParams['ooPort'] = appyTool.openOfficePort
|
|
||||||
# Launch the renderer
|
|
||||||
try:
|
|
||||||
renderer = Renderer(**rendererParams)
|
|
||||||
renderer.run()
|
|
||||||
except appy.pod.PodError, pe:
|
|
||||||
if not os.path.exists(tempFileName):
|
|
||||||
# In some (most?) cases, when OO returns an error, the result is
|
|
||||||
# nevertheless generated.
|
|
||||||
appyTool.log(str(pe), type='error')
|
|
||||||
appyTool.say(POD_ERROR)
|
|
||||||
return self.goto(rq.get('HTTP_REFERER'))
|
return self.goto(rq.get('HTTP_REFERER'))
|
||||||
# Open the temp file on the filesystem
|
# res contains a FileWrapper instance.
|
||||||
f = file(tempFileName, 'rb')
|
response = rq.RESPONSE
|
||||||
res = f.read()
|
response.setHeader('Content-Type', res.mimeType)
|
||||||
# Identify the filename to return
|
response.setHeader('Content-Disposition',
|
||||||
if rq['queryData']:
|
'inline;filename="%s"' % res.name)
|
||||||
# This is a POD for a bunch of objects
|
return res.content
|
||||||
fileName = podTitle
|
|
||||||
else:
|
|
||||||
# This is a POD for a single object: personalize the file name with
|
|
||||||
# the object title.
|
|
||||||
fileName = '%s-%s' % (obj.Title(), podTitle)
|
|
||||||
fileName = appyTool.normalize(fileName)
|
|
||||||
response = obj.REQUEST.RESPONSE
|
|
||||||
response.setHeader('Content-Type', mimeTypes[format])
|
|
||||||
response.setHeader('Content-Disposition', 'inline;filename="%s.%s"' % \
|
|
||||||
(fileName, format))
|
|
||||||
f.close()
|
|
||||||
# Execute the related action if relevant
|
|
||||||
if doAction and podInfo['action']:
|
|
||||||
podInfo['action'](appyObj, podContext)
|
|
||||||
# Returns the doc and removes the temp file
|
|
||||||
try:
|
|
||||||
os.remove(tempFileName)
|
|
||||||
except OSError, oe:
|
|
||||||
appyTool.log(DELETE_TEMP_DOC_ERROR % str(oe), type='warning')
|
|
||||||
except IOError, ie:
|
|
||||||
appyTool.log(DELETE_TEMP_DOC_ERROR % str(ie), type='warning')
|
|
||||||
return res
|
|
||||||
|
|
||||||
def getAttr(self, name):
|
def getAttr(self, name):
|
||||||
'''Gets attribute named p_attrName. Useful because we can't use getattr
|
'''Gets attribute named p_attrName. Useful because we can't use getattr
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
<label tal:attributes="for chekboxId" class="discreet"
|
<label tal:attributes="for chekboxId" class="discreet"
|
||||||
tal:content="python: tool.translate(doLabel)"></label>
|
tal:content="python: tool.translate(doLabel)"></label>
|
||||||
</tal:askAction>
|
</tal:askAction>
|
||||||
<img tal:repeat="podFormat python: tool.getPodInfo(contextObj, name)['formats']"
|
<img tal:repeat="podFormat python: tool.getPodInfo(contextObj, name)[1]"
|
||||||
tal:attributes="src string: $portal_url/skyn/${podFormat}.png;
|
tal:attributes="src string: $portal_url/skyn/${podFormat}.png;
|
||||||
onClick python: 'generatePodDocument(\'%s\',\'%s\',\'%s\',\'%s\')' % (contextObj.UID(), name, podFormat, tool.getQueryInfo());
|
onClick python: 'generatePodDocument(\'%s\',\'%s\',\'%s\',\'%s\')' % (contextObj.UID(), name, podFormat, tool.getQueryInfo());
|
||||||
title podFormat/capitalize"
|
title podFormat/capitalize"
|
||||||
|
|
|
@ -14,6 +14,10 @@ from appy.shared.csv_parser import CsvMarshaller
|
||||||
WRONG_FILE_TUPLE = 'This is not the way to set a file. You can specify a ' \
|
WRONG_FILE_TUPLE = 'This is not the way to set a file. You can specify a ' \
|
||||||
'2-tuple (fileName, fileContent) or a 3-tuple (fileName, fileContent, ' \
|
'2-tuple (fileName, fileContent) or a 3-tuple (fileName, fileContent, ' \
|
||||||
'mimeType).'
|
'mimeType).'
|
||||||
|
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:
|
class AbstractWrapper:
|
||||||
|
@ -205,6 +209,41 @@ class AbstractWrapper:
|
||||||
ploneObj.reindexObject()
|
ploneObj.reindexObject()
|
||||||
return appyObj
|
return appyObj
|
||||||
|
|
||||||
|
def freeze(self, fieldName, doAction=False):
|
||||||
|
'''This method freezes a POD document. TODO: allow to freeze Computed
|
||||||
|
fields.'''
|
||||||
|
rq = self.request
|
||||||
|
field = self.o.getAppyType(fieldName)
|
||||||
|
if field.type != 'Pod': raise 'Cannot freeze non-Pod field.'
|
||||||
|
# Perform the related action if required.
|
||||||
|
if doAction: self.request.set('askAction', True)
|
||||||
|
# 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)
|
||||||
|
|
||||||
|
def unFreeze(self, fieldName):
|
||||||
|
'''This method un freezes a POD document. TODO: allow to unfreeze
|
||||||
|
Computed fields.'''
|
||||||
|
rq = self.request
|
||||||
|
field = self.o.getAppyType(fieldName)
|
||||||
|
if field.type != 'Pod': raise 'Cannot unFreeze non-Pod field.'
|
||||||
|
field.store(self.o, None)
|
||||||
|
|
||||||
def delete(self):
|
def delete(self):
|
||||||
'''Deletes myself.'''
|
'''Deletes myself.'''
|
||||||
self.o.delete()
|
self.o.delete()
|
||||||
|
|
Loading…
Reference in a new issue