Added the possibility to define POD templates for any search result (Pod field with param view='search'), bugfix while getting default value for a Ref field, added Computed fields that computes a ZPT macro given as a string to param 'method', added the possibility to define a global style mapping for every Pod field, stopped to generate a field-specific set of i18n labels for pod output formats, carry portal_status_message even through page redirections, added 'deprecatedAddRemove' tags in generated configure.zcml, onEdit can now return a customized message, added possibility to normalize strings for other usages than 'fileName', in appy.shared.utils.normalizeString (for alpha and alphanum usages)
This commit is contained in:
parent
38f71be89a
commit
90553381a3
18 changed files with 250 additions and 59 deletions
|
@ -45,6 +45,7 @@ class ToolMixin(BaseMixin):
|
|||
res['title'] = self.translate(appyType.labelId)
|
||||
res['context'] = appyType.context
|
||||
res['action'] = appyType.action
|
||||
res['stylesMapping'] = appyType.stylesMapping
|
||||
return res
|
||||
|
||||
def getSiteUrl(self):
|
||||
|
@ -68,7 +69,7 @@ class ToolMixin(BaseMixin):
|
|||
template = podInfo['template'].content
|
||||
podTitle = podInfo['title']
|
||||
if podInfo['context']:
|
||||
if type(podInfo['context']) == types.FunctionType:
|
||||
if callable(podInfo['context']):
|
||||
specificPodContext = podInfo['context'](appyObj)
|
||||
else:
|
||||
specificPodContext = podInfo['context']
|
||||
|
@ -76,16 +77,38 @@ class ToolMixin(BaseMixin):
|
|||
# Temporary file where to generate the result
|
||||
tempFileName = '%s/%s_%f.%s' % (
|
||||
getOsTempFolder(), obj.UID(), time.time(), format)
|
||||
# Define parameters to pass to the appy.pod renderer
|
||||
# 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:
|
||||
|
@ -105,7 +128,13 @@ class ToolMixin(BaseMixin):
|
|||
f = file(tempFileName, 'rb')
|
||||
res = f.read()
|
||||
# Identify the filename to return
|
||||
fileName = u'%s-%s' % (obj.Title().decode('utf-8'), podTitle)
|
||||
if rq['queryData']:
|
||||
# This is a POD for a bunch of objects
|
||||
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])
|
||||
|
@ -189,6 +218,19 @@ class ToolMixin(BaseMixin):
|
|||
return {'fields': fields, 'nbOfColumns': nbOfColumns,
|
||||
'fieldDicts': fieldDicts}
|
||||
|
||||
queryParamNames = ('type_name', 'search', 'sortKey', 'sortOrder',
|
||||
'filterKey', 'filterValue')
|
||||
def getQueryInfo(self):
|
||||
'''If we are showing search results, this method encodes in a string all
|
||||
the params in the request that are required for re-triggering the
|
||||
search.'''
|
||||
rq = self.REQUEST
|
||||
res = ''
|
||||
if rq.has_key('search'):
|
||||
res = ';'.join([rq.get(key,'').replace(';','') \
|
||||
for key in self.queryParamNames])
|
||||
return res
|
||||
|
||||
def getImportElements(self, contentType):
|
||||
'''Returns the list of elements that can be imported from p_path for
|
||||
p_contentType.'''
|
||||
|
@ -863,4 +905,10 @@ class ToolMixin(BaseMixin):
|
|||
os.remove(fileName)
|
||||
return content
|
||||
return 'File does not exist'
|
||||
|
||||
def getResultPodFields(self, contentType):
|
||||
'''Finds, among fields defined on p_contentType, which ones are Pod
|
||||
fields that need to be shown on a page displaying query results.'''
|
||||
return [f.__dict__ for f in self.getAllAppyTypes(contentType) \
|
||||
if (f.type == 'Pod') and (f.show == 'result')]
|
||||
# ------------------------------------------------------------------------------
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
- mixins/ToolMixin is mixed in with the generated application Tool class.'''
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
import os, os.path, sys, types, mimetypes
|
||||
import os, os.path, sys, types, mimetypes, urllib
|
||||
import appy.gen
|
||||
from appy.gen import Type, String, Selection, Role
|
||||
from appy.gen.utils import *
|
||||
|
@ -67,13 +67,15 @@ class BaseMixin:
|
|||
initiator.appy().link(fieldName, obj)
|
||||
|
||||
# Call the custom "onEdit" if available
|
||||
msg = None # The message to display to the user. It can be set by onEdit
|
||||
if obj.wrapperClass:
|
||||
appyObject = obj.appy()
|
||||
if hasattr(appyObject, 'onEdit'): appyObject.onEdit(created)
|
||||
if hasattr(appyObject, 'onEdit'):
|
||||
msg = appyObject.onEdit(created)
|
||||
# Manage "add" permissions and reindex the object
|
||||
obj._appy_managePermissions()
|
||||
obj.reindexObject()
|
||||
return obj
|
||||
return obj, msg
|
||||
|
||||
def delete(self):
|
||||
'''This methods is self's suicide.'''
|
||||
|
@ -219,10 +221,21 @@ class BaseMixin:
|
|||
return self.skyn.edit(self)
|
||||
|
||||
# Create or update the object in the database
|
||||
obj = self.createOrUpdate(isNew, values)
|
||||
obj, msg = self.createOrUpdate(isNew, values)
|
||||
|
||||
# Redirect the user to the appropriate page
|
||||
msg = obj.translate('Changes saved.', domain='plone')
|
||||
if not msg: msg = obj.translate('Changes saved.', domain='plone')
|
||||
# If the object has already been deleted (ie, it is a kind of transient
|
||||
# object like a one-shot form and has already been deleted in method
|
||||
# onEdit), redirect to the main site page.
|
||||
if not getattr(obj.getParentNode(), obj.id, None):
|
||||
obj.unindexObject()
|
||||
return self.goto(tool.getSiteUrl(), msg)
|
||||
# If the user can't access the object anymore, redirect him to the
|
||||
# main site page.
|
||||
user = self.portal_membership.getAuthenticatedMember()
|
||||
if not user.has_permission('View', obj):
|
||||
return self.goto(tool.getSiteUrl(), msg)
|
||||
if rq.get('buttonOk.x', None) or saveConfirmed:
|
||||
# Go to the consult view for this object
|
||||
obj.plone_utils.addPortalMessage(msg)
|
||||
|
@ -321,8 +334,10 @@ class BaseMixin:
|
|||
if previousData:
|
||||
self.addDataChange(previousData)
|
||||
|
||||
def goto(self, url, addParams=False):
|
||||
def goto(self, url, msg=None):
|
||||
'''Brings the user to some p_url after an action has been executed.'''
|
||||
if msg:
|
||||
url += '?' + urllib.urlencode([('portal_status_message',msg)])
|
||||
return self.REQUEST.RESPONSE.redirect(url)
|
||||
|
||||
def showField(self, name, layoutType='view'):
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue