Doc, webdav: new API for the DAV:resourcetype property.
[odoo/odoo.git] / addons / document_webdav / webdav.py
1 # -*- coding: utf-8 -*-
2 ##############################################################################
3 #
4 #    OpenERP, Open Source Management Solution
5 #    Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
6 #    Copyright (c) 1999 Christian Scholz (ruebe@aachen.heimat.de)
7 #
8 #    This program is free software: you can redistribute it and/or modify
9 #    it under the terms of the GNU Affero General Public License as
10 #    published by the Free Software Foundation, either version 3 of the
11 #    License, or (at your option) any later version.
12 #
13 #    This program is distributed in the hope that it will be useful,
14 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
15 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 #    GNU Affero General Public License for more details.
17 #
18 #    You should have received a copy of the GNU Affero General Public License
19 #    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 #
21 ##############################################################################
22
23 import xml.dom.minidom
24 domimpl = xml.dom.minidom.getDOMImplementation()
25 import urlparse
26 import urllib
27 from DAV import utils
28 from DAV.propfind import PROPFIND
29 import tools
30
31
32 super_mk_prop_response = PROPFIND.mk_prop_response
33 def mk_prop_response(self, uri, good_props, bad_props, doc):
34     """ make a new <prop> result element
35
36     We differ between the good props and the bad ones for
37     each generating an extra <propstat>-Node (for each error
38     one, that means).
39
40     """
41     re=doc.createElement("D:response")
42     # append namespaces to response
43     nsnum=0
44     namespaces = self.namespaces
45     if 'DAV:' in namespaces:
46         namespaces.remove('DAV:')
47     for nsname in namespaces:
48         re.setAttribute("xmlns:ns"+str(nsnum),nsname)
49         nsnum=nsnum+1
50
51     def _prop_child(xnode, ns, prop, value):
52         """Append a property xml node to xnode, with <prop>value</prop>
53            
54            And a little smarter than that, it will consider namespace and
55            also allow nested properties etc.
56            
57            :param ns the namespace of the <prop/> node
58            :param prop the name of the property
59            :param value the value. Can be:
60                     string: text node
61                     tuple ('elem', 'ns') for empty sub-node <ns:elem />
62                     tuple ('elem', 'ns', sub-elems) for sub-node with elements
63                     list, of above tuples
64         """
65         if ns == 'DAV:':
66             ns_prefix = 'D:'
67         else:
68             ns_prefix="ns"+str(namespaces.index(ns))+":"
69
70         pe=doc.createElement(ns_prefix+str(prop))
71         if hasattr(value, '__class__') and value.__class__.__name__ == 'Element':
72             pe.appendChild(value)
73         else:
74             if ns == 'DAV:' and prop=="resourcetype" and isinstance(value, int):
75                 # hack, to go..
76                 if value == 1:
77                     ve=doc.createElement("D:collection")
78                     pe.appendChild(ve)
79             else:
80                 _prop_elem_child(pe, ns, value, ns_prefix)
81
82             xnode.appendChild(pe)
83
84     def _prop_elem_child(pnode, pns, v, pns_prefix):
85         
86         if isinstance(v, list):
87             for vit in v:
88                 _prop_elem_child(pnode, pns, vit, pns_prefix)
89         elif isinstance(v,tuple):
90             need_ns = False
91             if v[1] == pns:
92                 ns_prefix = pns_prefix
93             elif v[1] == 'DAV:':
94                 ns_prefix = 'D:'
95             elif v[1] in namespaces:
96                 ns_prefix="ns"+str(namespaces.index(v[1]))+":"
97             else:
98                 # namespaces.append(v[1])
99                 # nsnum += 1
100                 ns_prefix="ns"+str(nsnum)+":"
101                 need_ns = True
102
103             ve=doc.createElement(ns_prefix+v[0])
104             if need_ns:
105                 ve.setAttribute("xmlns:ns"+str(nsnum), v[1])
106             if len(v) > 2 and isinstance(v[2], list):
107                 # support nested elements like:
108                 # ( 'elem', 'ns:', [('sub-elem1', 'ns1'), ...]
109                 _prop_elem_child(ve, v[1], v[2], ns_prefix)
110             pnode.appendChild(ve)
111         else:
112             ve=doc.createTextNode(tools.ustr(v))
113             pnode.appendChild(ve)
114
115     # write href information
116     uparts=urlparse.urlparse(uri)
117     fileloc=uparts[2]
118     if isinstance(fileloc, unicode):
119         fileloc = fileloc.encode('utf-8')
120     href=doc.createElement("D:href")
121     davpath = self._dataclass.parent.get_davpath()
122     hurl = '%s://%s%s%s' % (uparts[0], uparts[1], davpath, urllib.quote(fileloc))
123     huri=doc.createTextNode(hurl)
124     href.appendChild(huri)
125     re.appendChild(href)
126
127     # write good properties
128     ps=doc.createElement("D:propstat")
129     if good_props:
130         re.appendChild(ps)
131
132     gp=doc.createElement("D:prop")
133     for ns in good_props.keys():
134         if ns == 'DAV:':
135             ns_prefix = 'D:'
136         else:
137             ns_prefix="ns"+str(namespaces.index(ns))+":"
138         for p,v in good_props[ns].items():
139             if not v:
140                 continue
141             _prop_child(gp, ns, p, v)
142
143     ps.appendChild(gp)
144     s=doc.createElement("D:status")
145     t=doc.createTextNode("HTTP/1.1 200 OK")
146     s.appendChild(t)
147     ps.appendChild(s)
148     re.appendChild(ps)
149
150     # now write the errors!
151     if len(bad_props.items()):
152
153         # write a propstat for each error code
154         for ecode in bad_props.keys():
155             ps=doc.createElement("D:propstat")
156             re.appendChild(ps)
157             bp=doc.createElement("D:prop")
158             ps.appendChild(bp)
159
160             for ns in bad_props[ecode].keys():
161                 if ns == 'DAV:':
162                     ns_prefix='D:'
163                 else:
164                     ns_prefix="ns"+str(self.namespaces.index(ns))+":"
165
166             for p in bad_props[ecode][ns]:
167                 pe=doc.createElement(ns_prefix+str(p))
168                 bp.appendChild(pe)
169
170             s=doc.createElement("D:status")
171             t=doc.createTextNode(utils.gen_estring(ecode))
172             s.appendChild(t)
173             ps.appendChild(s)
174             re.appendChild(ps)
175
176     # return the new response element
177     return re
178
179
180 def mk_propname_response(self,uri,propnames,doc):
181     """ make a new <prop> result element for a PROPNAME request
182
183     This will simply format the propnames list.
184     propnames should have the format {NS1 : [prop1, prop2, ...], NS2: ...}
185
186     """
187     re=doc.createElement("D:response")
188
189     # write href information
190     uparts=urlparse.urlparse(uri)
191     fileloc=uparts[2]
192     if isinstance(fileloc, unicode):
193         fileloc = fileloc.encode('utf-8')
194     href=doc.createElement("D:href")
195     davpath = self._dataclass.parent.get_davpath()
196     hurl = '%s://%s%s%s' % (uparts[0], uparts[1], davpath, urllib.quote(fileloc))
197     huri=doc.createTextNode(hurl)
198     href.appendChild(huri)
199     re.appendChild(href)
200
201     ps=doc.createElement("D:propstat")
202     nsnum=0
203
204     for ns,plist in propnames.items():
205         # write prop element
206         pr=doc.createElement("D:prop")
207         if ns == 'DAV':
208             nsp = 'D'
209         else:
210             nsp="ns"+str(nsnum)
211             ps.setAttribute("xmlns:"+nsp,ns)
212             nsnum=nsnum+1
213
214         # write propertynames
215         for p in plist:
216             pe=doc.createElement(nsp+":"+p)
217             pr.appendChild(pe)
218
219         ps.appendChild(pr)
220
221     re.appendChild(ps)
222
223     return re
224
225 PROPFIND.mk_prop_response = mk_prop_response
226 PROPFIND.mk_propname_response = mk_propname_response
227