From f95f47b4a9a60d464218d64393305ff4edb19014 Mon Sep 17 00:00:00 2001 From: "P. Christeas" Date: Tue, 23 Nov 2010 20:53:54 +0200 Subject: [PATCH] doc webdav: refactor the mk_prop_response() for the locks This prepares the code to be reused in the DAV lock functions. bzr revid: p_christ@hol.gr-20101123185354-a2rjviaep3emqeez --- addons/document_webdav/webdav.py | 179 +++++++++++++++++-------------- 1 file changed, 99 insertions(+), 80 deletions(-) diff --git a/addons/document_webdav/webdav.py b/addons/document_webdav/webdav.py index bb2b8caf470..486595bc241 100644 --- a/addons/document_webdav/webdav.py +++ b/addons/document_webdav/webdav.py @@ -45,13 +45,103 @@ class Text2(xml.dom.minidom.Text): data = data.replace(">", ">") writer.write(data) -def createText2Node(doc, data): - if not isinstance(data, StringTypes): - raise TypeError, "node contents must be a string" - t = Text2() - t.data = data - t.ownerDocument = doc - return t +class Prop2xml(object): + """ A helper class to convert property structs to DAV:XML + + Written to generalize the use of _prop_child(), a class is + needed to hold some persistent data accross the recursions + of _prop_elem_child(). + """ + + def __init__(self, doc, namespaces, nsnum): + """ Init the structure + @param doc the xml doc element + @param namespaces a dict of namespaces + @param nsnum the next namespace number to define + """ + self.doc = doc + self.namespaces = namespaces + self.nsnum = nsnum + + def createText2Node(self, data): + if not isinstance(data, StringTypes): + raise TypeError, "node contents must be a string" + t = Text2() + t.data = data + t.ownerDocument = self.doc + return t + + def _prop_child(self, xnode, ns, prop, value): + """Append a property xml node to xnode, with value + + And a little smarter than that, it will consider namespace and + also allow nested properties etc. + + :param ns the namespace of the node + :param prop the name of the property + :param value the value. Can be: + string: text node + tuple ('elem', 'ns') for empty sub-node + tuple ('elem', 'ns', sub-elems) for sub-node with elements + tuple ('elem', 'ns', sub-elems, {attrs}) for sub-node with + optional elements and attributes + list, of above tuples + """ + if ns == 'DAV:': + ns_prefix = 'D:' + else: + ns_prefix="ns"+str(self.namespaces.index(ns))+":" + + pe = self.doc.createElement(ns_prefix+str(prop)) + if hasattr(value, '__class__') and value.__class__.__name__ == 'Element': + pe.appendChild(value) + else: + if ns == 'DAV:' and prop=="resourcetype" and isinstance(value, int): + # hack, to go.. + if value == 1: + ve = self.doc.createElement("D:collection") + pe.appendChild(ve) + else: + self._prop_elem_child(pe, ns, value, ns_prefix) + + xnode.appendChild(pe) + + def _prop_elem_child(self, pnode, pns, v, pns_prefix): + + if isinstance(v, list): + for vit in v: + self._prop_elem_child(pnode, pns, vit, pns_prefix) + elif isinstance(v,tuple): + need_ns = False + if v[1] == pns: + ns_prefix = pns_prefix + elif v[1] == 'DAV:': + ns_prefix = 'D:' + elif v[1] in self.namespaces: + ns_prefix="ns"+str(self.namespaces.index(v[1]))+":" + else: + ns_prefix="ns"+str(self.nsnum)+":" + need_ns = True + + ve = self.doc.createElement(ns_prefix+v[0]) + if need_ns: + ve.setAttribute("xmlns:ns"+str(self.nsnum), v[1]) + if len(v) > 2 and v[2] is not None: + if isinstance(v[2], (list, tuple)): + # support nested elements like: + # ( 'elem', 'ns:', [('sub-elem1', 'ns1'), ...] + self._prop_elem_child(ve, v[1], v[2], ns_prefix) + else: + vt = self.createText2Node(tools.ustr(v[2])) + ve.appendChild(vt) + if len(v) > 3 and v[3]: + assert isinstance(v[3], dict) + for ak, av in v[3].items(): + ve.setAttribute(ak, av) + pnode.appendChild(ve) + else: + ve = self.createText2Node(tools.ustr(v)) + pnode.appendChild(ve) super_mk_prop_response = PROPFIND.mk_prop_response @@ -73,78 +163,7 @@ def mk_prop_response(self, uri, good_props, bad_props, doc): re.setAttribute("xmlns:ns"+str(nsnum),nsname) nsnum=nsnum+1 - def _prop_child(xnode, ns, prop, value): - """Append a property xml node to xnode, with value - - And a little smarter than that, it will consider namespace and - also allow nested properties etc. - - :param ns the namespace of the node - :param prop the name of the property - :param value the value. Can be: - string: text node - tuple ('elem', 'ns') for empty sub-node - tuple ('elem', 'ns', sub-elems) for sub-node with elements - tuple ('elem', 'ns', sub-elems, {attrs}) for sub-node with - optional elements and attributes - list, of above tuples - """ - if ns == 'DAV:': - ns_prefix = 'D:' - else: - ns_prefix="ns"+str(namespaces.index(ns))+":" - - pe=doc.createElement(ns_prefix+str(prop)) - if hasattr(value, '__class__') and value.__class__.__name__ == 'Element': - pe.appendChild(value) - else: - if ns == 'DAV:' and prop=="resourcetype" and isinstance(value, int): - # hack, to go.. - if value == 1: - ve=doc.createElement("D:collection") - pe.appendChild(ve) - else: - _prop_elem_child(pe, ns, value, ns_prefix) - - xnode.appendChild(pe) - - def _prop_elem_child(pnode, pns, v, pns_prefix): - - if isinstance(v, list): - for vit in v: - _prop_elem_child(pnode, pns, vit, pns_prefix) - elif isinstance(v,tuple): - need_ns = False - if v[1] == pns: - ns_prefix = pns_prefix - elif v[1] == 'DAV:': - ns_prefix = 'D:' - elif v[1] in namespaces: - ns_prefix="ns"+str(namespaces.index(v[1]))+":" - else: - ns_prefix="ns"+str(nsnum)+":" - need_ns = True - - ve=doc.createElement(ns_prefix+v[0]) - if need_ns: - ve.setAttribute("xmlns:ns"+str(nsnum), v[1]) - if len(v) > 2 and v[2] is not None: - if isinstance(v[2], (list, tuple)): - # support nested elements like: - # ( 'elem', 'ns:', [('sub-elem1', 'ns1'), ...] - _prop_elem_child(ve, v[1], v[2], ns_prefix) - else: - vt=createText2Node(doc,tools.ustr(v[2])) - ve.appendChild(vt) - if len(v) > 3 and v[3]: - assert isinstance(v[3], dict) - for ak, av in v[3].items(): - ve.setAttribute(ak, av) - pnode.appendChild(ve) - else: - ve=createText2Node(doc, tools.ustr(v)) - pnode.appendChild(ve) - + propgen = Prop2xml(doc, namespaces, nsnum) # write href information uparts=urlparse.urlparse(uri) fileloc=uparts[2] @@ -180,7 +199,7 @@ def mk_prop_response(self, uri, good_props, bad_props, doc): for p,v in good_props[ns].items(): if v is None: continue - _prop_child(gp, ns, p, v) + propgen._prop_child(gp, ns, p, v) ps.appendChild(gp) re.appendChild(ps)