[gen] Added attribute 'xml' on every field allowing to customize the XML marshalling process. [gen] Added new layout 'xml', now different from the 'view' layout, allowing to define which fields are to be dumped in the XML version of some object. [gen] Security fix in ToolMixin::getUser. [gen] Bugfix in Mixin::getUrl. [shared] dav.py: method 'get' can now accept parameters. [shared] xml_parser: changes to the XmlMarshaller (due to XML-related changes).

This commit is contained in:
Gaetan Delannay 2014-12-08 14:52:04 +01:00
parent f055ec1754
commit c53654a1a1
19 changed files with 119 additions and 80 deletions

View file

@ -1,6 +1,6 @@
# ------------------------------------------------------------------------------
import os, re, httplib, sys, stat, urlparse, time, socket, xml.sax
from urllib import quote
import urllib
from StringIO import StringIO
from mimetypes import guess_type
from base64 import encodestring
@ -19,7 +19,7 @@ class FormDataEncoder:
def marshalValue(self, name, value):
if isinstance(value, basestring):
return '%s=%s' % (name, quote(str(value)))
return '%s=%s' % (name, urllib.quote(str(value)))
elif isinstance(value, float):
return '%s:float=%s' % (name, value)
elif isinstance(value, int):
@ -109,7 +109,13 @@ class HttpResponse:
# Return an unmarshalled version of the XML content, for
# easy use in Python.
try:
return XmlUnmarshaller(utf8=self.utf8).parse(self.body)
parser = XmlUnmarshaller(utf8=self.utf8)
res = parser.parse(self.body)
if parser.rootTag == 'exception':
# This is an exception: "res" contains the traceback
raise ResourceError('Distant server exception: ' \
'%s' % res)
return res
except xml.sax.SAXParseException, se:
raise ResourceError('Invalid XML response (%s)'%str(se))
@ -153,10 +159,10 @@ class Resource:
# Add credentials if present
if not (self.username and self.password): return
if headers.has_key('Authorization'): return
credentials = '%s:%s' % (self.username,self.password)
credentials = credentials.replace('\012','')
credentials = '%s:%s' % (self.username, self.password)
credentials = credentials.replace('\012', '')
headers['Authorization'] = "Basic %s" % encodestring(credentials)
headers['User-Agent'] = 'WebDAV.client'
headers['User-Agent'] = 'Appy'
headers['Host'] = self.host
headers['Connection'] = 'close'
headers['Accept'] = '*/*'
@ -241,9 +247,14 @@ class Resource:
if type =='fileName': body.close()
return res
def get(self, uri=None, headers={}):
'''Perform a HTTP GET on the server.'''
def get(self, uri=None, headers={}, params=None):
'''Perform a HTTP GET on the server. Parameters can be given as a dict
in p_params.'''
if not uri: uri = self.uri
# Encode and append params if given
if params:
sep = ('?' in uri) and '&' or '?'
uri = '%s%s%s' % (uri, sep, urllib.urlencode(params))
return self.send('GET', uri, headers=headers)
rss = get

View file

@ -322,6 +322,8 @@ class XmlUnmarshaller(XmlParser):
# knowing that the value is a 'string' is not sufficient).
self.conversionFunctions = conversionFunctions
self.utf8 = utf8
# Remember the name of the root tag
self.rootTag = None
def encode(self, value):
'''Depending on self.utf8 we may need to encode p_value.'''
@ -354,6 +356,9 @@ class XmlUnmarshaller(XmlParser):
previousElem = None
if self.env.currentElem:
previousElem = self.env.currentElem.name
else:
# We are walking the root tag
self.rootTag = elem
e = XmlParser.startElement(self, elem, attrs)
# Determine the type of the element.
elemType = 'unicode' # Default value
@ -668,15 +673,11 @@ 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()+suffix)
self.dumpField(res, 'url', elem.absolute_url())
else:
self.dumpField(res, 'url', value.absolute_url()+suffix)
self.dumpField(res, 'url', value.absolute_url())
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.
@ -814,27 +815,19 @@ class XmlMarshaller:
self.dumpField(res, field.getName(),field.get(instance),
fieldType=fieldType)
elif objectType == 'appy':
for field in instance.getAppyTypes('view', None):
# Dump base attributes
for name in ('created', 'creator', 'modified'):
self.dumpField(res, name, getattr(instance, name))
for field in instance.getAppyTypes('xml', 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 (type(self.fieldsToMarshall) in sequenceTypes) \
and (field.name not in self.fieldsToMarshall): continue
# Determine field type and value
fieldType = 'basic'
if field.type == 'File':
fieldType = 'file'
v = field.getValue(instance)
elif field.type == 'Ref':
fieldType = 'ref'
v = field.getValue(instance, appy=False)
else:
v = field.getValue(instance)
fieldType = (field.type == 'File') and 'file' or 'basic'
v = field.getXmlValue(instance, field.getValue(instance))
self.dumpField(res, field.name, v, fieldType=fieldType)
# Dump the object history.
# Dump the object history
if hasattr(instance.aq_base, 'workflow_history'):
histTag = self.getTagName('history')
eventTag = self.getTagName('event')