[gen] Added the possility to get an XML version of every object by calling URL <objectUrl>/xml; added the possiblity to call any method on any object by calling <objectUrl>?do=myMethod and retrieve the result as XML.

This commit is contained in:
Gaetan Delannay 2012-11-23 15:20:12 +01:00
parent 5269b278f7
commit c3aa01a554
2 changed files with 64 additions and 23 deletions

View file

@ -9,8 +9,9 @@ import appy.gen as gen
from appy.gen.utils import * from appy.gen.utils import *
from appy.gen.layout import Table, defaultPageLayouts, ColumnLayout from appy.gen.layout import Table, defaultPageLayouts, ColumnLayout
from appy.gen.descriptors import WorkflowDescriptor, ClassDescriptor from appy.gen.descriptors import WorkflowDescriptor, ClassDescriptor
from appy.shared.utils import sequenceTypes, normalizeText from appy.shared.utils import sequenceTypes, normalizeText, Traceback
from appy.shared.data import rtlLanguages from appy.shared.data import rtlLanguages
from appy.shared.xml_parser import XmlMarshaller
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
class BaseMixin: class BaseMixin:
@ -344,6 +345,27 @@ class BaseMixin:
iNames = self.wrapperClass.getIndexes().keys() iNames = self.wrapperClass.getIndexes().keys()
catalog.catalog_object(self, path, idxs=iNames) catalog.catalog_object(self, path, idxs=iNames)
def xml(self, action=None):
'''If no p_action is defined, this method returns the XML version of
this object. Else, it calls method named p_action on the
corresponding Appy wrapper and returns, as XML, the its result.'''
self.REQUEST.RESPONSE.setHeader('Content-Type','text/xml;charset=utf-8')
# Check if the user is allowed to consult this object
if not self.allows('View'):
return XmlMarshaller().marshall('Unauthorized')
if not action:
marshaller = XmlMarshaller(rootTag=self.getClass().__name__,
dumpUnicode=True)
res = marshaller.marshall(self, objectType='appy')
else:
appyObj = self.appy()
try:
methodRes = getattr(appyObj, action)()
res = XmlMarshaller().marshall(methodRes)
except Exception, e:
res = XmlMarshaller().marshall(Traceback.get())
return res
def say(self, msg, type='info'): def say(self, msg, type='info'):
'''Prints a p_msg in the user interface. p_logLevel may be "info", '''Prints a p_msg in the user interface. p_logLevel may be "info",
"warning" or "error".''' "warning" or "error".'''
@ -664,13 +686,14 @@ class BaseMixin:
return res return res
def getAppyTypes(self, layoutType, pageName): def getAppyTypes(self, layoutType, pageName):
'''Returns the list of appyTypes that belong to a given p_page, for a '''Returns the list of fields that belong to a given page (p_pageName)
given p_layoutType.''' for a given p_layoutType. If p_pageName is None, fields of all pages
are returned.'''
res = [] res = []
for appyType in self.getAllAppyTypes(): for field in self.getAllAppyTypes():
if appyType.page.name != pageName: continue if pageName and (field.page.name != pageName): continue
if not appyType.isShowable(self, layoutType): continue if not field.isShowable(self, layoutType): continue
res.append(appyType) res.append(field)
return res return res
def getCssJs(self, fields, layoutType, res): def getCssJs(self, fields, layoutType, res):
@ -1413,8 +1436,15 @@ class BaseMixin:
if parent.meta_type != 'Folder': return parent if parent.meta_type != 'Folder': return parent
def index_html(self): def index_html(self):
'''Redirects to /ui.''' '''Redirects to /ui.'''
return self.REQUEST.RESPONSE.redirect(self.getUrl()) rq = self.REQUEST
if rq.has_key('do'):
# The user wants to call a method on this object and get its result
# as XML.
return self.xml(action=rq['do'])
else:
# The user wants to consult the view page for this object
return rq.RESPONSE.redirect(self.getUrl())
def userIsAnon(self): def userIsAnon(self):
'''Is the currently logged user anonymous ?''' '''Is the currently logged user anonymous ?'''

View file

@ -622,11 +622,15 @@ class XmlMarshaller:
elif fieldType == 'dict': self.dumpDict(res, value) elif fieldType == 'dict': self.dumpDict(res, value)
elif isRef: elif isRef:
if value: if value:
if self.objectType == 'appy':
suffix = '/xml'
else:
suffix = ''
if type(value) in sequenceTypes: if type(value) in sequenceTypes:
for elem in value: for elem in value:
self.dumpField(res, 'url', elem.absolute_url()) self.dumpField(res, 'url', elem.absolute_url()+suffix)
else: else:
self.dumpField(res, 'url', value.absolute_url()) self.dumpField(res, 'url', value.absolute_url()+suffix)
elif fieldType in ('list', 'tuple'): elif fieldType in ('list', 'tuple'):
# The previous condition must be checked before this one because # The previous condition must be checked before this one because
# referred objects may be stored in lists or tuples, too. # referred objects may be stored in lists or tuples, too.
@ -751,33 +755,40 @@ class XmlMarshaller:
self.dumpField(res, field.getName(),field.get(instance), self.dumpField(res, field.getName(),field.get(instance),
fieldType=fieldType) fieldType=fieldType)
elif objectType == 'appy': elif objectType == 'appy':
for field in instance.getAllAppyTypes(): for field in instance.getAppyTypes('view', None):
# Dump only needed fields # Dump only needed fields
if (field.type == 'Computed') and not field.plainText:
# Ignore fields used for producing custom chunks of HTML
# within the web UI.
continue
if field.name in self.fieldsToExclude: continue if field.name in self.fieldsToExclude: continue
if (field.type == 'Ref') and field.isBack: continue
if (type(self.fieldsToMarshall) in sequenceTypes) \ if (type(self.fieldsToMarshall) in sequenceTypes) \
and (field.name not in self.fieldsToMarshall): continue and (field.name not in self.fieldsToMarshall): continue
# Determine field type # Determine field type and value
fieldType = 'basic' fieldType = 'basic'
if field.type == 'File': if field.type == 'File':
fieldType = 'file' fieldType = 'file'
v = field.getValue(instance)
if v: v = v._zopeFile
elif field.type == 'Ref': elif field.type == 'Ref':
fieldType = 'ref' fieldType = 'ref'
self.dumpField(res, field.name,field.getValue(instance), v = field.getValue(instance, type='zobjects')
fieldType=fieldType) else:
v = field.getValue(instance)
self.dumpField(res, field.name, v, fieldType=fieldType)
# Dump the object history. # Dump the object history.
histTag = self.getTagName('history') if hasattr(instance.aq_base, 'workflow_history'):
eventTag = self.getTagName('event') histTag = self.getTagName('history')
res.write('<%s type="list">' % histTag) eventTag = self.getTagName('event')
wfInfo = instance.portal_workflow.getWorkflowsFor(instance) res.write('<%s type="list">' % histTag)
if wfInfo: key = instance.workflow_history.keys()[0]
history = instance.workflow_history[wfInfo[0].id] history = instance.workflow_history[key]
for event in history: for event in history:
res.write('<%s type="object">' % eventTag) res.write('<%s type="object">' % eventTag)
for k, v in event.iteritems(): for k, v in event.iteritems():
self.dumpField(res, k, v) self.dumpField(res, k, v)
res.write('</%s>' % eventTag) res.write('</%s>' % eventTag)
res.write('</%s>' % histTag) res.write('</%s>' % histTag)
self.marshallSpecificElements(instance, res) self.marshallSpecificElements(instance, res)
res.write('</'); res.write(rootTagName); res.write('>') res.write('</'); res.write(rootTagName); res.write('>')
else: else: