[gen] Pod field: allow to upload a replacement file for a frozen pod document.
This commit is contained in:
parent
d0749cc365
commit
e969bbf362
133
fields/pod.py
133
fields/pod.py
|
@ -58,7 +58,8 @@ class Pod(Field):
|
||||||
<table cellpadding="0" cellspacing="0" class="podTable">
|
<table cellpadding="0" cellspacing="0" class="podTable">
|
||||||
<tr>
|
<tr>
|
||||||
<td for="fmt in info.formats"
|
<td for="fmt in info.formats"
|
||||||
var2="freezeAllowed=fmt in info.freezeFormats;
|
var2="freezeAllowed=(fmt in info.freezeFormats) and \
|
||||||
|
(field.show != 'result');
|
||||||
frozen=field.isFrozen(obj, info.template, fmt)">
|
frozen=field.isFrozen(obj, info.template, fmt)">
|
||||||
<!-- A clickable icon if no freeze action is allowed -->
|
<!-- A clickable icon if no freeze action is allowed -->
|
||||||
<x if="not freezeAllowed">:field.pxIcon</x>
|
<x if="not freezeAllowed">:field.pxIcon</x>
|
||||||
|
@ -249,25 +250,35 @@ class Pod(Field):
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def getValue(self, obj, template=None, format=None, result=None,
|
def getValue(self, obj, template=None, format=None, result=None,
|
||||||
noSecurity=False):
|
queryData=None, customParams=None, noSecurity=False):
|
||||||
'''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, either:
|
file, either from params, or from default values.
|
||||||
- from params p_template and p_format;
|
* p_template is the specific template, among self.template, that must
|
||||||
- from the request object;
|
be used as base for generating the document;
|
||||||
- from default values (the request object may not be present, ie,
|
* p_format is the output format of the resulting document;
|
||||||
when Zope runs in test mode).'''
|
* p_result, if given, must be the absolute path of the document that
|
||||||
|
will be computed by pod. If not given, pod will produce a doc in
|
||||||
|
the OS temp folder;
|
||||||
|
* if the pod document is related to a query, the query parameters
|
||||||
|
needed to re-trigger the query are given in p_queryData;
|
||||||
|
* p_customParams may be specified. Every custom param must have form
|
||||||
|
"name:value". Custom params override any other value available in
|
||||||
|
the context, including values from the field-specific context.
|
||||||
|
'''
|
||||||
obj = obj.appy()
|
obj = obj.appy()
|
||||||
rq = obj.request
|
template = template or self.template[0]
|
||||||
template = template or rq.get('template') or self.template[0]
|
format = format or 'odt'
|
||||||
format = format or rq.get('podFormat') or 'odt'
|
|
||||||
# Security check.
|
# Security check.
|
||||||
if not noSecurity and not self.showTemplate(obj, template):
|
if not noSecurity and not queryData and \
|
||||||
|
not self.showTemplate(obj, template):
|
||||||
raise Exception(self.UNAUTHORIZED)
|
raise Exception(self.UNAUTHORIZED)
|
||||||
# Return the frozen document if frozen.
|
# Return the possibly frozen document (not applicable for query-related
|
||||||
|
# pods).
|
||||||
|
if not queryData:
|
||||||
frozen = self.isFrozen(obj, template, format)
|
frozen = self.isFrozen(obj, template, format)
|
||||||
if frozen:
|
if frozen:
|
||||||
fileName = self.getDownloadName(obj, template, format, False)
|
fileName = self.getDownloadName(obj, template, format, False)
|
||||||
|
@ -293,13 +304,12 @@ class Pod(Field):
|
||||||
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(),
|
||||||
'_': obj.translate, 'projectFolder': diskFolder}
|
'_': obj.translate, 'projectFolder': diskFolder}
|
||||||
# If the POD document is related to a query, get it from the request,
|
# If the pod document is related to a query, re-trigger it and put the
|
||||||
# execute it and put the result in the context.
|
# result in the pod context.
|
||||||
isQueryRelated = rq.get('queryData', None)
|
if queryData:
|
||||||
if isQueryRelated:
|
# Retrieve query params
|
||||||
# Retrieve query params from the request
|
|
||||||
cmd = ', '.join(tool.o.queryParamNames)
|
cmd = ', '.join(tool.o.queryParamNames)
|
||||||
cmd += " = rq['queryData'].split(';')"
|
cmd += " = queryData.split(';')"
|
||||||
exec cmd
|
exec cmd
|
||||||
# (re-)execute the query, but without any limit on the number of
|
# (re-)execute the query, but without any limit on the number of
|
||||||
# results; return Appy objects.
|
# results; return Appy objects.
|
||||||
|
@ -310,11 +320,7 @@ class Pod(Field):
|
||||||
# Add the field-specific context if present.
|
# Add the field-specific context if present.
|
||||||
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.
|
||||||
# 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)
|
|
||||||
if customParams:
|
if customParams:
|
||||||
paramsDict = eval(customParams)
|
paramsDict = eval(customParams)
|
||||||
podContext.update(paramsDict)
|
podContext.update(paramsDict)
|
||||||
|
@ -342,7 +348,7 @@ class Pod(Field):
|
||||||
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.getDownloadName(obj, template, format, isQueryRelated)
|
fileName = self.getDownloadName(obj, template, format, queryData)
|
||||||
# Get a FileInfo instance to manipulate the file on the filesystem.
|
# Get a FileInfo instance to manipulate the file on the filesystem.
|
||||||
return FileInfo(result, inDb=False, uploadName=fileName)
|
return FileInfo(result, inDb=False, uploadName=fileName)
|
||||||
|
|
||||||
|
@ -364,13 +370,17 @@ class Pod(Field):
|
||||||
if os.path.exists(res): return res
|
if os.path.exists(res): return res
|
||||||
|
|
||||||
def freeze(self, obj, template=None, format='pdf', noSecurity=True,
|
def freeze(self, obj, template=None, format='pdf', noSecurity=True,
|
||||||
freezeOdtOnError=True):
|
upload=None, freezeOdtOnError=True):
|
||||||
'''Freezes, on p_obj, a document for this pod field, for p_template in
|
'''Freezes, on p_obj, a document for this pod field, for p_template in
|
||||||
p_format. If p_noSecurity is True, the security check, based on
|
p_format. If p_noSecurity is True, the security check, based on
|
||||||
self.freezeTemplate, is bypassed. if freezeOdtOnError is True and
|
self.freezeTemplate, is bypassed. If no p_upload file is specified,
|
||||||
format is not "odt", if the freezing fails we try to freeze the odt
|
we re-compute a pod document on-the-fly and we freeze this document.
|
||||||
version, which is more robust because it does not require calling
|
Else, we store the uploaded file.
|
||||||
LibreOffice.'''
|
|
||||||
|
If p_freezeOdtOnError is True and format is not "odt" (has only sense
|
||||||
|
when no p_upload file is specified), if the freezing fails we try to
|
||||||
|
freeze the odt version, which is more robust because it does not
|
||||||
|
require calling LibreOffice.'''
|
||||||
# Security check.
|
# Security check.
|
||||||
if not noSecurity and \
|
if not noSecurity and \
|
||||||
(format not in self.getFreezeFormats(obj, template)):
|
(format not in self.getFreezeFormats(obj, template)):
|
||||||
|
@ -381,12 +391,16 @@ class Pod(Field):
|
||||||
fileName = self.getFreezeName(template, format)
|
fileName = self.getFreezeName(template, format)
|
||||||
result = os.path.join(dbFolder, folder, fileName)
|
result = os.path.join(dbFolder, folder, fileName)
|
||||||
if os.path.exists(result):
|
if os.path.exists(result):
|
||||||
obj.log('Freeze: overwriting %s...' % result)
|
prefix = upload and 'Freeze (upload)' or 'Freeze'
|
||||||
|
obj.log('%s: overwriting %s...' % (prefix, result))
|
||||||
|
if not upload:
|
||||||
# Generate the document.
|
# Generate the document.
|
||||||
doc = self.getValue(obj, template=template, format=format,result=result)
|
doc = self.getValue(obj, template=template, format=format,
|
||||||
|
result=result)
|
||||||
if isinstance(doc, basestring):
|
if isinstance(doc, basestring):
|
||||||
# An error occurred, the document was not generated.
|
# An error occurred, the document was not generated.
|
||||||
obj.log(self.FREEZE_ERROR % (format, self.name, doc), type='error')
|
obj.log(self.FREEZE_ERROR % (format, self.name, doc),
|
||||||
|
type='error')
|
||||||
if not freezeOdtOnError or (format == 'odt'):
|
if not freezeOdtOnError or (format == 'odt'):
|
||||||
raise Exception(self.FREEZE_FATAL_ERROR)
|
raise Exception(self.FREEZE_FATAL_ERROR)
|
||||||
obj.log('Trying to freeze the ODT version...')
|
obj.log('Trying to freeze the ODT version...')
|
||||||
|
@ -402,6 +416,12 @@ class Pod(Field):
|
||||||
self.log(self.FREEZE_ERROR % ('odt', self.name, doc),
|
self.log(self.FREEZE_ERROR % ('odt', self.name, doc),
|
||||||
type='error')
|
type='error')
|
||||||
raise Exception(self.FREEZE_FATAL_ERROR)
|
raise Exception(self.FREEZE_FATAL_ERROR)
|
||||||
|
else:
|
||||||
|
# Store the uploaded file in the database.
|
||||||
|
f = file(result, 'wb')
|
||||||
|
doc = FileInfo(result, inDb=False)
|
||||||
|
doc.replicateFile(upload, f)
|
||||||
|
f.close()
|
||||||
return doc
|
return doc
|
||||||
|
|
||||||
def unfreeze(self, obj, template=None, format='pdf', noSecurity=True):
|
def unfreeze(self, obj, template=None, format='pdf', noSecurity=True):
|
||||||
|
@ -435,4 +455,53 @@ class Pod(Field):
|
||||||
if frozen:
|
if frozen:
|
||||||
res += ' (%s)' % obj.translate('frozen')
|
res += ' (%s)' % obj.translate('frozen')
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
def onUiRequest(self, obj, rq):
|
||||||
|
'''This method is called when an action tied to this pod field
|
||||||
|
(generate, freeze, upload...) is triggered from the user
|
||||||
|
interface.'''
|
||||||
|
# What is the action to perform?
|
||||||
|
action = rq.get('action', 'generate')
|
||||||
|
# Security check.
|
||||||
|
obj.o.allows('read', raiseError=True)
|
||||||
|
# Perform the requested action.
|
||||||
|
tool = obj.tool.o
|
||||||
|
template = rq.get('template')
|
||||||
|
format = rq.get('podFormat')
|
||||||
|
if action == 'generate':
|
||||||
|
# Generate a (or get a frozen) document.
|
||||||
|
res = self.getValue(obj, template=template, format=format,
|
||||||
|
queryData=rq.get('queryData'),
|
||||||
|
customParams=rq.get('customParams'))
|
||||||
|
if isinstance(res, basestring):
|
||||||
|
# An error has occurred, and p_res contains the error message.
|
||||||
|
obj.say(res)
|
||||||
|
return tool.goto(rq.get('HTTP_REFERER'))
|
||||||
|
# res contains a FileInfo instance.
|
||||||
|
res.writeResponse(rq.RESPONSE)
|
||||||
|
return
|
||||||
|
# Performing any other action requires write access to p_obj.
|
||||||
|
obj.o.allows('write', raiseError=True)
|
||||||
|
msg = 'action_done'
|
||||||
|
if action == 'freeze':
|
||||||
|
# (Re-)freeze a document in the database.
|
||||||
|
self.freeze(obj, template, format, noSecurity=False,
|
||||||
|
freezeOdtOnError=False)
|
||||||
|
elif action == 'unfreeze':
|
||||||
|
# Unfreeze a document in the database.
|
||||||
|
self.unfreeze(obj, template, format, noSecurity=False)
|
||||||
|
elif action == 'upload':
|
||||||
|
# Ensure a file from the correct type has been uploaded.
|
||||||
|
upload = rq.get('uploadedFile')
|
||||||
|
if not upload or not upload.filename or \
|
||||||
|
not upload.filename.endswith('.%s' % format):
|
||||||
|
# A wrong file has been uploaded (or no file at all)
|
||||||
|
msg = 'upload_invalid'
|
||||||
|
else:
|
||||||
|
# Store the uploaded file in the database.
|
||||||
|
self.freeze(obj, template, format, noSecurity=False,
|
||||||
|
upload=upload)
|
||||||
|
# Return a message to the user interface.
|
||||||
|
obj.say(obj.translate(msg))
|
||||||
|
return tool.goto(rq.get('HTTP_REFERER'))
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
|
@ -113,31 +113,7 @@ class ToolMixin(BaseMixin):
|
||||||
rq = self.REQUEST
|
rq = self.REQUEST
|
||||||
# Get the object that is the target of this action.
|
# Get the object that is the target of this action.
|
||||||
obj = self.getObject(rq.get('objectUid'), appy=True)
|
obj = self.getObject(rq.get('objectUid'), appy=True)
|
||||||
fieldName = rq.get('fieldName')
|
return obj.getField(rq.get('fieldName')).onUiRequest(obj, rq)
|
||||||
# What is the action to perform?
|
|
||||||
action = rq.get('action', 'generate')
|
|
||||||
if action == 'generate':
|
|
||||||
# Generate a (or get a frozen) 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
|
|
||||||
obj.say(res)
|
|
||||||
return self.goto(rq.get('HTTP_REFERER'))
|
|
||||||
# res contains a FileInfo instance.
|
|
||||||
res.writeResponse(rq.RESPONSE)
|
|
||||||
elif action == 'freeze':
|
|
||||||
# (Re-)freeze a document in the database.
|
|
||||||
res = obj.freeze(fieldName, rq.get('template'), rq.get('podFormat'),
|
|
||||||
noSecurity=False, freezeOdtOnError=False)
|
|
||||||
obj.say(obj.translate('action_done'))
|
|
||||||
return self.goto(rq.get('HTTP_REFERER'))
|
|
||||||
elif action == 'unfreeze':
|
|
||||||
# Unfreeze a document in the database.
|
|
||||||
obj.unfreeze(fieldName, rq.get('template'), rq.get('podFormat'),
|
|
||||||
noSecurity=False)
|
|
||||||
obj.say(obj.translate('action_done'))
|
|
||||||
return self.goto(rq.get('HTTP_REFERER'))
|
|
||||||
|
|
||||||
def getAppName(self):
|
def getAppName(self):
|
||||||
'''Returns the name of the application.'''
|
'''Returns the name of the application.'''
|
||||||
|
|
|
@ -295,6 +295,10 @@ msgstr ""
|
||||||
msgid "uploadField"
|
msgid "uploadField"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#. Default: "Please upload a file of the same type."
|
||||||
|
msgid "upload_invalid"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#. Default: "Welcome to this Appy-powered site."
|
#. Default: "Welcome to this Appy-powered site."
|
||||||
msgid "front_page_text"
|
msgid "front_page_text"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
|
@ -295,6 +295,10 @@ msgstr ""
|
||||||
msgid "uploadField"
|
msgid "uploadField"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#. Default: "Please upload a file of the same type."
|
||||||
|
msgid "upload_invalid"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#. Default: "Welcome to this Appy-powered site."
|
#. Default: "Welcome to this Appy-powered site."
|
||||||
msgid "front_page_text"
|
msgid "front_page_text"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
|
@ -295,6 +295,10 @@ msgstr ""
|
||||||
msgid "uploadField"
|
msgid "uploadField"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#. Default: "Please upload a file of the same type."
|
||||||
|
msgid "upload_invalid"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#. Default: "Welcome to this Appy-powered site."
|
#. Default: "Welcome to this Appy-powered site."
|
||||||
msgid "front_page_text"
|
msgid "front_page_text"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
|
@ -296,6 +296,10 @@ msgstr "Unfreeze"
|
||||||
msgid "uploadField"
|
msgid "uploadField"
|
||||||
msgstr "Upload a new file"
|
msgstr "Upload a new file"
|
||||||
|
|
||||||
|
#. Default: "Please upload a file of the same type."
|
||||||
|
msgid "upload_invalid"
|
||||||
|
msgstr "Please upload a file of the same type."
|
||||||
|
|
||||||
#. Default: "Welcome to this Appy-powered site."
|
#. Default: "Welcome to this Appy-powered site."
|
||||||
msgid "front_page_text"
|
msgid "front_page_text"
|
||||||
msgstr "Welcome to this Appy-powered site."
|
msgstr "Welcome to this Appy-powered site."
|
||||||
|
|
|
@ -295,6 +295,10 @@ msgstr ""
|
||||||
msgid "uploadField"
|
msgid "uploadField"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#. Default: "Please upload a file of the same type."
|
||||||
|
msgid "upload_invalid"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#. Default: "Welcome to this Appy-powered site."
|
#. Default: "Welcome to this Appy-powered site."
|
||||||
msgid "front_page_text"
|
msgid "front_page_text"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
|
@ -296,6 +296,10 @@ msgstr "Dégeler"
|
||||||
msgid "uploadField"
|
msgid "uploadField"
|
||||||
msgstr "Écraser par..."
|
msgstr "Écraser par..."
|
||||||
|
|
||||||
|
#. Default: "Please upload a file of the same type."
|
||||||
|
msgid "upload_invalid"
|
||||||
|
msgstr "Veuillez uploader un fichier du même type."
|
||||||
|
|
||||||
#. Default: "Welcome to this Appy-powered site."
|
#. Default: "Welcome to this Appy-powered site."
|
||||||
msgid "front_page_text"
|
msgid "front_page_text"
|
||||||
msgstr "Bienvenue sur ce site fabriqué avec <a href=\"http://appyframework.org\" target=\"_blank\">Appy</a>"
|
msgstr "Bienvenue sur ce site fabriqué avec <a href=\"http://appyframework.org\" target=\"_blank\">Appy</a>"
|
||||||
|
|
|
@ -295,6 +295,10 @@ msgstr ""
|
||||||
msgid "uploadField"
|
msgid "uploadField"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#. Default: "Please upload a file of the same type."
|
||||||
|
msgid "upload_invalid"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#. Default: "Welcome to this Appy-powered site."
|
#. Default: "Welcome to this Appy-powered site."
|
||||||
msgid "front_page_text"
|
msgid "front_page_text"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
|
@ -295,6 +295,10 @@ msgstr ""
|
||||||
msgid "uploadField"
|
msgid "uploadField"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#. Default: "Please upload a file of the same type."
|
||||||
|
msgid "upload_invalid"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#. Default: "Welcome to this Appy-powered site."
|
#. Default: "Welcome to this Appy-powered site."
|
||||||
msgid "front_page_text"
|
msgid "front_page_text"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
|
@ -545,13 +545,14 @@ function freezePod(uid, fieldName, template, podFormat, action) {
|
||||||
askConfirm('form', 'podForm', action_confirm);
|
askConfirm('form', 'podForm', action_confirm);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function that allows to upload a file for freezing it in a od field.
|
// Function that allows to upload a file for freezing it in a pod field.
|
||||||
function uploadPod(uid, fieldName, template, podFormat) {
|
function uploadPod(uid, fieldName, template, podFormat) {
|
||||||
var f = document.getElementById('uploadForm');
|
var f = document.getElementById('uploadForm');
|
||||||
f.objectUid.value = uid;
|
f.objectUid.value = uid;
|
||||||
f.fieldName.value = fieldName;
|
f.fieldName.value = fieldName;
|
||||||
f.template.value = template;
|
f.template.value = template;
|
||||||
f.podFormat.value = podFormat;
|
f.podFormat.value = podFormat;
|
||||||
|
f.uploadedFile.value = null;
|
||||||
openPopup('uploadPopup');
|
openPopup('uploadPopup');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -126,11 +126,12 @@ class AbstractWrapper(object):
|
||||||
<!-- Popup for uploading a file in a pod field -->
|
<!-- Popup for uploading a file in a pod field -->
|
||||||
<div id="uploadPopup" class="popup" align="center">
|
<div id="uploadPopup" class="popup" align="center">
|
||||||
<form id="uploadForm" name="uploadForm" enctype="multipart/form-data"
|
<form id="uploadForm" name="uploadForm" enctype="multipart/form-data"
|
||||||
method="post" action=":ztool.absolute_url() + '/uploadPod'">
|
method="post" action=":ztool.absolute_url() + '/doPod'">
|
||||||
<input type="hidden" name="objectUid"/>
|
<input type="hidden" name="objectUid"/>
|
||||||
<input type="hidden" name="fieldName"/>
|
<input type="hidden" name="fieldName"/>
|
||||||
<input type="hidden" name="template"/>
|
<input type="hidden" name="template"/>
|
||||||
<input type="hidden" name="podFormat"/>
|
<input type="hidden" name="podFormat"/>
|
||||||
|
<input type="hidden" name="action" value="upload"/>
|
||||||
<input type="file" name="uploadedFile"/><br/><br/>
|
<input type="file" name="uploadedFile"/><br/><br/>
|
||||||
<input type="submit" value=":_('object_save')"/>
|
<input type="submit" value=":_('object_save')"/>
|
||||||
<input type="button" onclick="closePopup('uploadPopup')"
|
<input type="button" onclick="closePopup('uploadPopup')"
|
||||||
|
|
Loading…
Reference in a new issue