From aa70854c09a1e287342e830318c873131bf9744f Mon Sep 17 00:00:00 2001 From: "Harry (Open ERP)" Date: Tue, 6 Apr 2010 16:41:32 +0530 Subject: [IMP] document_webdav: removed DAV and refactore code bzr revid: hmo@tinyerp.com-20100406111132-9bscvnb6aojdvioo --- addons/document_webdav/DAV/BufferingHTTPServer.py | 99 ------ addons/document_webdav/DAV/WebDAVServer.py | 379 ---------------------- addons/document_webdav/DAV/__init__.py | 20 -- addons/document_webdav/DAV/constants.py | 18 - addons/document_webdav/DAV/davcmd.py | 218 ------------- addons/document_webdav/DAV/davcopy.py | 133 -------- addons/document_webdav/DAV/davmove.py | 102 ------ addons/document_webdav/DAV/delete.py | 63 ---- addons/document_webdav/DAV/errors.py | 56 ---- addons/document_webdav/DAV/iface.py | 263 --------------- addons/document_webdav/DAV/propfind.py | 372 --------------------- addons/document_webdav/DAV/status.py | 31 -- addons/document_webdav/DAV/utils.py | 160 --------- addons/document_webdav/dav_fs.py | 183 +++++------ addons/document_webdav/webdav_server.py | 140 +++++++- 15 files changed, 214 insertions(+), 2023 deletions(-) delete mode 100644 addons/document_webdav/DAV/BufferingHTTPServer.py delete mode 100644 addons/document_webdav/DAV/WebDAVServer.py delete mode 100644 addons/document_webdav/DAV/__init__.py delete mode 100644 addons/document_webdav/DAV/constants.py delete mode 100644 addons/document_webdav/DAV/davcmd.py delete mode 100755 addons/document_webdav/DAV/davcopy.py delete mode 100755 addons/document_webdav/DAV/davmove.py delete mode 100755 addons/document_webdav/DAV/delete.py delete mode 100755 addons/document_webdav/DAV/errors.py delete mode 100644 addons/document_webdav/DAV/iface.py delete mode 100755 addons/document_webdav/DAV/propfind.py delete mode 100644 addons/document_webdav/DAV/status.py delete mode 100755 addons/document_webdav/DAV/utils.py (limited to 'addons/document_webdav') diff --git a/addons/document_webdav/DAV/BufferingHTTPServer.py b/addons/document_webdav/DAV/BufferingHTTPServer.py deleted file mode 100644 index 37520421432..00000000000 --- a/addons/document_webdav/DAV/BufferingHTTPServer.py +++ /dev/null @@ -1,99 +0,0 @@ -#!/usr/bin/env python - -""" - Buffering HTTP Server - Copyright (C) 1999 Christian Scholz (ruebe@aachen.heimat.de) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -""" - - -from utils import VERSION, AUTHOR -__version__ = VERSION -__author__ = AUTHOR - -from BaseHTTPServer import BaseHTTPRequestHandler -import os -class BufferedHTTPRequestHandler(BaseHTTPRequestHandler): - """ - Buffering HTTP Request Handler - - This class is an extension to the BaseHTTPRequestHandler - class which buffers the whole output and sends it at once - after the processing if the request is finished. - - This makes it possible to work together with some clients - which otherwise would break (e.g. cadaver) - - """ - - - def _init_buffer(self): - """initialize the buffer. - - If you override the handle() method remember to call - this (see below) - """ - self.__buffer="" - self.__outfp=os.tmpfile() - - def _append(self,s): - """ append a string to the buffer """ - self.__buffer=self.__buffer+s - - def _flush(self): - """ flush the buffer to wfile """ - self.wfile.write(self.__buffer) - self.__outfp.write(self.__buffer) - self.__outfp.flush() - self.wfile.flush() - self.__buffer="" - - def handle(self): - """ Handle a HTTP request """ - self._init_buffer() - BaseHTTPRequestHandler.handle(self) - self._flush() - - def send_header(self, keyword, value): - """Send a MIME header.""" - if self.request_version != 'HTTP/0.9': - self._append("%s: %s\r\n" % (keyword, value)) - - def end_headers(self): - """Send the blank line ending the MIME headers.""" - if self.request_version != 'HTTP/0.9': - self._append("\r\n") - - def send_response(self, code, message=None): - self.log_request(code) - - if message is None: - if self.responses.has_key(code): - message = self.responses[code][0] - else: - message = '' - - if self.request_version != 'HTTP/0.9': - self._append("%s %s %s\r\n" % - (self.protocol_version, str(code), message)) - - self.send_header('Server', self.version_string()) - self.send_header('Connection', 'close') - self.send_header('Date', self.date_time_string()) - - protocol_version="HTTP/1.1" - diff --git a/addons/document_webdav/DAV/WebDAVServer.py b/addons/document_webdav/DAV/WebDAVServer.py deleted file mode 100644 index 5f409773c18..00000000000 --- a/addons/document_webdav/DAV/WebDAVServer.py +++ /dev/null @@ -1,379 +0,0 @@ -""" - Python WebDAV Server. - Copyright (C) 1999 Christian Scholz (ruebe@aachen.heimat.de) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -This module builds on AuthServer by implementing the standard DAV -methods. - -Subclass this class and specify an IFACE_CLASS. See example. - -""" - -DEBUG=None - -from utils import VERSION, AUTHOR -__version__ = VERSION -__author__ = AUTHOR - - -import os -import sys -import time -import socket -import string -import posixpath -import base64 -import urlparse -import urllib - -from propfind import PROPFIND -from delete import DELETE -from davcopy import COPY -from davmove import MOVE - -from string import atoi,split -from status import STATUS_CODES -from errors import * - -import BaseHTTPServer - -class DAVRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): - """Simple DAV request handler with - - - GET - - HEAD - - PUT - - OPTIONS - - PROPFIND - - PROPPATCH - - MKCOL - - It uses the resource/collection classes for serving and - storing content. - - """ - - server_version = "DAV/" + __version__ - protocol_version = 'HTTP/1.1' - - ### utility functions - def _log(self, message): - pass - - def _append(self,s): - """ write the string to wfile """ - self.wfile.write(s) - - def send_body(self,DATA,code,msg,desc,ctype='application/octet-stream',headers=None): - """ send a body in one part """ - - if not headers: - headers = {} - self.send_response(code,message=msg) - self.send_header("Connection", "keep-alive") - self.send_header("Accept-Ranges", "bytes") - - for a,v in headers.items(): - self.send_header(a,v) - - if DATA: - self.send_header("Content-Length", str(len(DATA))) - self.send_header("Content-Type", ctype) - else: - self.send_header("Content-Length", "0") - - self.end_headers() - if DATA: - self._append(DATA) - - def send_body_chunks(self,DATA,code,msg,desc,ctype='text/xml; encoding="utf-8"'): - """ send a body in chunks """ - - self.responses[207]=(msg,desc) - self.send_response(code,message=msg) - self.send_header("Content-type", ctype) - self.send_header("Connection", "keep-alive") - self.send_header("Transfer-Encoding", "chunked") - self.end_headers() - self._append(hex(len(DATA))[2:]+"\r\n") - self._append(DATA) - self._append("\r\n") - self._append("0\r\n") - self._append("\r\n") - - ### HTTP METHODS - - def do_OPTIONS(self): - """return the list of capabilities """ - self.send_response(200) - self.send_header("Allow", "GET, HEAD, COPY, MOVE, POST, PUT, PROPFIND, PROPPATCH, OPTIONS, MKCOL, DELETE, TRACE") - self.send_header("Content-Type", "text/plain") - self.send_header("Connection", "keep-alive") - self.send_header("DAV", "1") - self.end_headers() - - def do_PROPFIND(self): - - dc=self.IFACE_CLASS - # read the body - body=None - if self.headers.has_key("Content-Length"): - l=self.headers['Content-Length'] - body=self.rfile.read(atoi(l)) - alt_body = """ - - - - - - - - - - """ - #self.wfile.write(body) - - # which Depth? - if self.headers.has_key('Depth'): - d=self.headers['Depth'] - else: - d="infinity" - - uri=self.geturi() - pf=PROPFIND(uri,dc,d) - - if body: - pf.read_propfind(body) - - try: - DATA=pf.createResponse() - DATA=DATA+"\n" - # print "Data:", DATA - except DAV_NotFound,(ec,dd): - return self.send_notFound(dd, uri) - except DAV_Error, (ec,dd): - return self.send_error(ec,dd) - - self.send_body_chunks(DATA,207,"Multi-Status","Multiple responses") - - def geturi(self): - buri = self.IFACE_CLASS.baseuri - if buri[-1] == '/': - return urllib.unquote(buri[:-1]+self.path) - else: - return urllib.unquote(buri+self.path) - - def do_GET(self): - """Serve a GET request.""" - dc=self.IFACE_CLASS - uri=self.geturi() - - # get the last modified date - try: - lm=dc.get_prop(uri,"DAV:","getlastmodified") - except: - lm="Sun, 01 Dec 2014 00:00:00 GMT" # dummy! - headers={"Last-Modified":lm , "Connection": "keep-alive"} - - # get the content type - try: - ct=dc.get_prop(uri,"DAV:","getcontenttype") - except: - ct="application/octet-stream" - - # get the data - try: - data=dc.get_data(uri) - except DAV_Error, (ec,dd): - self.send_status(ec) - return - - # send the data - self.send_body(data,200,"OK","OK",ct,headers) - - def do_HEAD(self): - """ Send a HEAD response """ - dc=self.IFACE_CLASS - uri=self.geturi() - - # get the last modified date - try: - lm=dc.get_prop(uri,"DAV:","getlastmodified") - except: - lm="Sun, 01 Dec 2014 00:00:00 GMT" # dummy! - - headers={"Last-Modified":lm, "Connection": "keep-alive"} - - # get the content type - try: - ct=dc.get_prop(uri,"DAV:","getcontenttype") - except: - ct="application/octet-stream" - - try: - data=dc.get_data(uri) - headers["Content-Length"]=str(len(data)) - except DAV_NotFound: - self.send_body(None,404,"Not Found","") - return - - self.send_body(None,200,"OK","OK",ct,headers) - - def do_POST(self): - self.send_error(404,"File not found") - - def do_MKCOL(self): - """ create a new collection """ - - dc=self.IFACE_CLASS - uri=self.geturi() - try: - res = dc.mkcol(uri) - if res: - self.send_body(None,201,"Created",'') - else: - self.send_body(None,415,"Cannot create",'') - #self.send_header("Connection", "keep-alive") - # Todo: some content, too - except DAV_Error, (ec,dd): - self.send_body(None,int(ec),dd,dd) - - def do_DELETE(self): - """ delete an resource """ - dc=self.IFACE_CLASS - uri=self.geturi() - dl=DELETE(uri,dc) - if dc.is_collection(uri): - res=dl.delcol() - else: - res=dl.delone() - - if res: - self.send_status(207,body=res) - else: - self.send_status(204) - - def do_PUT(self): - dc=self.IFACE_CLASS - - # read the body - body=None - if self.headers.has_key("Content-Length"): - l=self.headers['Content-Length'] - body=self.rfile.read(atoi(l)) - uri=self.geturi() - - ct=None - if self.headers.has_key("Content-Type"): - ct=self.headers['Content-Type'] - try: - dc.put(uri,body,ct) - except DAV_Error, (ec,dd): - self.send_status(ec) - return - self.send_status(201) - - def do_COPY(self): - """ copy one resource to another """ - try: - self.copymove(COPY) - except DAV_Error, (ec,dd): - self.send_status(ec) - - def do_MOVE(self): - """ move one resource to another """ - try: - self.copymove(MOVE) - except DAV_Error, (ec,dd): - self.send_status(ec) - - def copymove(self,CLASS): - """ common method for copying or moving objects """ - dc=self.IFACE_CLASS - - # get the source URI - source_uri=self.geturi() - - # get the destination URI - dest_uri=self.headers['Destination'] - dest_uri=urllib.unquote(dest_uri) - - # Overwrite? - overwrite=1 - result_code=204 - if self.headers.has_key("Overwrite"): - if self.headers['Overwrite']=="F": - overwrite=None - result_code=201 - - # instanciate ACTION class - cp=CLASS(dc,source_uri,dest_uri,overwrite) - - # Depth? - d="infinity" - if self.headers.has_key("Depth"): - d=self.headers['Depth'] - - if d!="0" and d!="infinity": - self.send_status(400) - return - - if d=="0": - res=cp.single_action() - self.send_status(res) - return - - # now it only can be "infinity" but we nevertheless check for a collection - if dc.is_collection(source_uri): - try: - res=cp.tree_action() - except DAV_Error, (ec,dd): - self.send_status(ec) - return - else: - try: - res=cp.single_action() - except DAV_Error, (ec,dd): - self.send_status(ec) - return - - if res: - self.send_body_chunks(res,207,STATUS_CODES[207],STATUS_CODES[207], - ctype='text/xml; charset="utf-8"') - else: - self.send_status(result_code) - - def get_userinfo(self,user,pw): - """ Dummy method which lets all users in """ - - return 1 - - def send_status(self,code=200,mediatype='text/xml; charset="utf-8"', \ - msg=None,body=None): - - if not msg: msg=STATUS_CODES[code] - self.send_body(body,code,STATUS_CODES[code],msg,mediatype) - - def send_notFound(self,descr,uri): - body = """ - - %s - - %s - - """ - return self.send_status(404,descr, body=body % (uri,descr)) diff --git a/addons/document_webdav/DAV/__init__.py b/addons/document_webdav/DAV/__init__.py deleted file mode 100644 index 10abdb40014..00000000000 --- a/addons/document_webdav/DAV/__init__.py +++ /dev/null @@ -1,20 +0,0 @@ -""" - python davserver - Copyright (C) 1999 Christian Scholz (ruebe@aachen.heimat.de) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -""" - - diff --git a/addons/document_webdav/DAV/constants.py b/addons/document_webdav/DAV/constants.py deleted file mode 100644 index e858ac519c2..00000000000 --- a/addons/document_webdav/DAV/constants.py +++ /dev/null @@ -1,18 +0,0 @@ -""" - -constants definition - - -""" - -# definition for resourcetype -COLLECTION=1 -OBJECT=None -DAV_PROPS=['creationdate', 'displayname', 'getcontentlanguage', 'getcontentlength', 'getcontenttype', 'getetag', 'getlastmodified', 'lockdiscovery', 'resourcetype', 'source', 'supportedlock'] - - -# Request classes in propfind - -RT_ALLPROP=1 -RT_PROPNAME=2 -RT_PROP=3 diff --git a/addons/document_webdav/DAV/davcmd.py b/addons/document_webdav/DAV/davcmd.py deleted file mode 100644 index 5c6be3ff9f7..00000000000 --- a/addons/document_webdav/DAV/davcmd.py +++ /dev/null @@ -1,218 +0,0 @@ -""" - -davcmd.py ---------- - -containts commands like copy, move, delete for normal -resources and collections - -""" - -from string import split,replace,joinfields -import urlparse - -from utils import create_treelist, is_prefix -from errors import * - -def deltree(dc,uri,exclude={}): - """ delete a tree of resources - - dc -- dataclass to use - uri -- root uri to delete - exclude -- an optional list of uri:error_code pairs which should not - be deleted. - - returns dict of uri:error_code tuples from which - another method can create a multistatus xml element. - - Also note that we only know Depth=infinity thus we don't have - to test for it. - - """ - - tlist=create_treelist(dc,uri) - result={} - - for i in range(len(tlist),0,-1): - problem_uris=result.keys() - element=tlist[i-1] - - # test here, if an element is a prefix of an uri which - # generated an error before. - # note that we walk here from childs to parents, thus - # we cannot delete a parent if a child made a problem. - # (see example in 8.6.2.1) - ok=1 - for p in problem_uris: - if is_prefix(element,p): - ok=None - break - - if not ok: continue - - # here we test for the exclude list which is the other way round! - for p in exclude.keys(): - if is_prefix(p,element): - ok=None - break - - if not ok: continue - - # now delete stuff - try: - delone(dc,element) - except DAV_Error, (ec,dd): - result[element]=ec - - return result - -def delone(dc,uri): - """ delete a single object """ - if dc.is_collection(uri): - dc.rmcol(uri) # should be empty - else: - dc.rm(uri) - -### -### COPY -### - -# helper function - -def copy(dc,src,dst): - """ only copy the element - - This is just a helper method factored out from copy and - copytree. It will not handle the overwrite or depth header. - - """ - - # destination should have been deleted before - if dc.exists(dst): raise DAV_Error, 412 - - # source should exist also - if not dc.exists(src): raise DAV_NotFound - - if dc.is_collection(src): - dc.copycol(src,dst) # an exception will be passed thru - else: - dc.copy(src,dst) # an exception will be passed thru - - -# the main functions - -def copyone(dc,src,dst,overwrite=None): - """ copy one resource to a new destination """ - - if overwrite and dc.exists(dst): - delres=deltree(dc,dst) - else: - delres={} - - # if we cannot delete everything, then do not copy! - if delres: return delres - - try: - copy(dc,src,dst) # pass thru exceptions - except DAV_Error, (ec,dd): - return ec - -def copytree(dc,src,dst,overwrite=None): - """ copy a tree of resources to another location - - dc -- dataclass to use - src -- src uri from where to copy - dst -- dst uri - overwrite -- if 1 then delete dst uri before - - returns dict of uri:error_code tuples from which - another method can create a multistatus xml element. - - """ - - - # first delete the destination resource - if overwrite and dc.exists(dst): - delres=deltree(dc,dst) - else: - delres={} - - # if we cannot delete everything, then do not copy! - if delres: return delres - - # get the tree we have to copy - tlist=create_treelist(dc,src) - result={} - - # prepare destination URIs (get the prefix) - dpath=urlparse.urlparse(dst)[2] - - for element in tlist: - problem_uris=result.keys() - - # now URIs get longer and longer thus we have - # to test if we had a parent URI which we were not - # able to copy in problem_uris which is the prefix - # of the actual element. If it is, then we cannot - # copy this as well but do not generate another error. - ok=1 - for p in problem_uris: - if is_prefix(p,element): - ok=None - break - - if not ok: continue - - # now create the destination URI which corresponds to - # the actual source URI. -> actual_dst - # ("subtract" the base src from the URI and prepend the - # dst prefix to it.) - esrc=replace(element,src,"") - actual_dst=dpath+esrc - - # now copy stuff - try: - copy(dc,element,actual_dst) - except DAV_Error, (ec,dd): - result[element]=ec - - return result - - - -### -### MOVE -### - - -def moveone(dc,src,dst,overwrite=None): - """ move a single resource - - This is done by first copying it and then deleting - the original. - """ - - # first copy it - copyone(dc,src,dst,overwrite) - - # then delete it - dc.rm(src) - -def movetree(dc,src,dst,overwrite=None): - """ move a collection - - This is done by first copying it and then deleting - the original. - - PROBLEM: if something did not copy then we have a problem - when deleting as the original might get deleted! - """ - - # first copy it - res=copytree(dc,src,dst,overwrite) - - # then delete it - res=deltree(dc,src,exclude=res) - - return res - diff --git a/addons/document_webdav/DAV/davcopy.py b/addons/document_webdav/DAV/davcopy.py deleted file mode 100755 index ec44931b107..00000000000 --- a/addons/document_webdav/DAV/davcopy.py +++ /dev/null @@ -1,133 +0,0 @@ -#!/usr/bin/env python - -""" - python davserver - Copyright (C) 1999 Christian Scholz (ruebe@aachen.heimat.de) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - -""" - - -from xml.dom import ext -from xml.dom.Document import Document - -import sys -import string -import urlparse -import urllib -from StringIO import StringIO - -import utils -from constants import COLLECTION, OBJECT, DAV_PROPS, RT_ALLPROP, RT_PROPNAME, RT_PROP -from errors import * -from utils import create_treelist, quote_uri, gen_estring - -class COPY: - """ copy resources and eventually create multistatus responses - - This module implements the COPY class which is responsible for - copying resources. Usually the normal copy work is done in the - interface class. This class only creates error messages if error - occur. - - """ - - - def __init__(self,dataclass,src_uri,dst_uri,overwrite): - self.__dataclass=dataclass - self.__src=src_uri - self.__dst=dst_uri - self.__overwrite=overwrite - - - def single_action(self): - """ copy a normal resources. - - We try to copy it and return the result code. - This is for Depth==0 - - """ - - dc=self.__dataclass - base=self.__src - - ### some basic tests - # test if dest exists and overwrite is false - if dc.exists(self.__dst) and not self.__overwrite: raise DAV_Error, 412 - # test if src and dst are the same - # (we assume that both uris are on the same server!) - ps=urlparse.urlparse(self.__src)[2] - pd=urlparse.urlparse(self.__dst)[2] - if ps==pd: raise DAV_Error, 403 - - return dc.copyone(self.__src,self.__dst,self.__overwrite) - - #return copyone(dc,self.__src,self.__dst,self.__overwrite) - - def tree_action(self): - """ copy a tree of resources (a collection) - - Here we return a multistatus xml element. - - """ - dc=self.__dataclass - base=self.__src - - ### some basic tests - # test if dest exists and overwrite is false - if dc.exists(self.__dst) and not self.__overwrite: raise DAV_Error, 412 - # test if src and dst are the same - # (we assume that both uris are on the same server!) - ps=urlparse.urlparse(self.__src)[2] - pd=urlparse.urlparse(self.__dst)[2] - if ps==pd: raise DAV_Error, 403 - - - result=dc.copytree(self.__src,self.__dst,self.__overwrite) - #result=copytree(dc,self.__src,self.__dst,self.__overwrite) - - if not result: return None - - ### - ### create the multistatus XML element - ### (this is also the same as in delete.py. - ### we might make a common method out of it) - ### - - doc = Document(None) - ms=doc.createElement("D:multistatus") - ms.setAttribute("xmlns:D","DAV:") - doc.appendChild(ms) - - for el,ec in result.items(): - re=doc.createElement("D:response") - hr=doc.createElement("D:href") - st=doc.createElement("D:status") - huri=doc.createTextNode(quote_uri(el)) - t=doc.createTextNode(gen_estring(ec)) - st.appendChild(t) - hr.appendChild(huri) - re.appendChild(hr) - re.appendChild(st) - ms.appendChild(re) - - sfile=StringIO() - ext.PrettyPrint(doc,stream=sfile) - s=sfile.getvalue() - sfile.close() - return s - diff --git a/addons/document_webdav/DAV/davmove.py b/addons/document_webdav/DAV/davmove.py deleted file mode 100755 index 78c1e649389..00000000000 --- a/addons/document_webdav/DAV/davmove.py +++ /dev/null @@ -1,102 +0,0 @@ -#!/usr/bin/env python - -""" - python davserver - Copyright (C) 1999 Christian Scholz (ruebe@aachen.heimat.de) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - -""" - - -import sys -import string -import urlparse -import urllib -from StringIO import StringIO - -import utils -from constants import COLLECTION, OBJECT, DAV_PROPS -from constants import RT_ALLPROP, RT_PROPNAME, RT_PROP -from errors import * -from utils import create_treelist, quote_uri, gen_estring, make_xmlresponse -from davcmd import moveone, movetree - -class MOVE: - """ move resources and eventually create multistatus responses - - This module implements the MOVE class which is responsible for - moving resources. - - MOVE is implemented by a COPY followed by a DELETE of the old - resource. - - """ - - - def __init__(self,dataclass,src_uri,dst_uri,overwrite): - self.__dataclass=dataclass - self.__src=src_uri - self.__dst=dst_uri - self.__overwrite=overwrite - - - def single_action(self): - """ move a normal resources. - - We try to move it and return the result code. - This is for Depth==0 - - """ - - dc=self.__dataclass - base=self.__src - - ### some basic tests - # test if dest exists and overwrite is false - if dc.exists(self.__dst) and not self.__overwrite: raise DAV_Error, 412 - # test if src and dst are the same - # (we assume that both uris are on the same server!) - ps=urlparse.urlparse(self.__src)[2] - pd=urlparse.urlparse(self.__dst)[2] - if ps==pd: raise DAV_Error, 403 - - return dc.moveone(self.__src,self.__dst,self.__overwrite) - - def tree_action(self): - """ move a tree of resources (a collection) - - Here we return a multistatus xml element. - - """ - dc=self.__dataclass - base=self.__src - - ### some basic tests - # test if dest exists and overwrite is false - if dc.exists(self.__dst) and not self.__overwrite: raise DAV_Error, 412 - # test if src and dst are the same - # (we assume that both uris are on the same server!) - ps=urlparse.urlparse(self.__src)[2] - pd=urlparse.urlparse(self.__dst)[2] - if ps==pd: raise DAV_Error, 403 - - result=dc.movetree(self.__src,self.__dst,self.__overwrite) - if not result: return None - - # create the multistatus XML element - return make_xmlresponse(result) - diff --git a/addons/document_webdav/DAV/delete.py b/addons/document_webdav/DAV/delete.py deleted file mode 100755 index ed017e53b6d..00000000000 --- a/addons/document_webdav/DAV/delete.py +++ /dev/null @@ -1,63 +0,0 @@ -#!/usr/bin/env python - -""" - - python davserver - Copyright (C) 1999 Christian Scholz (ruebe@aachen.heimat.de) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - -""" -import os -import string -import urllib -from StringIO import StringIO - -from status import STATUS_CODES -from utils import gen_estring, quote_uri, make_xmlresponse -from davcmd import deltree - -class DELETE: - - def __init__(self,uri,dataclass): - self.__dataclass=dataclass - self.__uri=uri - - def delcol(self): - """ delete a collection """ - - dc=self.__dataclass - result=dc.deltree(self.__uri) - - if not len(result.items()): - return None # everything ok - - # create the result element - return make_xmlresponse(result) - - def delone(self): - """ delete a resource """ - - dc=self.__dataclass - result=dc.delone(self.__uri) - - if not result: return None - if not len(result.items()): - return None # everything ok - - # create the result element - return make_xmlresponse(result) - diff --git a/addons/document_webdav/DAV/errors.py b/addons/document_webdav/DAV/errors.py deleted file mode 100755 index 9c0e7667913..00000000000 --- a/addons/document_webdav/DAV/errors.py +++ /dev/null @@ -1,56 +0,0 @@ -#!/usr/bin/env python -""" - - Exceptions for the DAVserver implementation - -""" - -class DAV_Error(Exception): - """ in general we can have the following arguments: - - 1. the error code - 2. the error result element, e.g. a element - """ - - def __init__(self,*args): - if len(args)==1: - self.args=(args[0],"") - else: - self.args=args - -class DAV_Secret(DAV_Error): - """ the user is not allowed to know anything about it - - returning this for a property value means to exclude it - from the response xml element. - """ - - def __init__(self): - DAV_Error.__init__(self,0) - pass - -class DAV_NotFound(DAV_Error): - """ a requested property was not found for a resource """ - - def __init__(self,*args): - if len(args): - if isinstance(args[0],list): - stre = "Path %s not found!"%('/'.join(args[0])) - else: - stre = args[0] - DAV_Error.__init__(self,404,stre) - else: - DAV_Error.__init__(self,404) - - pass - -class DAV_Forbidden(DAV_Error): - """ a method on a resource is not allowed """ - - def __init__(self,*args): - if len(args): - DAV_Error.__init__(self,403,args[0]) - else: - DAV_Error.__init__(self,403) - pass - diff --git a/addons/document_webdav/DAV/iface.py b/addons/document_webdav/DAV/iface.py deleted file mode 100644 index c8f5fe2594d..00000000000 --- a/addons/document_webdav/DAV/iface.py +++ /dev/null @@ -1,263 +0,0 @@ -""" - -basic interface class - -use this for subclassing when writing your own interface -class. - -""" - -from errors import * - -import time -from string import lower - -class dav_interface: - """ interface class for implementing DAV servers """ - - ### defined properties (modify this but let the DAV stuff there!) - ### the format is namespace: [list of properties] - - PROPS={"DAV:" : ('creationdate', - 'displayname', - 'getcontentlanguage', - 'getcontentlength', - 'getcontenttype', - 'getetag', - 'getlastmodified', - 'lockdiscovery', - 'resourcetype', - 'source', - 'supportedlock'), - "NS2" : ("p1","p2") - } - - # here we define which methods handle which namespace - # the first item is the namespace URI and the second one - # the method prefix - # e.g. for DAV:getcontenttype we call dav_getcontenttype() - M_NS={"DAV:" : "_get_dav", - "NS2" : "ns2" } - - def get_propnames(self,uri): - """ return the property names allowed for the given URI - - In this method we simply return the above defined properties - assuming that they are valid for any resource. - You can override this in order to return a different set - of property names for each resource. - - """ - return self.PROPS - - def get_prop2(self,uri,ns,pname): - """ return the value of a property - """ - if lower(ns)=="dav:": return self.get_dav(uri,pname) - - raise DAV_NotFound - - def get_prop(self,uri,ns,propname): - """ return the value of a given property - - uri -- uri of the object to get the property of - ns -- namespace of the property - pname -- name of the property - """ - if self.M_NS.has_key(ns): - prefix=self.M_NS[ns] - else: - print "No namespace:",ns, "( for prop:", propname,")" - raise DAV_NotFound - mname=prefix+"_"+propname - if not hasattr(self,mname): - raise DAV_NotFound - - try: - m=getattr(self,mname) - r=m(uri) - return r - except AttributeError, e: - print 'Property %s not supported' % propname - print "Exception:", e - raise DAV_NotFound - - ### - ### DATA methods (for GET and PUT) - ### - - def get_data(self,uri): - """ return the content of an object - - return data or raise an exception - - """ - raise DAV_NotFound - - def put(self,uri,data): - """ write an object to the repository - - return a result code or raise an exception - """ - - raise DAV_Forbidden - - ### - ### Methods for DAV properties - ### - - def _get_dav_creationdate(self,uri): - """ return the creationdate of a resource """ - d=self.get_creationdate(uri) - # format it - if isinstance(d, int) or isinstance(d, float): - d = time.localtimetime(d) - return time.strftime("%Y-%m-%dT%H:%M:%S%Z",d) - - def _get_dav_getlastmodified(self,uri): - """ return the last modified date of a resource """ - d=self.get_lastmodified(uri) - if isinstance(d, int) or isinstance(d, float): - d = time.localtime(d) - # format it - return time.asctime(d) - - - ### - ### OVERRIDE THESE! - ### - - def get_creationdate(self,uri): - """ return the creationdate of the resource """ - return time.time() - - def get_lastmodified(self,uri): - """ return the last modification date of the resource """ - return time.time() - - - ### - ### COPY MOVE DELETE - ### - - ### methods for deleting a resource - - def rmcol(self,uri): - """ delete a collection - - This should not delete any children! This is automatically done - before by the DELETE class in DAV/delete.py - - return a success code or raise an exception - - """ - raise DAV_NotFound - - def rm(self,uri): - """ delete a single resource - - return a success code or raise an exception - - """ - raise DAV_NotFound - - """ - - COPY/MOVE HANDLER - - These handler are called when a COPY or MOVE method is invoked by - a client. In the default implementation it works as follows: - - - the davserver receives a COPY/MOVE method - - the davcopy or davmove module will be loaded and the corresponding - class will be initialized - - this class parses the query and decides which method of the interface class - to call: - - copyone for a single resource to copy - copytree for a tree to copy (collection) - (the same goes for move of course). - - - the interface class has now two options: - 1. to handle the action directly (e.g. cp or mv on filesystems) - 2. to let it handle via the copy/move methods in davcmd. - - ad 1) The first approach can be used when we know that no error can - happen inside a tree or when the action can exactly tell which - element made which error. We have to collect these and return - it in a dict of the form {uri: error_code, ...} - - ad 2) The copytree/movetree/... methods of davcmd.py will do the recursion - themselves and call for each resource the copy/move method of the - interface class. Thus method will then only act on a single resource. - (Thus a copycol on a normal unix filesystem actually only needs to do - an mkdir as the content will be copied by the davcmd.py function. - The davcmd.py method will also automatically collect all errors and - return the dictionary described above. - When you use 2) you also have to implement the copy() and copycol() - methods in your interface class. See the example for details. - - To decide which approach is the best you have to decide if your application - is able to generate errors inside a tree. E.g. a function which completely - fails on a tree if one of the tree's childs fail is not what we need. Then - 2) would be your way of doing it. - Actually usually 2) is the better solution and should only be replaced by - 1) if you really need it. - - The remaining question is if we should do the same for the DELETE method. - - """ - - ### MOVE handlers - - def moveone(self,src,dst,overwrite): - """ move one resource with Depth=0 """ - return moveone(self,src,dst,overwrite) - - def movetree(self,src,dst,overwrite): - """ move a collection with Depth=infinity """ - return movetree(self,src,dst,overwrite) - - ### COPY handlers - - def copyone(self,src,dst,overwrite): - """ copy one resource with Depth=0 """ - return copyone(self,src,dst,overwrite) - - def copytree(self,src,dst,overwrite): - """ copy a collection with Depth=infinity """ - return copytree(self,src,dst,overwrite) - - - ### low level copy methods (you only need these for method 2) - def copy(self,src,dst): - """ copy a resource with depth==0 - - You don't need to bother about overwrite or not. - This has been done already. - - return a success code or raise an exception if something fails - """ - return 201 - - - def copycol(self,src,dst): - """ copy a resource with depth==infinity - - You don't need to bother about overwrite or not. - This has been done already. - - return a success code or raise an exception if something fails - """ - return 201 - - ### some utility functions you need to implement - - def exists(self,uri): - """ return 1 or None depending on if a resource exists """ - return None # no - - def is_collection(self,uri): - """ return 1 or None depending on if a resource is a collection """ - return None # no - diff --git a/addons/document_webdav/DAV/propfind.py b/addons/document_webdav/DAV/propfind.py deleted file mode 100755 index 0fb9c229c03..00000000000 --- a/addons/document_webdav/DAV/propfind.py +++ /dev/null @@ -1,372 +0,0 @@ -#!/usr/bin/env python - -""" - python davserver - Copyright (C) 1999 Christian Scholz (ruebe@aachen.heimat.de) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -""" - - -from xml.dom import ext -from xml.dom.Document import Document - -import sys -import string -import urlparse -import urllib -from StringIO import StringIO - -import utils -from constants import COLLECTION, OBJECT, DAV_PROPS, RT_ALLPROP, RT_PROPNAME, RT_PROP -from errors import * - -def utf8str(st): - if isinstance(st,unicode): - return st.encode('utf8') - else: - return str(st) - -class PROPFIND: - """ parse a propfind xml element and extract props - - It will set the following instance vars: - - request_class : ALLPROP | PROPNAME | PROP - proplist : list of properties - nsmap : map of namespaces - - The list of properties will contain tuples of the form - (element name, ns_prefix, ns_uri) - - - """ - - - def __init__(self,uri,dataclass,depth): - self.request_type=None - self.nsmap={} - self.proplist={} - self.default_ns=None - self.__dataclass=dataclass - self.__depth=str(depth) - self.__uri=uri - self.use_full_urls=True - self.__has_body=None # did we parse a body? - - def read_propfind(self,xml_doc): - self.request_type,self.proplist,self.namespaces=utils.parse_propfind(xml_doc) - - # a violation of the expected logic: client (korganizer) will ask for DAV:resourcetype - # but we also have to return the http://groupdav.org/:resourcetype property! - if self.proplist.has_key('DAV:') and 'resourcetype' in self.proplist['DAV:']: - if not self.proplist.has_key('http://groupdav.org/'): - self.proplist['http://groupdav.org/'] = [] - self.proplist['http://groupdav.org/'].append('resourcetype') - if 'DAV:' in self.namespaces: #TMP - self.namespaces.append('http://groupdav.org/') - - def createResponse(self): - """ create the multistatus response - - This will be delegated to the specific method - depending on which request (allprop, propname, prop) - was found. - - If we get a PROPNAME then we simply return the list with empty - values which we get from the interface class - - If we get an ALLPROP we first get the list of properties and then - we do the same as with a PROP method. - - If the uri doesn't exist, return an xml response with a 404 status - - """ - - if not self.__dataclass.exists(self.__uri): - raise DAV_NotFound("Path %s doesn't exist" % self.__uri) - - if self.request_type==RT_ALLPROP: - return self.create_allprop() - - if self.request_type==RT_PROPNAME: - return self.create_propname() - - if self.request_type==RT_PROP: - return self.create_prop() - - # no body means ALLPROP! - return self.create_allprop() - - def create_propname(self): - """ create a multistatus response for the prop names """ - - dc=self.__dataclass - # create the document generator - doc = Document(None) - ms=doc.createElement("D:multistatus") - ms.setAttribute("xmlns:D","DAV:") - doc.appendChild(ms) - - if self.__depth=="0": - pnames=dc.get_propnames(self.__uri) - re=self.mk_propname_response(self.__uri,pnames,doc) - ms.appendChild(re) - - elif self.__depth=="1": - pnames=dc.get_propnames(self.__uri) - re=self.mk_propname_response(self.__uri,pnames,doc) - ms.appendChild(re) - - for newuri in dc.get_childs(self.__uri): - pnames=dc.get_propnames(newuri) - re=self.mk_propname_response(newuri,pnames,doc) - ms.appendChild(re) - # *** depth=="infinity" - - sfile=StringIO() - ext.PrettyPrint(doc,stream=sfile) - s=sfile.getvalue() - sfile.close() - return s - - def create_allprop(self): - """ return a list of all properties """ - self.proplist={} - self.namespaces=[] - for ns,plist in self.__dataclass.get_propnames(self.__uri).items(): - self.proplist[ns]=plist - self.namespaces.append(ns) - - return self.create_prop() - - def create_prop(self): - """ handle a request - - This will - - 1. set up the -Framework - - 2. read the property values for each URI - (which is dependant on the Depth header) - This is done by the get_propvalues() method. - - 3. For each URI call the append_result() method - to append the actual -Tag to the result - document. - - We differ between "good" properties, which have been - assigned a value by the interface class and "bad" - properties, which resulted in an error, either 404 - (Not Found) or 403 (Forbidden). - - """ - - - # create the document generator - doc = Document(None) - ms=doc.createElement("D:multistatus") - ms.setAttribute("xmlns:D","DAV:") - doc.appendChild(ms) - - if self.__depth=="0": - gp,bp=self.get_propvalues(self.__uri) - res=self.mk_prop_response(self.__uri,gp,bp,doc) - ms.appendChild(res) - - elif self.__depth=="1": - gp,bp=self.get_propvalues(self.__uri) - res=self.mk_prop_response(self.__uri,gp,bp,doc) - ms.appendChild(res) - - try: - for newuri in self.__dataclass.get_childs(self.__uri): - gp,bp=self.get_propvalues(newuri) - res=self.mk_prop_response(newuri,gp,bp,doc) - ms.appendChild(res) - except DAV_NotFound: - # If no children, never mind. - pass - - sfile=StringIO() - ext.PrettyPrint(doc,stream=sfile) - s=sfile.getvalue() - sfile.close() - return s - - - def mk_propname_response(self,uri,propnames,doc): - """ make a new result element for a PROPNAME request - - This will simply format the propnames list. - propnames should have the format {NS1 : [prop1, prop2, ...], NS2: ...} - - """ - re=doc.createElement("D:response") - - # write href information - href=doc.createElement("D:href") - if self.use_full_urls: - huri=doc.createTextNode(uri) - else: - uparts=urlparse.urlparse(uri) - fileloc=uparts[2] - huri=doc.createTextNode(urllib.quote(fileloc.encode('utf8'))) - href.appendChild(huri) - re.appendChild(href) - - ps=doc.createElement("D:propstat") - nsnum=0 - - for ns,plist in propnames.items(): - # write prop element - pr=doc.createElement("D:prop") - nsp="ns"+str(nsnum) - pr.setAttribute("xmlns:"+nsp,ns) - nsnum=nsnum+1 - - # write propertynames - for p in plist: - pe=doc.createElement(nsp+":"+p) - pr.appendChild(pe) - - ps.appendChild(pr) - - re.appendChild(ps) - - return re - - def mk_prop_response(self,uri,good_props,bad_props,doc): - """ make a new result element - - We differ between the good props and the bad ones for - each generating an extra -Node (for each error - one, that means). - - """ - re=doc.createElement("D:response") - # append namespaces to response - nsnum=0 - for nsname in self.namespaces: - re.setAttribute("xmlns:ns"+str(nsnum),nsname) - nsnum=nsnum+1 - - # write href information - href=doc.createElement("D:href") - if self.use_full_urls: - huri=doc.createTextNode(uri) - else: - uparts=urlparse.urlparse(uri) - fileloc=uparts[2] - huri=doc.createTextNode(urllib.quote(fileloc.encode('utf8'))) - href.appendChild(huri) - re.appendChild(href) - - # write good properties - if good_props and len(good_props.items()): - ps=doc.createElement("D:propstat") - - gp=doc.createElement("D:prop") - for ns in good_props.keys(): - ns_prefix="ns"+str(self.namespaces.index(ns))+":" - for p,v in good_props[ns].items(): - pe=doc.createElement(ns_prefix+str(p)) - if v == None: - pass - elif ns=='DAV:' and p=="resourcetype": - if v == 1: - ve=doc.createElement("D:collection") - pe.appendChild(ve) - elif isinstance(v,tuple) and v[1] == ns: - ve=doc.createElement(ns_prefix+v[0]) - pe.appendChild(ve) - else: - ve=doc.createTextNode(utf8str(v)) - pe.appendChild(ve) - - gp.appendChild(pe) - if gp.hasChildNodes(): - re.appendChild(ps) - ps.appendChild(gp) - s=doc.createElement("D:status") - t=doc.createTextNode("HTTP/1.1 200 OK") - s.appendChild(t) - ps.appendChild(s) - re.appendChild(ps) - - # now write the errors! - if len(bad_props.items()): - - # write a propstat for each error code - for ecode in bad_props.keys(): - ps=doc.createElement("D:propstat") - re.appendChild(ps) - bp=doc.createElement("D:prop") - ps.appendChild(bp) - - for ns in bad_props[ecode].keys(): - ns_prefix="ns"+str(self.namespaces.index(ns))+":" - - for p in bad_props[ecode][ns]: - pe=doc.createElement(ns_prefix+str(p)) - bp.appendChild(pe) - - s=doc.createElement("D:status") - t=doc.createTextNode(utils.gen_estring(ecode)) - s.appendChild(t) - ps.appendChild(s) - re.appendChild(ps) - - # return the new response element - return re - - def get_propvalues(self,uri): - """ create lists of property values for an URI - - We create two lists for an URI: the properties for - which we found a value and the ones for which we - only got an error, either because they haven't been - found or the user is not allowed to read them. - - """ - good_props={} - bad_props={} - - for (ns,plist) in self.proplist.items(): - good_props[ns]={} - bad_props={} - ec = 0 - for prop in plist: - try: - ec = 0 - r=self.__dataclass.get_prop(uri,ns,prop) - good_props[ns][prop]=r - except DAV_Error, error_code: - ec=error_code[0] - - # ignore props with error_code if 0 (invisible) - if ec==0: continue - - if bad_props.has_key(ec): - if bad_props[ec].has_key(ns): - bad_props[ec][ns].append(prop) - else: - bad_props[ec][ns]=[prop] - else: - bad_props[ec]={ns:[prop]} - - return good_props, bad_props - diff --git a/addons/document_webdav/DAV/status.py b/addons/document_webdav/DAV/status.py deleted file mode 100644 index 62cb323c4fb..00000000000 --- a/addons/document_webdav/DAV/status.py +++ /dev/null @@ -1,31 +0,0 @@ -""" - -status codes for DAV services - - -""" - - -STATUS_CODES={ - 102: "Processing", - 200: "Ok", - 201: "Created", - 204: "No Content", - 207: "Multi-Status", - 201: "Created", - 400: "Bad Request", - 403: "Forbidden", - 404: "Not Found", - 405: "Method Not Allowed", - 409: "Conflict", - 412: "Precondition failed", - 423: "Locked", - 415: "Unsupported Media Type", - 507: "Insufficient Storage", - 422: "Unprocessable Entity", - 423: "Locked", - 424: "Failed Dependency", - 502: "Bad Gateway", - 507: "Insufficient Storage", - 999: "Some error in Create Method please check the data of create method" -} diff --git a/addons/document_webdav/DAV/utils.py b/addons/document_webdav/DAV/utils.py deleted file mode 100755 index c4bb4d1a4c0..00000000000 --- a/addons/document_webdav/DAV/utils.py +++ /dev/null @@ -1,160 +0,0 @@ -#!/usr/bin/env python - -""" - -UTILITIES - -- parse a propfind request body into a list of props - -""" - -from xml.dom import ext -from xml.dom.Document import Document -from xml.dom.ext.reader import PyExpat -from xml.dom import Node -from xml.dom import NodeIterator, NodeFilter - -from string import lower, split, atoi, joinfields -import urlparse -from StringIO import StringIO - -from constants import RT_ALLPROP, RT_PROPNAME, RT_PROP -from status import STATUS_CODES - -VERSION = '0.6' -AUTHOR = 'Simon Pamies ' - - -def gen_estring(ecode): - """ generate an error string from the given code """ - ec=atoi(str(ecode)) - if STATUS_CODES.has_key(ec): - return "HTTP/1.1 %s %s" %(ec,STATUS_CODES[ec]) - else: - return "HTTP/1.1 %s" %(ec) - -def parse_propfind(xml_doc): - """ parse an propfind xml file and return a list of props - - returns: - - request_type -- ALLPROP, PROPNAME, PROP - proplist -- list of properties found - namespaces -- list of namespaces found - - """ - doc = PyExpat.Reader().fromString(xml_doc) - snit = doc.createNodeIterator(doc, NodeFilter.NodeFilter.SHOW_ELEMENT, None, None) - - request_type=None - props={} - namespaces=[] - - while 1: - curr_elem = snit.nextNode() - if not curr_elem: break - ename=fname=lower(curr_elem.nodeName) - if ":" in fname: - ename=split(fname,":")[1] - if ename=="prop": request_type=RT_PROP; continue - if ename=="propfind": continue - if ename=="allprop": request_type=RT_ALLPROP; continue - if ename=="propname": request_type=RT_PROPNAME; continue - - # rest should be names of attributes - - ns = curr_elem.namespaceURI - if props.has_key(ns): - props[ns].append(ename) - else: - props[ns]=[ename] - namespaces.append(ns) - - return request_type,props,namespaces - - -def create_treelist(dataclass,uri): - """ create a list of resources out of a tree - - This function is used for the COPY, MOVE and DELETE methods - - uri - the root of the subtree to flatten - - It will return the flattened tree as list - - """ - queue=[uri] - list=[uri] - while len(queue): - element=queue[-1] - if dataclass.is_collection(element): - childs=dataclass.get_childs(element) - else: - childs=[] - if len(childs): - list=list+childs - # update queue - del queue[-1] - if len(childs): - queue=queue+childs - return list - -def is_prefix(uri1,uri2): - """ returns 1 of uri1 is a prefix of uri2 """ - if uri2[:len(uri1)]==uri1: - return 1 - else: - return None - -def quote_uri(uri): - """ quote an URL but not the protocol part """ - import urlparse - import urllib - - up=urlparse.urlparse(uri) - np=urllib.quote(up[2]) - return urlparse.urlunparse((up[0],up[1],np,up[3],up[4],up[5])) - -def get_uriparentpath(uri): - """ extract the uri path and remove the last element """ - up=urlparse.urlparse(uri) - return joinfields(split(up[2],"/")[:-1],"/") - -def get_urifilename(uri): - """ extract the uri path and return the last element """ - up=urlparse.urlparse(uri) - return split(up[2],"/")[-1] - -def get_parenturi(uri): - """ return the parent of the given resource""" - up=urlparse.urlparse(uri) - np=joinfields(split(up[2],"/")[:-1],"/") - return urlparse.urlunparse((up[0],up[1],np,up[3],up[4],up[5])) - -### XML utilities - -def make_xmlresponse(result): - """ construct a response from a dict of uri:error_code elements """ - doc = Document(None) - ms=doc.createElement("D:multistatus") - ms.setAttribute("xmlns:D","DAV:") - doc.appendChild(ms) - - for el,ec in result.items(): - re=doc.createElement("D:response") - hr=doc.createElement("D:href") - st=doc.createElement("D:status") - huri=doc.createTextNode(quote_uri(el)) - t=doc.createTextNode(gen_estring(ec)) - st.appendChild(t) - hr.appendChild(huri) - re.appendChild(hr) - re.appendChild(st) - ms.appendChild(re) - - sfile=StringIO() - ext.PrettyPrint(doc,stream=sfile) - s=sfile.getvalue() - sfile.close() - return s - diff --git a/addons/document_webdav/dav_fs.py b/addons/document_webdav/dav_fs.py index 1acbfd7d5ec..9ef91e0f9a6 100644 --- a/addons/document_webdav/dav_fs.py +++ b/addons/document_webdav/dav_fs.py @@ -59,67 +59,47 @@ class tinydav_handler(dav_interface): """ This class models a Tiny ERP interface for the DAV server """ - PROPS={'DAV:': dav_interface.PROPS['DAV:'], } + PROPS={'DAV:': dav_interface.PROPS['DAV:'],} - M_NS={ "DAV:" : dav_interface.M_NS['DAV:'], } + M_NS={ "DAV:" : dav_interface.M_NS['DAV:'],} - def __init__(self, parent, verbose=False): + def __init__(self, parent, verbose=False): self.db_name = False self.directory_id=False self.db_name_list=[] self.parent = parent self.baseuri = parent.baseuri - - def get_propnames(self,uri): - props = self.PROPS - self.parent.log_message('get propnames: %s' % uri) - if uri[-1]=='/':uri=uri[:-1] - cr, uid, pool, dbname, uri2 = self.get_cr(uri) - if not dbname: - cr.close() - return props - node = self.uri2object(cr,uid,pool, uri2) - if node: - props.update(node.get_dav_props(cr)) - cr.close() - return props - - def get_prop(self,uri,ns,propname): - """ return the value of a given property - - uri -- uri of the object to get the property of - ns -- namespace of the property - pname -- name of the property - """ - if self.M_NS.has_key(ns): - return dav_interface.get_prop(self,uri,ns,propname) - - if uri[-1]=='/':uri=uri[:-1] - cr, uid, pool, dbname, uri2 = self.get_cr(uri) - if not dbname: - cr.close() - raise DAV_NotFound - node = self.uri2object(cr,uid,pool, uri2) - if not node: - cr.close() - raise DAV_NotFound - res = node.get_dav_eprop(cr,ns,propname) - cr.close() - return res - -# -# def get_db(self,uri): -# names=self.uri2local(uri).split('/') -# self.db_name=False -# if len(names) > 1: -# self.db_name=self.uri2local(uri).split('/')[1] -# if self.db_name=='': -# raise Exception,'Plese specify Database name in folder' -# return self.db_name -# - - def later_get_db_from_path(self,path): - return "aaa" + self.verbose = verbose + + def get_propnames(self,uri): + props = self.PROPS + return props + + def _get_dav_lockdiscovery(self, uri): + raise DAV_NotFound + + def _get_dav_supportedlock(self, uri): + raise DAV_NotFound + def get_prop(self,uri,ns,propname): + """ return the value of a given property + + uri -- uri of the object to get the property of + ns -- namespace of the property + pname -- name of the property + """ + if self.M_NS.has_key(ns): + return dav_interface.get_prop(self,uri,ns,propname) + raise DAV_NotFound + + def get_db(self,uri): + names=self.uri2local(uri).split('/') + self.db_name=False + if len(names) > 1: + self.db_name=self.uri2local(uri).split('/')[1] + if self.db_name=='': + raise Exception,'Plese specify Database name in folder' + return self.db_name + def urijoin(self,*ajoin): """ Return the base URI of this request, or even join it with the @@ -130,7 +110,7 @@ class tinydav_handler(dav_interface): @memoize(4) def db_list(self): s = netsvc.ExportService.getService('db') - result = s.list() + result = s.exp_list() self.db_name_list=[] for db_name in result: db = pooler.get_db_only(db_name) @@ -146,16 +126,17 @@ class tinydav_handler(dav_interface): """ return the child objects as self.baseuris for the given URI """ self.parent.log_message('get childs: %s' % uri) if uri[-1]=='/':uri=uri[:-1] - cr, uid, pool, dbname, uri2 = self.get_cr(uri) + cr, uid, pool, dbname, uri2 = self.get_cr(uri) - if not dbname: - s = netsvc.ExportService.getService('db') - cr.close() - return map(lambda x: self.urijoin(x), self.db_list()) + if not dbname: + if cr: cr.close() + res = map(lambda x: self.urijoin(x), self.db_list()) + return res result = [] node = self.uri2object(cr,uid,pool, uri2[:]) + if not node: - cr.close() + if cr: cr.close() raise DAV_NotFound(uri2) else: fp = node.full_path() @@ -165,12 +146,13 @@ class tinydav_handler(dav_interface): else: fp = None for d in node.children(cr): - self.parent.log_message('child: %s' % d.path) + self.parent.log_message('child: %s' % d.path) if fp: result.append( self.urijoin(dbname,fp,d.path) ) else: result.append( self.urijoin(dbname,d.path) ) - cr.close() + if cr: cr.close() + return result def uri2local(self, uri): @@ -183,24 +165,28 @@ class tinydav_handler(dav_interface): # # pos: -1 to get the parent of the uri # - def get_cr(self, uri): + def get_cr(self, uri): pdb = self.parent.auth_proxy.last_auth reluri = self.uri2local(uri) try: - dbname = reluri.split('/')[2] + dbname = reluri.split('/')[1] except: - dbname = False + dbname = False if not dbname: return None, None, None, False, None if not pdb and dbname: # if dbname was in our uri, we should have authenticated # against that. raise Exception("Programming error") - assert pdb == dbname, " %s != %s" %(pdb, dbname) - user, passwd, dbn2, uid = self.parent.auth_proxy.auth_creds[pdb] + #assert pdb == dbname, " %s != %s" %(pdb, dbname) + res = self.parent.auth_proxy.auth_creds.get(dbname, False) + if not res: + self.parent.auth_proxy.checkRequest(self.parent, uri, dbname) + res = self.parent.auth_proxy.auth_creds[dbname] + user, passwd, dbn2, uid = res db,pool = pooler.get_db_and_pool(dbname) cr = db.cursor() - uri2 = reluri.split('/')[3:] + uri2 = reluri.split('/')[2:] return cr, uid, pool, dbname, uri2 def uri2object(self, cr,uid, pool,uri): @@ -208,20 +194,20 @@ class tinydav_handler(dav_interface): return None return pool.get('document.directory').get_object(cr, uid, uri) - def get_data(self,uri): + def get_data(self,uri): self.parent.log_message('GET: %s' % uri) if uri[-1]=='/':uri=uri[:-1] cr, uid, pool, dbname, uri2 = self.get_cr(uri) try: if not dbname: raise DAV_Error, 409 - node = self.uri2object(cr,uid,pool, uri2) + node = self.uri2object(cr,uid,pool, uri2) if not node: raise DAV_NotFound(uri2) try: datas = node.get_data(cr) except TypeError,e: - import traceback + import traceback self.parent.log_error("GET typeError: %s", str(e)) self.parent.log_message("Exc: %s",traceback.format_exc()) raise DAV_Forbidden @@ -235,11 +221,11 @@ class tinydav_handler(dav_interface): raise DAV_Error, 409 return datas finally: - cr.close() + if cr: cr.close() @memoize(CACHE_SIZE) def _get_dav_resourcetype(self,uri): - """ return type of object """ + """ return type of object """ self.parent.log_message('get RT: %s' % uri) if uri[-1]=='/':uri=uri[:-1] cr, uid, pool, dbname, uri2 = self.get_cr(uri) @@ -253,7 +239,7 @@ class tinydav_handler(dav_interface): return COLLECTION return OBJECT finally: - cr.close() + if cr: cr.close() def _get_dav_displayname(self,uri): self.parent.log_message('get DN: %s' % uri) @@ -271,14 +257,14 @@ class tinydav_handler(dav_interface): @memoize(CACHE_SIZE) def _get_dav_getcontentlength(self,uri): - """ return the content length of an object """ + """ return the content length of an object """ self.parent.log_message('get length: %s' % uri) if uri[-1]=='/':uri=uri[:-1] result = 0 - cr, uid, pool, dbname, uri2 = self.get_cr(uri) + cr, uid, pool, dbname, uri2 = self.get_cr(uri) if not dbname: - cr.close() - return '0' + if cr: cr.close() + return str(result) node = self.uri2object(cr, uid, pool, uri2) if not node: cr.close() @@ -311,9 +297,9 @@ class tinydav_handler(dav_interface): if uri[-1]=='/':uri=uri[:-1] today = time.time() cr, uid, pool, dbname, uri2 = self.get_cr(uri) - try: - if not dbname: - return today + if not dbname: + return today + try: node = self.uri2object(cr,uid,pool, uri2) if not node: raise DAV_NotFound(uri2) @@ -322,36 +308,35 @@ class tinydav_handler(dav_interface): else: return today finally: - cr.close() + if cr: cr.close() @memoize(CACHE_SIZE) def get_creationdate(self,uri): - """ return the last modified date of the object """ - + """ return the last modified date of the object """ if uri[-1]=='/':uri=uri[:-1] cr, uid, pool, dbname, uri2 = self.get_cr(uri) - try: - if not dbname: - raise DAV_Error, 409 + if not dbname: + raise DAV_Error, 409 + try: node = self.uri2object(cr,uid,pool, uri2) if not node: - raise DAV_NotFound(uri2) + raise DAV_NotFound(uri2) if node.create_date: - result = time.strptime(node.create_date,'%Y-%m-%d %H:%M:%S') + result = time.mktime(time.strptime(node.create_date,'%Y-%m-%d %H:%M:%S')) else: - result = time.gmtime() + result = time.time() return result finally: - cr.close() + if cr: cr.close() @memoize(CACHE_SIZE) def _get_dav_getcontenttype(self,uri): self.parent.log_message('get contenttype: %s' % uri) if uri[-1]=='/':uri=uri[:-1] cr, uid, pool, dbname, uri2 = self.get_cr(uri) - try: - if not dbname: - return 'httpd/unix-directory' + if not dbname: + return 'httpd/unix-directory' + try: node = self.uri2object(cr,uid,pool, uri2) if not node: raise DAV_NotFound(uri2) @@ -359,8 +344,8 @@ class tinydav_handler(dav_interface): return result #raise DAV_NotFound, 'Could not find %s' % path finally: - cr.close() - + if cr: cr.close() + def mkcol(self,uri): """ create a new collection """ self.parent.log_message('MKCOL: %s' % uri) @@ -401,7 +386,7 @@ class tinydav_handler(dav_interface): def put(self,uri,data,content_type=None): """ put the object into the filesystem """ - self.parent.log_message('Putting %s (%d), %s'%( misc.ustr(uri), len(data), content_type)) + self.parent.log_message('Putting %s (%d), %s'%( misc.ustr(uri), data and len(data) or 0, content_type)) parent='/'.join(uri.split('/')[:-1]) cr, uid, pool,dbname, uri2 = self.get_cr(uri) if not dbname: @@ -633,7 +618,7 @@ class tinydav_handler(dav_interface): result = False cr, uid, pool,dbname, uri2 = self.get_cr(uri) if not dbname: - cr.close() + if cr: cr.close() return True try: node = self.uri2object(cr,uid,pool, uri2) diff --git a/addons/document_webdav/webdav_server.py b/addons/document_webdav/webdav_server.py index 15e8e030824..f2c129dd608 100644 --- a/addons/document_webdav/webdav_server.py +++ b/addons/document_webdav/webdav_server.py @@ -28,10 +28,113 @@ import netsvc +import tools from dav_fs import tinydav_handler from tools.config import config from DAV.WebDAVServer import DAVRequestHandler from service.websrv_lib import HTTPDir,FixSendError +from DAV.propfind import PROPFIND + +import xml.dom.minidom +domimpl = xml.dom.minidom.getDOMImplementation() +import urlparse +import urllib +from DAV import utils + +super_mk_prop_response = PROPFIND.mk_prop_response +def mk_prop_response(self,uri,good_props,bad_props,doc): + """ make a new result element + + We differ between the good props and the bad ones for + each generating an extra -Node (for each error + one, that means). + + """ + re=doc.createElement("D:response") + # append namespaces to response + nsnum=0 + for nsname in self.namespaces: + re.setAttribute("xmlns:ns"+str(nsnum),nsname) + nsnum=nsnum+1 + + # write href information + uparts=urlparse.urlparse(uri) + fileloc=uparts[2] + href=doc.createElement("D:href") + huri=doc.createTextNode(uparts[0]+'://'+'/'.join(uparts[1:2]) + urllib.quote(fileloc)) + href.appendChild(huri) + re.appendChild(href) + + # write good properties + ps=doc.createElement("D:propstat") + if good_props: + re.appendChild(ps) + + gp=doc.createElement("D:prop") + for ns in good_props.keys(): + ns_prefix="ns"+str(self.namespaces.index(ns))+":" + for p,v in good_props[ns].items(): + if not v: + pass + pe=doc.createElement(ns_prefix+str(p)) + if hasattr(v, '__class__') and v.__class__.__name__ == 'Element': + pe.appendChild(v) + else: + if p=="resourcetype": + if v==1: + ve=doc.createElement("D:collection") + pe.appendChild(ve) + else: + ve=doc.createTextNode(tools.ustr(v)) + pe.appendChild(ve) + + gp.appendChild(pe) + + ps.appendChild(gp) + s=doc.createElement("D:status") + t=doc.createTextNode("HTTP/1.1 200 OK") + s.appendChild(t) + ps.appendChild(s) + re.appendChild(ps) + + # now write the errors! + if len(bad_props.items()): + + # write a propstat for each error code + for ecode in bad_props.keys(): + ps=doc.createElement("D:propstat") + re.appendChild(ps) + bp=doc.createElement("D:prop") + ps.appendChild(bp) + + for ns in bad_props[ecode].keys(): + ns_prefix="ns"+str(self.namespaces.index(ns))+":" + + for p in bad_props[ecode][ns]: + pe=doc.createElement(ns_prefix+str(p)) + bp.appendChild(pe) + + s=doc.createElement("D:status") + t=doc.createTextNode(utils.gen_estring(ecode)) + s.appendChild(t) + ps.appendChild(s) + re.appendChild(ps) + + # return the new response element + return re + + +PROPFIND.mk_prop_response = mk_prop_response + +def OpenDAVConfig(**kw): + class OpenDAV: + def __init__(self, **kw): + self.__dict__.update(**kw) + + class Config: + DAV = OpenDAV(**kw) + + return Config() class DAVHandler(FixSendError,DAVRequestHandler): verbose = False @@ -43,16 +146,24 @@ class DAVHandler(FixSendError,DAVRequestHandler): netsvc.Logger().notifyChannel("webdav",netsvc.LOG_DEBUG,message) def handle(self): - pass + self._init_buffer() def finish(self): pass + def get_db_from_path(self, uri): + if uri or uri == '/': + dbs = self.IFACE_CLASS.db_list() + res = len(dbs) and dbs[0] or False + else: + res = self.IFACE_CLASS.get_db(uri) + return res + def setup(self): - davpath = '/'+config.get_misc('webdav','vdir','webdav')+'/' - self.baseuri = "http://%s:%d%s"% (self.server.server_name,self.server.server_port,davpath) - self.IFACE_CLASS = tinydav_handler(self) - pass + davpath = '/'+config.get_misc('webdav','vdir','webdav') + self.baseuri = "http://%s:%d/"% (self.server.server_name,self.server.server_port) + self.IFACE_CLASS = tinydav_handler(self, self.verbose) + def log_message(self, format, *args): netsvc.Logger().notifyChannel('webdav',netsvc.LOG_DEBUG_RPC,format % args) @@ -62,14 +173,23 @@ class DAVHandler(FixSendError,DAVRequestHandler): try: - from service.http_server import reg_http_service,OpenERPAuthProvider + from service.http_server import reg_http_service,OpenERPAuthProvider + if (config.get_misc('webdav','enable',True)): - davpath = '/'+config.get_misc('webdav','vdir','webdav')+'/' + directory = '/'+config.get_misc('webdav','vdir','webdav') handler = DAVHandler - handler.verbose = config.get_misc('webdav','verbose',True) + verbose = config.get_misc('webdav','verbose',True) handler.debug = config.get_misc('webdav','debug',True) - reg_http_service(HTTPDir(davpath,DAVHandler,OpenERPAuthProvider())) - netsvc.Logger().notifyChannel('webdav',netsvc.LOG_INFO,"WebDAV service registered at path: %s/ "% davpath) + _dc = { 'verbose' : verbose, + 'directory' : directory, + 'lockemulation' : False, + + } + + conf = OpenDAVConfig(**_dc) + handler._config = conf + reg_http_service(HTTPDir(directory,DAVHandler,OpenERPAuthProvider())) + netsvc.Logger().notifyChannel('webdav',netsvc.LOG_INFO,"WebDAV service registered at path: %s/ "% directory) except Exception, e: logger = netsvc.Logger() logger.notifyChannel('webdav', netsvc.LOG_ERROR, 'Cannot launch webdav: %s' % e) -- cgit v1.2.3 From 565d1a18c737021cde9e0faa7b5718ae04992972 Mon Sep 17 00:00:00 2001 From: "Harry (Open ERP)" Date: Mon, 12 Apr 2010 16:22:00 +0530 Subject: [REF+IMP] caldav bzr revid: hmo@tinyerp.com-20100412105200-c3kvao81ypbh8l0g --- addons/document_webdav/__init__.py | 34 ++++------ addons/document_webdav/dav_fs.py | 39 +++++------ addons/document_webdav/webdav.py | 114 ++++++++++++++++++++++++++++++++ addons/document_webdav/webdav_server.py | 96 +-------------------------- 4 files changed, 146 insertions(+), 137 deletions(-) create mode 100644 addons/document_webdav/webdav.py (limited to 'addons/document_webdav') diff --git a/addons/document_webdav/__init__.py b/addons/document_webdav/__init__.py index 08701e920d2..69312668a74 100644 --- a/addons/document_webdav/__init__.py +++ b/addons/document_webdav/__init__.py @@ -1,29 +1,23 @@ +# -*- coding: utf-8 -*- ############################################################################## # -# Copyright (c) 2004 TINY SPRL. (http://tiny.be) All Rights Reserved. -# Fabien Pinckaers +# OpenERP, Open Source Management Solution +# Copyright (C) 2004-2010 Tiny SPRL (). # -# WARNING: This program as such is intended to be used by professional -# programmers who take the whole responsability of assessing all potential -# consequences resulting from its eventual inadequacies and bugs -# End users who are looking for a ready-to-use solution with commercial -# garantees and support are strongly adviced to contract a Free Software -# Service Company +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. # -# This program is Free Software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. # -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . # ############################################################################## +import webdav import webdav_server diff --git a/addons/document_webdav/dav_fs.py b/addons/document_webdav/dav_fs.py index 9ef91e0f9a6..9be77c50daa 100644 --- a/addons/document_webdav/dav_fs.py +++ b/addons/document_webdav/dav_fs.py @@ -1,32 +1,23 @@ -# -*- encoding: utf-8 -*- +# -*- coding: utf-8 -*- ############################################################################## # -# Copyright (c) 2004 TINY SPRL. (http://tiny.be) All Rights Reserved. -# Fabien Pinckaers +# OpenERP, Open Source Management Solution +# Copyright (C) 2004-2010 Tiny SPRL (). # -# WARNING: This program as such is intended to be used by professional -# programmers who take the whole responsability of assessing all potential -# consequences resulting from its eventual inadequacies and bugs -# End users who are looking for a ready-to-use solution with commercial -# garantees and support are strongly adviced to contract a Free Software -# Service Company +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. # -# This program is Free Software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. # -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . # ############################################################################## - import pooler import base64 @@ -55,9 +46,9 @@ CACHE_SIZE=20000 urlparse.uses_netloc.append('webdav') urlparse.uses_netloc.append('webdavs') -class tinydav_handler(dav_interface): +class openerp_dav_handler(dav_interface): """ - This class models a Tiny ERP interface for the DAV server + This class models a OpenERP interface for the DAV server """ PROPS={'DAV:': dav_interface.PROPS['DAV:'],} diff --git a/addons/document_webdav/webdav.py b/addons/document_webdav/webdav.py new file mode 100644 index 00000000000..6e816c35e10 --- /dev/null +++ b/addons/document_webdav/webdav.py @@ -0,0 +1,114 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2004-2010 Tiny SPRL (). +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +import xml.dom.minidom +domimpl = xml.dom.minidom.getDOMImplementation() +import urlparse +import urllib +from DAV import utils +from DAV.propfind import PROPFIND + + +super_mk_prop_response = PROPFIND.mk_prop_response +def mk_prop_response(self,uri,good_props,bad_props,doc): + """ make a new result element + + We differ between the good props and the bad ones for + each generating an extra -Node (for each error + one, that means). + + """ + re=doc.createElement("D:response") + # append namespaces to response + nsnum=0 + for nsname in self.namespaces: + re.setAttribute("xmlns:ns"+str(nsnum),nsname) + nsnum=nsnum+1 + + # write href information + uparts=urlparse.urlparse(uri) + fileloc=uparts[2] + href=doc.createElement("D:href") + huri=doc.createTextNode(uparts[0]+'://'+'/'.join(uparts[1:2]) + urllib.quote(fileloc)) + href.appendChild(huri) + re.appendChild(href) + + # write good properties + ps=doc.createElement("D:propstat") + if good_props: + re.appendChild(ps) + + gp=doc.createElement("D:prop") + for ns in good_props.keys(): + ns_prefix="ns"+str(self.namespaces.index(ns))+":" + for p,v in good_props[ns].items(): + if not v: + pass + pe=doc.createElement(ns_prefix+str(p)) + if hasattr(v, '__class__') and v.__class__.__name__ == 'Element': + pe.appendChild(v) + else: + if p=="resourcetype": + if v==1: + ve=doc.createElement("D:collection") + pe.appendChild(ve) + else: + ve=doc.createTextNode(tools.ustr(v)) + pe.appendChild(ve) + + gp.appendChild(pe) + + ps.appendChild(gp) + s=doc.createElement("D:status") + t=doc.createTextNode("HTTP/1.1 200 OK") + s.appendChild(t) + ps.appendChild(s) + re.appendChild(ps) + + # now write the errors! + if len(bad_props.items()): + + # write a propstat for each error code + for ecode in bad_props.keys(): + ps=doc.createElement("D:propstat") + re.appendChild(ps) + bp=doc.createElement("D:prop") + ps.appendChild(bp) + + for ns in bad_props[ecode].keys(): + ns_prefix="ns"+str(self.namespaces.index(ns))+":" + + for p in bad_props[ecode][ns]: + pe=doc.createElement(ns_prefix+str(p)) + bp.appendChild(pe) + + s=doc.createElement("D:status") + t=doc.createTextNode(utils.gen_estring(ecode)) + s.appendChild(t) + ps.appendChild(s) + re.appendChild(ps) + + # return the new response element + return re + + +PROPFIND.mk_prop_response = mk_prop_response + diff --git a/addons/document_webdav/webdav_server.py b/addons/document_webdav/webdav_server.py index f2c129dd608..6cda2d172ef 100644 --- a/addons/document_webdav/webdav_server.py +++ b/addons/document_webdav/webdav_server.py @@ -29,102 +29,11 @@ import netsvc import tools -from dav_fs import tinydav_handler +from dav_fs import openerp_dav_handler from tools.config import config from DAV.WebDAVServer import DAVRequestHandler from service.websrv_lib import HTTPDir,FixSendError -from DAV.propfind import PROPFIND -import xml.dom.minidom -domimpl = xml.dom.minidom.getDOMImplementation() -import urlparse -import urllib -from DAV import utils - -super_mk_prop_response = PROPFIND.mk_prop_response -def mk_prop_response(self,uri,good_props,bad_props,doc): - """ make a new result element - - We differ between the good props and the bad ones for - each generating an extra -Node (for each error - one, that means). - - """ - re=doc.createElement("D:response") - # append namespaces to response - nsnum=0 - for nsname in self.namespaces: - re.setAttribute("xmlns:ns"+str(nsnum),nsname) - nsnum=nsnum+1 - - # write href information - uparts=urlparse.urlparse(uri) - fileloc=uparts[2] - href=doc.createElement("D:href") - huri=doc.createTextNode(uparts[0]+'://'+'/'.join(uparts[1:2]) + urllib.quote(fileloc)) - href.appendChild(huri) - re.appendChild(href) - - # write good properties - ps=doc.createElement("D:propstat") - if good_props: - re.appendChild(ps) - - gp=doc.createElement("D:prop") - for ns in good_props.keys(): - ns_prefix="ns"+str(self.namespaces.index(ns))+":" - for p,v in good_props[ns].items(): - if not v: - pass - pe=doc.createElement(ns_prefix+str(p)) - if hasattr(v, '__class__') and v.__class__.__name__ == 'Element': - pe.appendChild(v) - else: - if p=="resourcetype": - if v==1: - ve=doc.createElement("D:collection") - pe.appendChild(ve) - else: - ve=doc.createTextNode(tools.ustr(v)) - pe.appendChild(ve) - - gp.appendChild(pe) - - ps.appendChild(gp) - s=doc.createElement("D:status") - t=doc.createTextNode("HTTP/1.1 200 OK") - s.appendChild(t) - ps.appendChild(s) - re.appendChild(ps) - - # now write the errors! - if len(bad_props.items()): - - # write a propstat for each error code - for ecode in bad_props.keys(): - ps=doc.createElement("D:propstat") - re.appendChild(ps) - bp=doc.createElement("D:prop") - ps.appendChild(bp) - - for ns in bad_props[ecode].keys(): - ns_prefix="ns"+str(self.namespaces.index(ns))+":" - - for p in bad_props[ecode][ns]: - pe=doc.createElement(ns_prefix+str(p)) - bp.appendChild(pe) - - s=doc.createElement("D:status") - t=doc.createTextNode(utils.gen_estring(ecode)) - s.appendChild(t) - ps.appendChild(s) - re.appendChild(ps) - - # return the new response element - return re - - -PROPFIND.mk_prop_response = mk_prop_response def OpenDAVConfig(**kw): class OpenDAV: @@ -136,6 +45,7 @@ def OpenDAVConfig(**kw): return Config() + class DAVHandler(FixSendError,DAVRequestHandler): verbose = False @@ -162,7 +72,7 @@ class DAVHandler(FixSendError,DAVRequestHandler): def setup(self): davpath = '/'+config.get_misc('webdav','vdir','webdav') self.baseuri = "http://%s:%d/"% (self.server.server_name,self.server.server_port) - self.IFACE_CLASS = tinydav_handler(self, self.verbose) + self.IFACE_CLASS = openerp_dav_handler(self, self.verbose) def log_message(self, format, *args): -- cgit v1.2.3 From 37a0b05a170d0fe454f27cfabe8689d0a08ae552 Mon Sep 17 00:00:00 2001 From: "Harry (Open ERP)" Date: Mon, 12 Apr 2010 17:15:51 +0530 Subject: [REF] caldav bzr revid: hmo@tinyerp.com-20100412114551-pkrd135oxul8pw1u --- addons/document_webdav/webdav.py | 1 + 1 file changed, 1 insertion(+) (limited to 'addons/document_webdav') diff --git a/addons/document_webdav/webdav.py b/addons/document_webdav/webdav.py index 6e816c35e10..b69c21d62ee 100644 --- a/addons/document_webdav/webdav.py +++ b/addons/document_webdav/webdav.py @@ -25,6 +25,7 @@ import urlparse import urllib from DAV import utils from DAV.propfind import PROPFIND +import tools super_mk_prop_response = PROPFIND.mk_prop_response -- cgit v1.2.3 From f2311d256ffe78304388988024ce9b8b3cc4dfef Mon Sep 17 00:00:00 2001 From: "Harry (Open ERP)" Date: Wed, 14 Apr 2010 13:06:16 +0530 Subject: [REF+IMP] caldav bzr revid: hmo@tinyerp.com-20100414073616-i84h1e197yswuv0v --- addons/document_webdav/dav_fs.py | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) (limited to 'addons/document_webdav') diff --git a/addons/document_webdav/dav_fs.py b/addons/document_webdav/dav_fs.py index 9be77c50daa..41a65c73bfb 100644 --- a/addons/document_webdav/dav_fs.py +++ b/addons/document_webdav/dav_fs.py @@ -63,7 +63,17 @@ class openerp_dav_handler(dav_interface): self.verbose = verbose def get_propnames(self,uri): - props = self.PROPS + props = self.PROPS + self.parent.log_message('get propnames: %s' % uri) + if uri[-1]=='/':uri=uri[:-1] + cr, uid, pool, dbname, uri2 = self.get_cr(uri) + if not dbname: + cr.close() + return props + node = self.uri2object(cr, uid, pool, uri2) + if node: + props.update(node.get_dav_props(cr)) + cr.close() return props def _get_dav_lockdiscovery(self, uri): @@ -71,7 +81,8 @@ class openerp_dav_handler(dav_interface): def _get_dav_supportedlock(self, uri): raise DAV_NotFound - def get_prop(self,uri,ns,propname): + + def get_prop(self, uri, ns, propname): """ return the value of a given property uri -- uri of the object to get the property of @@ -79,8 +90,19 @@ class openerp_dav_handler(dav_interface): pname -- name of the property """ if self.M_NS.has_key(ns): - return dav_interface.get_prop(self,uri,ns,propname) - raise DAV_NotFound + return dav_interface.get_prop(self,uri,ns,propname) + if uri[-1]=='/':uri=uri[:-1] + cr, uid, pool, dbname, uri2 = self.get_cr(uri) + if not dbname: + cr.close() + raise DAV_NotFound + node = self.uri2object(cr, uid, pool, uri2) + if not node: + cr.close() + raise DAV_NotFound + res = node.get_dav_eprop(cr,ns,propname) + cr.close() + return res def get_db(self,uri): names=self.uri2local(uri).split('/') -- cgit v1.2.3 From 013abc77091ed4144d95dadfad7655fa8c5c80fe Mon Sep 17 00:00:00 2001 From: "Harry (Open ERP)" Date: Wed, 14 Apr 2010 17:19:40 +0530 Subject: [FIX] document: MKCOL bzr revid: hmo@tinyerp.com-20100414114940-jkhi3ds5eskjxhej --- addons/document_webdav/dav_fs.py | 40 ++++++++++------------------------------ 1 file changed, 10 insertions(+), 30 deletions(-) (limited to 'addons/document_webdav') diff --git a/addons/document_webdav/dav_fs.py b/addons/document_webdav/dav_fs.py index 41a65c73bfb..36b7313a0fa 100644 --- a/addons/document_webdav/dav_fs.py +++ b/addons/document_webdav/dav_fs.py @@ -68,7 +68,7 @@ class openerp_dav_handler(dav_interface): if uri[-1]=='/':uri=uri[:-1] cr, uid, pool, dbname, uri2 = self.get_cr(uri) if not dbname: - cr.close() + if cr: cr.close() return props node = self.uri2object(cr, uid, pool, uri2) if node: @@ -94,7 +94,7 @@ class openerp_dav_handler(dav_interface): if uri[-1]=='/':uri=uri[:-1] cr, uid, pool, dbname, uri2 = self.get_cr(uri) if not dbname: - cr.close() + if cr: cr.close() raise DAV_NotFound node = self.uri2object(cr, uid, pool, uri2) if not node: @@ -360,40 +360,20 @@ class openerp_dav_handler(dav_interface): if cr: cr.close() def mkcol(self,uri): - """ create a new collection """ + """ create a new collection """ self.parent.log_message('MKCOL: %s' % uri) + uri = self.uri2local(uri)[1:] if uri[-1]=='/':uri=uri[:-1] - parent='/'.join(uri.split('/')[:-1]) - if not parent.startswith(self.baseuri): - parent=self.baseuri + ''.join(parent[1:]) - if not uri.startswith(self.baseuri): - uri=self.baseuri + ''.join(uri[1:]) - - + parent = '/'.join(uri.split('/')[:-1]) + parent = self.baseuri + parent + uri = self.baseuri + uri cr, uid, pool,dbname, uri2 = self.get_cr(uri) if not dbname: raise DAV_Error, 409 node = self.uri2object(cr,uid,pool, uri2[:-1]) - object2 = False - if isinstance(node, node_res_obj): - object2 = node and pool.get(node.context.context['res_model']).browse(cr, uid, node.context.context['res_id']) or False - - obj = node.context._dirobj.browse(cr, uid, node.dir_id) - if obj and (obj.type == 'ressource') and not object2: - raise OSError(1, 'Operation not permited.') - - objname = uri2[-1] - val = { - 'name': objname, - 'ressource_parent_type_id': obj and obj.ressource_type_id.id or False, - 'ressource_id': object2 and object2.id or False, - 'parent_id' : False - } - if (obj and (obj.type in ('directory'))) or not object2: - val['parent_id'] = obj and obj.id or False - - pool.get('document.directory').create(cr, uid, val) - cr.commit() + if node: + node.create_child_collection(cr, uri2[-1]) + cr.commit() cr.close() return True -- cgit v1.2.3 From 7aea663bb63476b3725b4d56cdfffabbfb61aaf2 Mon Sep 17 00:00:00 2001 From: "Harry (Open ERP)" Date: Thu, 15 Apr 2010 13:28:09 +0530 Subject: [IMP] caldav: supporting caldav protocall bzr revid: hmo@tinyerp.com-20100415075809-edzwop5gzzdi80jj --- addons/document_webdav/dav_fs.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'addons/document_webdav') diff --git a/addons/document_webdav/dav_fs.py b/addons/document_webdav/dav_fs.py index 36b7313a0fa..1b77ea67832 100644 --- a/addons/document_webdav/dav_fs.py +++ b/addons/document_webdav/dav_fs.py @@ -135,8 +135,8 @@ class openerp_dav_handler(dav_interface): cr.close() return self.db_name_list - def get_childs(self,uri): - """ return the child objects as self.baseuris for the given URI """ + def get_childs(self,uri, filters=None): + """ return the child objects as self.baseuris for the given URI """ self.parent.log_message('get childs: %s' % uri) if uri[-1]=='/':uri=uri[:-1] cr, uid, pool, dbname, uri2 = self.get_cr(uri) @@ -158,14 +158,16 @@ class openerp_dav_handler(dav_interface): fp = '/'.join(fp) else: fp = None - for d in node.children(cr): + domain = None + if filters: + domain = node.get_domain(cr, filters) + for d in node.children(cr, domain): self.parent.log_message('child: %s' % d.path) if fp: result.append( self.urijoin(dbname,fp,d.path) ) else: result.append( self.urijoin(dbname,d.path) ) if cr: cr.close() - return result def uri2local(self, uri): -- cgit v1.2.3 From 7558802e883a3614f6a07764c7ee9a5723061358 Mon Sep 17 00:00:00 2001 From: "Harry (Open ERP)" Date: Thu, 15 Apr 2010 16:26:05 +0530 Subject: [IMP] caldav bzr revid: hmo@tinyerp.com-20100415105605-18h6tgny6lu21j85 --- addons/document_webdav/dav_fs.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'addons/document_webdav') diff --git a/addons/document_webdav/dav_fs.py b/addons/document_webdav/dav_fs.py index 1b77ea67832..d8b369b5ecf 100644 --- a/addons/document_webdav/dav_fs.py +++ b/addons/document_webdav/dav_fs.py @@ -100,8 +100,8 @@ class openerp_dav_handler(dav_interface): if not node: cr.close() raise DAV_NotFound - res = node.get_dav_eprop(cr,ns,propname) - cr.close() + res = node.get_dav_eprop(cr,ns,propname) + cr.close() return res def get_db(self,uri): -- cgit v1.2.3 From 5c3cf27f2fa72cd64c54e6241f10b86a089d357a Mon Sep 17 00:00:00 2001 From: "Harry (Open ERP)" Date: Wed, 21 Apr 2010 19:04:02 +0530 Subject: [IMP] caldav bzr revid: hmo@tinyerp.com-20100421133402-191nwwj3nohx6zas --- addons/document_webdav/dav_fs.py | 19 +++++++- addons/document_webdav/webdav_server.py | 82 ++++++++++++++++++++++++++++++++- 2 files changed, 98 insertions(+), 3 deletions(-) (limited to 'addons/document_webdav') diff --git a/addons/document_webdav/dav_fs.py b/addons/document_webdav/dav_fs.py index d8b369b5ecf..d8e654728e2 100644 --- a/addons/document_webdav/dav_fs.py +++ b/addons/document_webdav/dav_fs.py @@ -82,6 +82,20 @@ class openerp_dav_handler(dav_interface): def _get_dav_supportedlock(self, uri): raise DAV_NotFound + def match_prop(self, uri, match, ns, propname): + if uri[-1]=='/':uri=uri[:-1] + cr, uid, pool, dbname, uri2 = self.get_cr(uri) + if not dbname: + if cr: cr.close() + raise DAV_NotFound + node = self.uri2object(cr, uid, pool, uri2) + if not node: + cr.close() + raise DAV_NotFound + res = node.match_dav_eprop(cr, match, ns, propname) + cr.close() + return res + def get_prop(self, uri, ns, propname): """ return the value of a given property @@ -209,14 +223,14 @@ class openerp_dav_handler(dav_interface): return None return pool.get('document.directory').get_object(cr, uid, uri) - def get_data(self,uri): + def get_data(self,uri): self.parent.log_message('GET: %s' % uri) if uri[-1]=='/':uri=uri[:-1] cr, uid, pool, dbname, uri2 = self.get_cr(uri) try: if not dbname: raise DAV_Error, 409 - node = self.uri2object(cr,uid,pool, uri2) + node = self.uri2object(cr,uid,pool, uri2) if not node: raise DAV_NotFound(uri2) try: @@ -390,6 +404,7 @@ class openerp_dav_handler(dav_interface): node = self.uri2object(cr,uid,pool, uri2[:]) except: node = False + node.headers = self.parent.headers objname = uri2[-1] ext = objname.find('.') >0 and objname.split('.')[1] or False diff --git a/addons/document_webdav/webdav_server.py b/addons/document_webdav/webdav_server.py index 6cda2d172ef..5f88f90cf11 100644 --- a/addons/document_webdav/webdav_server.py +++ b/addons/document_webdav/webdav_server.py @@ -33,7 +33,10 @@ from dav_fs import openerp_dav_handler from tools.config import config from DAV.WebDAVServer import DAVRequestHandler from service.websrv_lib import HTTPDir,FixSendError - +import urlparse +import urllib +from string import atoi,split +from DAV.errors import * def OpenDAVConfig(**kw): class OpenDAV: @@ -81,6 +84,83 @@ class DAVHandler(FixSendError,DAVRequestHandler): def log_error(self, format, *args): netsvc.Logger().notifyChannel('xmlrpc',netsvc.LOG_WARNING,format % args) + def do_PUT(self): + dc=self.IFACE_CLASS + uri=urlparse.urljoin(self.get_baseuri(dc), self.path) + uri=urllib.unquote(uri) + # Handle If-Match + if self.headers.has_key('If-Match'): + test = False + etag = None + + for match in self.headers['If-Match'].split(','): + if match == '*': + if dc.exists(uri): + test = True + break + else: + if dc.match_prop(uri, match, "DAV:", "getetag"): + test = True + break + if not test: + self.send_status(412) + return + + # Handle If-None-Match + if self.headers.has_key('If-None-Match'): + test = True + etag = None + for match in self.headers['If-None-Match'].split(','): + if match == '*': + if dc.exists(uri): + test = False + break + else: + if dc.match_prop(uri, match, "DAV:", "getetag"): + test = False + break + if not test: + self.send_status(412) + return + + # Handle expect + expect = self.headers.get('Expect', '') + if (expect.lower() == '100-continue' and + self.protocol_version >= 'HTTP/1.1' and + self.request_version >= 'HTTP/1.1'): + self.send_status(100) + self._flush() + + # read the body + body=None + if self.headers.has_key("Content-Length"): + l=self.headers['Content-Length'] + body=self.rfile.read(atoi(l)) + + # locked resources are not allowed to be overwritten + if self._l_isLocked(uri): + return self.send_body(None, '423', 'Locked', 'Locked') + + ct=None + if self.headers.has_key("Content-Type"): + ct=self.headers['Content-Type'] + try: + location = dc.put(uri,body,ct) + except DAV_Error, (ec,dd): + return self.send_status(ec) + + headers = {} + if location: + headers['Location'] = location + + try: + etag = dc.get_prop(location or uri, "DAV:", "getetag") + headers['ETag'] = etag + except: + pass + + self.send_body(None, '201', 'Created', '', headers=headers) + try: from service.http_server import reg_http_service,OpenERPAuthProvider -- cgit v1.2.3 From e246a6bfe0e89f5c45cca17292837f3e520fa2c9 Mon Sep 17 00:00:00 2001 From: "Harry (Open ERP)" Date: Thu, 22 Apr 2010 18:20:41 +0530 Subject: [IMP+REF] caldav bzr revid: hmo@tinyerp.com-20100422125041-2x1fkswvf2gab05p --- addons/document_webdav/dav_fs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'addons/document_webdav') diff --git a/addons/document_webdav/dav_fs.py b/addons/document_webdav/dav_fs.py index d8e654728e2..bfe9729a194 100644 --- a/addons/document_webdav/dav_fs.py +++ b/addons/document_webdav/dav_fs.py @@ -404,7 +404,7 @@ class openerp_dav_handler(dav_interface): node = self.uri2object(cr,uid,pool, uri2[:]) except: node = False - node.headers = self.parent.headers + objname = uri2[-1] ext = objname.find('.') >0 and objname.split('.')[1] or False -- cgit v1.2.3 From 199ac22a962e89eee314254846cfbb95aaa6d99d Mon Sep 17 00:00:00 2001 From: "Harry (Open ERP)" Date: Fri, 23 Apr 2010 17:35:44 +0530 Subject: [FIX] caldav: remove calendar problem bzr revid: hmo@tinyerp.com-20100423120544-axml2owg03rwwvv0 --- addons/document_webdav/dav_fs.py | 29 +++++++---------------------- 1 file changed, 7 insertions(+), 22 deletions(-) (limited to 'addons/document_webdav') diff --git a/addons/document_webdav/dav_fs.py b/addons/document_webdav/dav_fs.py index bfe9729a194..0c2e52c8df7 100644 --- a/addons/document_webdav/dav_fs.py +++ b/addons/document_webdav/dav_fs.py @@ -433,6 +433,7 @@ class openerp_dav_handler(dav_interface): return 201 def rmcol(self,uri): + print ' REMOVE COLLL :::::', uri """ delete a collection """ if uri[-1]=='/':uri=uri[:-1] @@ -440,39 +441,23 @@ class openerp_dav_handler(dav_interface): if not dbname: # *-* raise DAV_Error, 409 node = self.uri2object(cr, uid, pool, uri2) - object = node.context._dirobj.browse(cr, uid, node.dir_id) - - if not object: - raise OSError(2, 'Not such file or directory.') - if object._table_name=='document.directory': - if node.children(cr): - raise OSError(39, 'Directory not empty.') - res = pool.get('document.directory').unlink(cr, uid, [object.id]) - else: - raise OSError(1, 'Operation not permited.') + node.rmcol(cr) cr.commit() cr.close() return 204 def rm(self,uri): - if uri[-1]=='/':uri=uri[:-1] - - object=False + print ' REMOVE EVENT :::::', uri + if uri[-1]=='/':uri=uri[:-1] cr, uid, pool,dbname, uri2 = self.get_cr(uri) if not dbname: cr.close() raise DAV_Error, 409 node = self.uri2object(cr,uid,pool, uri2) - object = pool.get('ir.attachment').browse(cr, uid, node.file_id) - self.parent.log_message(' rm %s "%s"'%(object._table_name,uri)) - if not object: - raise OSError(2, 'Not such file or directory.') - if object._table_name == 'ir.attachment': - res = pool.get('ir.attachment').unlink(cr, uid, [object.id]) - else: - raise OSError(1, 'Operation not permited.') - + res = node.rm(cr) + if not res: + raise OSError(1, 'Operation not permited.') cr.commit() cr.close() return 204 -- cgit v1.2.3