diff --git a/gen/mixins/__init__.py b/gen/mixins/__init__.py index d7d2d9f..1b687bc 100644 --- a/gen/mixins/__init__.py +++ b/gen/mixins/__init__.py @@ -9,8 +9,9 @@ import appy.gen as gen from appy.gen.utils import * from appy.gen.layout import Table, defaultPageLayouts, ColumnLayout 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.xml_parser import XmlMarshaller # ------------------------------------------------------------------------------ class BaseMixin: @@ -344,6 +345,27 @@ class BaseMixin: iNames = self.wrapperClass.getIndexes().keys() 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'): '''Prints a p_msg in the user interface. p_logLevel may be "info", "warning" or "error".''' @@ -664,13 +686,14 @@ class BaseMixin: return res def getAppyTypes(self, layoutType, pageName): - '''Returns the list of appyTypes that belong to a given p_page, for a - given p_layoutType.''' + '''Returns the list of fields that belong to a given page (p_pageName) + for a given p_layoutType. If p_pageName is None, fields of all pages + are returned.''' res = [] - for appyType in self.getAllAppyTypes(): - if appyType.page.name != pageName: continue - if not appyType.isShowable(self, layoutType): continue - res.append(appyType) + for field in self.getAllAppyTypes(): + if pageName and (field.page.name != pageName): continue + if not field.isShowable(self, layoutType): continue + res.append(field) return res def getCssJs(self, fields, layoutType, res): @@ -1413,8 +1436,15 @@ class BaseMixin: if parent.meta_type != 'Folder': return parent def index_html(self): - '''Redirects to /ui.''' - return self.REQUEST.RESPONSE.redirect(self.getUrl()) + '''Redirects to /ui.''' + 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): '''Is the currently logged user anonymous ?''' diff --git a/shared/xml_parser.py b/shared/xml_parser.py index 477c6de..7d4e73e 100644 --- a/shared/xml_parser.py +++ b/shared/xml_parser.py @@ -622,11 +622,15 @@ class XmlMarshaller: elif fieldType == 'dict': self.dumpDict(res, value) elif isRef: if value: + if self.objectType == 'appy': + suffix = '/xml' + else: + suffix = '' if type(value) in sequenceTypes: for elem in value: - self.dumpField(res, 'url', elem.absolute_url()) + self.dumpField(res, 'url', elem.absolute_url()+suffix) else: - self.dumpField(res, 'url', value.absolute_url()) + self.dumpField(res, 'url', value.absolute_url()+suffix) elif fieldType in ('list', 'tuple'): # The previous condition must be checked before this one because # referred objects may be stored in lists or tuples, too. @@ -751,33 +755,40 @@ class XmlMarshaller: self.dumpField(res, field.getName(),field.get(instance), fieldType=fieldType) elif objectType == 'appy': - for field in instance.getAllAppyTypes(): + for field in instance.getAppyTypes('view', None): # 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.type == 'Ref') and field.isBack: continue if (type(self.fieldsToMarshall) in sequenceTypes) \ and (field.name not in self.fieldsToMarshall): continue - # Determine field type + # Determine field type and value fieldType = 'basic' if field.type == 'File': fieldType = 'file' + v = field.getValue(instance) + if v: v = v._zopeFile elif field.type == 'Ref': fieldType = 'ref' - self.dumpField(res, field.name,field.getValue(instance), - fieldType=fieldType) + v = field.getValue(instance, type='zobjects') + else: + v = field.getValue(instance) + self.dumpField(res, field.name, v, fieldType=fieldType) # Dump the object history. - histTag = self.getTagName('history') - eventTag = self.getTagName('event') - res.write('<%s type="list">' % histTag) - wfInfo = instance.portal_workflow.getWorkflowsFor(instance) - if wfInfo: - history = instance.workflow_history[wfInfo[0].id] + if hasattr(instance.aq_base, 'workflow_history'): + histTag = self.getTagName('history') + eventTag = self.getTagName('event') + res.write('<%s type="list">' % histTag) + key = instance.workflow_history.keys()[0] + history = instance.workflow_history[key] for event in history: res.write('<%s type="object">' % eventTag) for k, v in event.iteritems(): self.dumpField(res, k, v) res.write('' % eventTag) - res.write('' % histTag) + res.write('' % histTag) self.marshallSpecificElements(instance, res) res.write('') else: