[gen] Pod field: allow to upload a replacement file for a frozen pod document.

This commit is contained in:
Gaetan Delannay 2014-03-25 12:05:07 +01:00
parent d0749cc365
commit e969bbf362
12 changed files with 158 additions and 79 deletions

View file

@ -58,7 +58,8 @@ class Pod(Field):
<table cellpadding="0" cellspacing="0" class="podTable">
<tr>
<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)">
<!-- A clickable icon if no freeze action is allowed -->
<x if="not freezeAllowed">:field.pxIcon</x>
@ -249,25 +250,35 @@ class Pod(Field):
return res
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
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, 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).'''
file, either from params, or from default values.
* p_template is the specific template, among self.template, that must
be used as base for generating the document;
* p_format is the output format of the resulting document;
* 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()
rq = obj.request
template = template or rq.get('template') or self.template[0]
format = format or rq.get('podFormat') or 'odt'
template = template or self.template[0]
format = format or 'odt'
# 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)
# 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)
if frozen:
fileName = self.getDownloadName(obj, template, format, False)
@ -293,13 +304,12 @@ class Pod(Field):
podContext = {'tool': tool, 'user': obj.user, 'self': obj, 'field':self,
'now': obj.o.getProductConfig().DateTime(),
'_': obj.translate, 'projectFolder': diskFolder}
# 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
# If the pod document is related to a query, re-trigger it and put the
# result in the pod context.
if queryData:
# Retrieve query params
cmd = ', '.join(tool.o.queryParamNames)
cmd += " = rq['queryData'].split(';')"
cmd += " = queryData.split(';')"
exec cmd
# (re-)execute the query, but without any limit on the number of
# results; return Appy objects.
@ -310,11 +320,7 @@ class Pod(Field):
# Add the field-specific context if present.
if specificContext:
podContext.update(specificContext)
# If a custom param comes from the request, add it to the context. A
# 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 a custom param comes from the request, add it to the context.
if customParams:
paramsDict = eval(customParams)
podContext.update(paramsDict)
@ -342,7 +348,7 @@ class Pod(Field):
obj.log(str(pe).strip(), type='error')
return Pod.POD_ERROR
# 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.
return FileInfo(result, inDb=False, uploadName=fileName)
@ -364,13 +370,17 @@ class Pod(Field):
if os.path.exists(res): return res
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
p_format. If p_noSecurity is True, the security check, based on
self.freezeTemplate, is bypassed. if freezeOdtOnError is True and
format is not "odt", if the freezing fails we try to freeze the odt
version, which is more robust because it does not require calling
LibreOffice.'''
self.freezeTemplate, is bypassed. If no p_upload file is specified,
we re-compute a pod document on-the-fly and we freeze this document.
Else, we store the uploaded file.
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.
if not noSecurity and \
(format not in self.getFreezeFormats(obj, template)):
@ -381,12 +391,16 @@ class Pod(Field):
fileName = self.getFreezeName(template, format)
result = os.path.join(dbFolder, folder, fileName)
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.
doc = self.getValue(obj, template=template, format=format,result=result)
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')
obj.log(self.FREEZE_ERROR % (format, self.name, doc),
type='error')
if not freezeOdtOnError or (format == 'odt'):
raise Exception(self.FREEZE_FATAL_ERROR)
obj.log('Trying to freeze the ODT version...')
@ -402,6 +416,12 @@ class Pod(Field):
self.log(self.FREEZE_ERROR % ('odt', self.name, doc),
type='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
def unfreeze(self, obj, template=None, format='pdf', noSecurity=True):
@ -435,4 +455,53 @@ class Pod(Field):
if frozen:
res += ' (%s)' % obj.translate('frozen')
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'))
# ------------------------------------------------------------------------------

View file

@ -113,31 +113,7 @@ class ToolMixin(BaseMixin):
rq = self.REQUEST
# Get the object that is the target of this action.
obj = self.getObject(rq.get('objectUid'), appy=True)
fieldName = rq.get('fieldName')
# 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'))
return obj.getField(rq.get('fieldName')).onUiRequest(obj, rq)
def getAppName(self):
'''Returns the name of the application.'''

View file

@ -295,6 +295,10 @@ msgstr ""
msgid "uploadField"
msgstr ""
#. Default: "Please upload a file of the same type."
msgid "upload_invalid"
msgstr ""
#. Default: "Welcome to this Appy-powered site."
msgid "front_page_text"
msgstr ""

View file

@ -295,6 +295,10 @@ msgstr ""
msgid "uploadField"
msgstr ""
#. Default: "Please upload a file of the same type."
msgid "upload_invalid"
msgstr ""
#. Default: "Welcome to this Appy-powered site."
msgid "front_page_text"
msgstr ""

View file

@ -295,6 +295,10 @@ msgstr ""
msgid "uploadField"
msgstr ""
#. Default: "Please upload a file of the same type."
msgid "upload_invalid"
msgstr ""
#. Default: "Welcome to this Appy-powered site."
msgid "front_page_text"
msgstr ""

View file

@ -296,6 +296,10 @@ msgstr "Unfreeze"
msgid "uploadField"
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."
msgid "front_page_text"
msgstr "Welcome to this Appy-powered site."

View file

@ -295,6 +295,10 @@ msgstr ""
msgid "uploadField"
msgstr ""
#. Default: "Please upload a file of the same type."
msgid "upload_invalid"
msgstr ""
#. Default: "Welcome to this Appy-powered site."
msgid "front_page_text"
msgstr ""

View file

@ -296,6 +296,10 @@ msgstr "Dégeler"
msgid "uploadField"
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."
msgid "front_page_text"
msgstr "Bienvenue sur ce site fabriqué avec <a href=\"http://appyframework.org\" target=\"_blank\">Appy</a>"

View file

@ -295,6 +295,10 @@ msgstr ""
msgid "uploadField"
msgstr ""
#. Default: "Please upload a file of the same type."
msgid "upload_invalid"
msgstr ""
#. Default: "Welcome to this Appy-powered site."
msgid "front_page_text"
msgstr ""

View file

@ -295,6 +295,10 @@ msgstr ""
msgid "uploadField"
msgstr ""
#. Default: "Please upload a file of the same type."
msgid "upload_invalid"
msgstr ""
#. Default: "Welcome to this Appy-powered site."
msgid "front_page_text"
msgstr ""

View file

@ -545,13 +545,14 @@ function freezePod(uid, fieldName, template, podFormat, action) {
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) {
var f = document.getElementById('uploadForm');
f.objectUid.value = uid;
f.fieldName.value = fieldName;
f.template.value = template;
f.podFormat.value = podFormat;
f.uploadedFile.value = null;
openPopup('uploadPopup');
}

View file

@ -126,11 +126,12 @@ class AbstractWrapper(object):
<!-- Popup for uploading a file in a pod field -->
<div id="uploadPopup" class="popup" align="center">
<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="fieldName"/>
<input type="hidden" name="template"/>
<input type="hidden" name="podFormat"/>
<input type="hidden" name="action" value="upload"/>
<input type="file" name="uploadedFile"/><br/><br/>
<input type="submit" value=":_('object_save')"/>
<input type="button" onclick="closePopup('uploadPopup')"