From 385aaa2467e8b3f355adba2c5d192a45e33b78ba Mon Sep 17 00:00:00 2001 From: "P. Christeas" Date: Mon, 12 Jul 2010 22:28:08 +0300 Subject: [PATCH 01/16] Document API: define node_class.create_child() and collection Allow clients to call those fn()s for the wrong nodes, just to get an NotImplementedError. bzr revid: p_christ@hol.gr-20100712192808-d0x2qud1p5q26fb8 --- addons/document/nodes.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/addons/document/nodes.py b/addons/document/nodes.py index d710db37c15..d40886846aa 100644 --- a/addons/document/nodes.py +++ b/addons/document/nodes.py @@ -306,7 +306,17 @@ class node_class(object): Move operations, as instructed from APIs (eg. request from DAV) could use this function. """ - raise NotImplementedError + raise NotImplementedError() + + def create_child(self, cr, path, data=None): + """ Create a regular file under this node + """ + raise NotImplementedError() + + def create_child_collection(self, cr, objname): + """ Create a child collection (directory) under self + """ + raise NotImplementedError() def rm(self, cr): raise RuntimeError("Not Implemented") From 136398f1755d46d8dc306ce0d3335e1cc688a065 Mon Sep 17 00:00:00 2001 From: "P. Christeas" Date: Mon, 12 Jul 2010 22:28:19 +0300 Subject: [PATCH 02/16] Doc Webdav: One more workaround for python-webdav. bzr revid: p_christ@hol.gr-20100712192819-7lr9zfogs6jjqq74 --- addons/document_webdav/webdav_server.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/addons/document_webdav/webdav_server.py b/addons/document_webdav/webdav_server.py index 610e51a0f07..b4cac5ffc70 100644 --- a/addons/document_webdav/webdav_server.py +++ b/addons/document_webdav/webdav_server.py @@ -175,6 +175,11 @@ class DAVHandler(FixSendError,DAVRequestHandler): self.send_body(None, '201', 'Created', '', headers=headers) + def do_DELETE(self): + try: + DAVRequestHandler.do_DELETE(self) + except DAV_Error, (ec, dd): + return self.send_status(ec) from service.http_server import reg_http_service,OpenERPAuthProvider From 3fe8bf10a8e7353db08cba69a9a2969ab6530832 Mon Sep 17 00:00:00 2001 From: "P. Christeas" Date: Mon, 12 Jul 2010 22:29:30 +0300 Subject: [PATCH 03/16] Doc WebDAV: More consistent exceptions The NotFound one should properly parse the list uri2. Define a helper function that will wrap around usual calls and handle their exceptions. bzr revid: p_christ@hol.gr-20100712192930-necdd0z9d2j6w4ut --- addons/document_webdav/dav_fs.py | 80 ++++++++++++++++++++++---------- 1 file changed, 56 insertions(+), 24 deletions(-) diff --git a/addons/document_webdav/dav_fs.py b/addons/document_webdav/dav_fs.py index 880074173ea..3805566f79d 100644 --- a/addons/document_webdav/dav_fs.py +++ b/addons/document_webdav/dav_fs.py @@ -46,6 +46,15 @@ CACHE_SIZE=20000 urlparse.uses_netloc.append('webdav') urlparse.uses_netloc.append('webdavs') +class DAV_NotFound2(DAV_NotFound): + """404 exception, that accepts our list uris + """ + def __init__(self, *args): + if len(args) and isinstance(args[0], (tuple, list)): + path = ''.join([ '/' + x for x in args[0]]) + args = (path, ) + DAV_NotFound.__init__(self, *args) + class openerp_dav_handler(dav_interface): """ This class models a OpenERP interface for the DAV server @@ -74,6 +83,36 @@ class openerp_dav_handler(dav_interface): cr.close() return props + def _try_function(self, funct, args, opname='run function', cr=None, default_exc=DAV_Forbidden): + """ Try to run a function, and properly convert exceptions to DAV ones. + + @objname the name of the operation being performed + @param cr if given, the cursor to close at exceptions + """ + + try: + funct(*args) + except DAV_Error: + if cr: cr.close() + raise + except NotImplementedError, e: + if cr: cr.close() + import traceback + self.parent.log_error("Cannot %s: %s", opname, str(e)) + self.parent.log_message("Exc: %s",traceback.format_exc()) + raise DAV_Error(405, str(e) or 'Not supported at this path') + except EnvironmentError, err: + if cr: cr.close() + import traceback + self.parent.log_error("Cannot %s: %s", opname, e.strerror) + self.parent.log_message("Exc: %s",traceback.format_exc()) + raise default_exc(err.strerror) + except Exception,e: + import traceback + self.parent.log_error("Cannot create %s: %s", opname, str(e)) + self.parent.log_message("Exc: %s",traceback.format_exc()) + raise default_exc("Operation failed") + def _get_dav_lockdiscovery(self, uri): raise DAV_NotFound @@ -192,7 +231,7 @@ class openerp_dav_handler(dav_interface): if not node: if cr: cr.close() - raise DAV_NotFound(uri2) + raise DAV_NotFound2(uri2) else: fp = node.full_path() if fp and len(fp): @@ -255,7 +294,7 @@ class openerp_dav_handler(dav_interface): raise DAV_Error, 409 node = self.uri2object(cr, uid, pool, uri2) if not node: - raise DAV_NotFound(uri2) + raise DAV_NotFound2(uri2) try: if rrange: self.parent.log_error("Doc get_data cannot use range") @@ -268,7 +307,7 @@ class openerp_dav_handler(dav_interface): raise DAV_Forbidden except IndexError,e : self.parent.log_error("GET IndexError: %s", str(e)) - raise DAV_NotFound(uri2) + raise DAV_NotFound2(uri2) except Exception,e: import traceback self.parent.log_error("GET exception: %s",str(e)) @@ -288,7 +327,7 @@ class openerp_dav_handler(dav_interface): return COLLECTION node = self.uri2object(cr,uid,pool, uri2) if not node: - raise DAV_NotFound(uri2) + raise DAV_NotFound2(uri2) if node.type in ('collection','database'): return COLLECTION return OBJECT @@ -304,7 +343,7 @@ class openerp_dav_handler(dav_interface): node = self.uri2object(cr, uid, pool, uri2) if not node: cr.close() - raise DAV_NotFound(uri2) + raise DAV_NotFound2(uri2) cr.close() return node.displayname @@ -320,7 +359,7 @@ class openerp_dav_handler(dav_interface): node = self.uri2object(cr, uid, pool, uri2) if not node: cr.close() - raise DAV_NotFound(uri2) + raise DAV_NotFound2(uri2) result = node.content_length or 0 cr.close() return str(result) @@ -337,7 +376,7 @@ class openerp_dav_handler(dav_interface): node = self.uri2object(cr, uid, pool, uri2) if not node: cr.close() - raise DAV_NotFound(uri2) + raise DAV_NotFound2(uri2) result = node.get_etag(cr) cr.close() return str(result) @@ -352,7 +391,7 @@ class openerp_dav_handler(dav_interface): try: node = self.uri2object(cr, uid, pool, uri2) if not node: - raise DAV_NotFound(uri2) + raise DAV_NotFound2(uri2) if node.write_date: return time.mktime(time.strptime(node.write_date,'%Y-%m-%d %H:%M:%S')) else: @@ -369,7 +408,7 @@ class openerp_dav_handler(dav_interface): try: node = self.uri2object(cr, uid, pool, uri2) if not node: - raise DAV_NotFound(uri2) + raise DAV_NotFound2(uri2) if node.create_date: result = time.mktime(time.strptime(node.create_date,'%Y-%m-%d %H:%M:%S')) else: @@ -387,7 +426,7 @@ class openerp_dav_handler(dav_interface): try: node = self.uri2object(cr, uid, pool, uri2) if not node: - raise DAV_NotFound(uri2) + raise DAV_NotFound2(uri2) result = str(node.mimetype) return result #raise DAV_NotFound, 'Could not find %s' % path @@ -398,6 +437,8 @@ class openerp_dav_handler(dav_interface): """ create a new collection """ self.parent.log_message('MKCOL: %s' % uri) uri = self.uri2local(uri)[1:] + if not uri: + raise DAV_Error(409, "Cannot create nameless collection") if uri[-1]=='/':uri=uri[:-1] parent = '/'.join(uri.split('/')[:-1]) parent = self.baseuri + parent @@ -430,22 +471,13 @@ class openerp_dav_handler(dav_interface): if not node: dir_node = self.uri2object(cr, uid, pool, uri2[:-1]) if not dir_node: + cr.close() raise DAV_NotFound('Parent folder not found') - try: - dir_node.create_child(cr, objname, data) - except Exception,e: - import traceback - self.parent.log_error("Cannot create %s: %s", objname, str(e)) - self.parent.log_message("Exc: %s",traceback.format_exc()) - raise DAV_Forbidden + + self._try_function(dir_node.create_child, (cr, objname, data), + "create %s" % objname, cr=cr) else: - try: - node.set_data(cr, data) - except Exception,e: - import traceback - self.parent.log_error("Cannot save %s: %s", objname, str(e)) - self.parent.log_message("Exc: %s",traceback.format_exc()) - raise DAV_Forbidden + self._try_function(node.set_data, (cr, data), "save %s" % objname, cr=cr) cr.commit() cr.close() From 8dc0cc8a32f7ee38e21f8e65b38cf320190ed155 Mon Sep 17 00:00:00 2001 From: "P. Christeas" Date: Mon, 12 Jul 2010 22:29:49 +0300 Subject: [PATCH 04/16] Document API: a little better messages, allow create_child() w/o data. bzr revid: p_christ@hol.gr-20100712192949-nre9wzvx6utz3b3l --- addons/document/nodes.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/addons/document/nodes.py b/addons/document/nodes.py index d40886846aa..345a104f806 100644 --- a/addons/document/nodes.py +++ b/addons/document/nodes.py @@ -306,23 +306,23 @@ class node_class(object): Move operations, as instructed from APIs (eg. request from DAV) could use this function. """ - raise NotImplementedError() + raise NotImplementedError(repr(self)) def create_child(self, cr, path, data=None): """ Create a regular file under this node """ - raise NotImplementedError() + raise NotImplementedError(repr(self)) def create_child_collection(self, cr, objname): """ Create a child collection (directory) under self """ - raise NotImplementedError() + raise NotImplementedError(repr(self)) def rm(self, cr): - raise RuntimeError("Not Implemented") + raise NotImplementedError(repr(self)) def rmcol(self, cr): - raise RuntimeError("Not Implemented") + raise NotImplementedError(repr(self)) def get_domain(self, cr, filters): return [] @@ -545,7 +545,7 @@ class node_dir(node_database): return dirobj.create(cr, uid, val) - def create_child(self, cr, path, data): + def create_child(self, cr, path, data=None): """ API function to create a child file object and node Return the node_* created """ @@ -970,7 +970,7 @@ class node_res_obj(node_class): return dirobj.create(cr, uid, val) - def create_child(self, cr, path, data): + def create_child(self, cr, path, data=None): """ API function to create a child file object and node Return the node_* created """ From 83ff0d67573a6f921cc9736c750cfb6f487b7a8a Mon Sep 17 00:00:00 2001 From: "P. Christeas" Date: Mon, 12 Jul 2010 22:32:36 +0300 Subject: [PATCH 05/16] Document webdav: fix mkcol, rename, get_data (temp) Conflicts: document_webdav/dav_fs.py document_webdav/webdav_server.py bzr revid: p_christ@hol.gr-20100712193236-8xde2tpmmxfp004n --- addons/document_webdav/dav_fs.py | 30 ++++++++++++++----------- addons/document_webdav/webdav_server.py | 12 ++++++++++ 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/addons/document_webdav/dav_fs.py b/addons/document_webdav/dav_fs.py index 3805566f79d..f6dc92caf20 100644 --- a/addons/document_webdav/dav_fs.py +++ b/addons/document_webdav/dav_fs.py @@ -313,7 +313,7 @@ class openerp_dav_handler(dav_interface): self.parent.log_error("GET exception: %s",str(e)) self.parent.log_message("Exc: %s", traceback.format_exc()) raise DAV_Error, 409 - return datas + return str(datas) # FIXME! finally: if cr: cr.close() @@ -434,22 +434,27 @@ class openerp_dav_handler(dav_interface): if cr: cr.close() def mkcol(self,uri): - """ create a new collection """ + """ create a new collection + see par. 9.3 of rfc4918 + """ self.parent.log_message('MKCOL: %s' % uri) - uri = self.uri2local(uri)[1:] - if not uri: + cr, uid, pool, dbname, uri2 = self.get_cr(uri) + if not uri2[-1]: + cr.close() raise DAV_Error(409, "Cannot create nameless collection") - if uri[-1]=='/':uri=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: + cr.close() raise DAV_Error, 409 node = self.uri2object(cr,uid,pool, uri2[:-1]) - if node: - node.create_child_collection(cr, uri2[-1]) - cr.commit() + if not node: + cr.close() + raise DAV_Error(409, "Parent path %s does not exist" % uri2[:-1]) + nc = node.child(cr, uri2[-1]) + if nc: + cr.close() + raise DAV_Error(405, "Path already exists") + self._try_function(node.create_child_collection, (cr, uri2[-1]), "create col %s" % uri2[-1], cr=cr) + cr.commit() cr.close() return True @@ -650,7 +655,6 @@ class openerp_dav_handler(dav_interface): advanced systems we might also have to copy properties from the source to the destination. """ - print " copy a collection." return self.mkcol(dst) diff --git a/addons/document_webdav/webdav_server.py b/addons/document_webdav/webdav_server.py index b4cac5ffc70..9f9f2733a68 100644 --- a/addons/document_webdav/webdav_server.py +++ b/addons/document_webdav/webdav_server.py @@ -78,6 +78,18 @@ class DAVHandler(FixSendError,DAVRequestHandler): self.baseuri = "http://%s:%d/"% (self.server.server_name, self.server.server_port) self.IFACE_CLASS = openerp_dav_handler(self, self.verbose) + def copymove(self, CLASS): + """ Our uri scheme removes the /webdav/ component from there, so we + need to mangle the header, too. + """ + dest = self.headers['Destination'] + up = urlparse.urlparse(urllib.unquote(self.headers['Destination'])) + if up.path.startswith(self.davpath): + self.headers['Destination'] = up.path[len(self.davpath):] + else: + raise DAV_Forbidden("Not allowed to copy/move outside webdav path") + DAVRequestHandler.copymove(self, CLASS) + def get_davpath(self): return self.davpath From e6cb0e4cf5c6ec58267fe6287750b5fed10700bb Mon Sep 17 00:00:00 2001 From: "P. Christeas" Date: Tue, 13 Jul 2010 13:27:44 +0300 Subject: [PATCH 06/16] Revert "Document API: meaningful error, when asking for directory data content." This reverts commit 9e6e98fbf132f1c7ef795dee9d0eb3193332a5ee. bzr revid: p_christ@hol.gr-20100713102744-rnu3vq3a2wjqmbyf --- addons/document/nodes.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/addons/document/nodes.py b/addons/document/nodes.py index 345a104f806..0669ece73aa 100644 --- a/addons/document/nodes.py +++ b/addons/document/nodes.py @@ -27,7 +27,6 @@ from osv.orm import except_orm import pooler from tools.safe_eval import safe_eval -import errno import os import time @@ -226,7 +225,7 @@ class node_class(object): return False def get_data(self,cr): - raise IOError(errno.EINVAL, 'no data for %s' % self.type) + raise TypeError('no data for %s'% self.type) def open_data(self, cr, mode): """ Open a node_descriptor object for this node. @@ -240,7 +239,7 @@ class node_class(object): For this class, there is no data, so no implementation. Each child class that has data should override this. """ - raise IOError(errno.EINVAL, 'no data for %s' % self.type) + raise TypeError('no data for %s' % self.type) def _get_storage(self,cr): raise RuntimeError("no storage for base class") From 6586f41062e8f5d521adeeacb577a4f6850e7870 Mon Sep 17 00:00:00 2001 From: "P. Christeas" Date: Tue, 13 Jul 2010 13:28:00 +0300 Subject: [PATCH 07/16] Document nodes: import the errno, as in 9e6e98fbf132f1 bzr revid: p_christ@hol.gr-20100713102800-kfdmkfnvj0uxduo0 --- addons/document/nodes.py | 1 + 1 file changed, 1 insertion(+) diff --git a/addons/document/nodes.py b/addons/document/nodes.py index 0669ece73aa..c1a11459c0a 100644 --- a/addons/document/nodes.py +++ b/addons/document/nodes.py @@ -27,6 +27,7 @@ from osv.orm import except_orm import pooler from tools.safe_eval import safe_eval +import errno import os import time From 403a71fbaab7a8b607934347ccf6e7309f875f1a Mon Sep 17 00:00:00 2001 From: "P. Christeas" Date: Tue, 13 Jul 2010 13:29:46 +0300 Subject: [PATCH 08/16] Document webdav: fix errors for get_data, mkcol bzr revid: p_christ@hol.gr-20100713102946-peksq27q3bxzgtnx --- addons/document_webdav/dav_fs.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/addons/document_webdav/dav_fs.py b/addons/document_webdav/dav_fs.py index f6dc92caf20..4dba174d0a5 100644 --- a/addons/document_webdav/dav_fs.py +++ b/addons/document_webdav/dav_fs.py @@ -83,7 +83,8 @@ class openerp_dav_handler(dav_interface): cr.close() return props - def _try_function(self, funct, args, opname='run function', cr=None, default_exc=DAV_Forbidden): + def _try_function(self, funct, args, opname='run function', cr=None, + default_exc=DAV_Forbidden): """ Try to run a function, and properly convert exceptions to DAV ones. @objname the name of the operation being performed @@ -100,7 +101,8 @@ class openerp_dav_handler(dav_interface): import traceback self.parent.log_error("Cannot %s: %s", opname, str(e)) self.parent.log_message("Exc: %s",traceback.format_exc()) - raise DAV_Error(405, str(e) or 'Not supported at this path') + # see par 9.3.1 of rfc + raise DAV_Error(403, str(e) or 'Not supported at this path') except EnvironmentError, err: if cr: cr.close() import traceback @@ -301,10 +303,9 @@ class openerp_dav_handler(dav_interface): raise DAV_Error(409) datas = node.get_data(cr) except TypeError,e: - import traceback - self.parent.log_error("GET typeError: %s", str(e)) - self.parent.log_message("Exc: %s",traceback.format_exc()) - raise DAV_Forbidden + # for the collections that return this error, the DAV standard + # says we'd better just return 200 OK with empty data + return '' except IndexError,e : self.parent.log_error("GET IndexError: %s", str(e)) raise DAV_NotFound2(uri2) @@ -453,7 +454,8 @@ class openerp_dav_handler(dav_interface): if nc: cr.close() raise DAV_Error(405, "Path already exists") - self._try_function(node.create_child_collection, (cr, uri2[-1]), "create col %s" % uri2[-1], cr=cr) + self._try_function(node.create_child_collection, (cr, uri2[-1]), + "create col %s" % uri2[-1], cr=cr) cr.commit() cr.close() return True From 2d3d861a3e4317a71fb58307ac9d8a2866c6999c Mon Sep 17 00:00:00 2001 From: "P. Christeas" Date: Tue, 13 Jul 2010 13:29:58 +0300 Subject: [PATCH 09/16] Document directory: "find_all" field for resource dirs. A (mis-)feature of the previous code was that in resource directories, it would only list attachments that would have those dirs as parents. This means that we couldn't have another categorisation, that would yield some of the same attachments. bzr revid: p_christ@hol.gr-20100713102958-nk40nckc41uxyzri --- addons/document/document_directory.py | 4 ++++ addons/document/document_view.xml | 1 + addons/document/nodes.py | 11 +++++++++-- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/addons/document/document_directory.py b/addons/document/document_directory.py index 0685f5c08ff..f5b9202fc8e 100644 --- a/addons/document/document_directory.py +++ b/addons/document/document_directory.py @@ -57,6 +57,9 @@ class document_directory(osv.osv): 'ressource_type_id': fields.many2one('ir.model', 'Resource model', help="Select an object here and there will be one folder per record of that resource."), 'resource_field': fields.many2one('ir.model.fields', 'Name field', help='Field to be used as name on resource directories. If empty, the "name" will be used.'), + 'resource_find_all': fields.boolean('Find all resources', required=True, + help="If true, all attachments that match this resource will " \ + " be located. If false, only ones that have this as parent." ), 'ressource_parent_type_id': fields.many2one('ir.model', 'Parent Model', help="If you put an object here, this directory template will appear bellow all of these objects. " \ "Don't put a parent directory if you select a parent model."), @@ -103,6 +106,7 @@ class document_directory(osv.osv): 'type': lambda *args: 'directory', 'ressource_id': lambda *a: 0, 'storage_id': _get_def_storage, + 'resource_find_all': True, } _sql_constraints = [ ('dirname_uniq', 'unique (name,parent_id,ressource_id,ressource_parent_type_id)', 'The directory name must be unique !'), diff --git a/addons/document/document_view.xml b/addons/document/document_view.xml index 693d7370567..c886b6fc9d4 100644 --- a/addons/document/document_view.xml +++ b/addons/document/document_view.xml @@ -82,6 +82,7 @@ + diff --git a/addons/document/nodes.py b/addons/document/nodes.py index c1a11459c0a..0def3995d91 100644 --- a/addons/document/nodes.py +++ b/addons/document/nodes.py @@ -657,6 +657,7 @@ class node_res_dir(node_class): self.uidperms = dirr.get_dir_permissions() self.res_model = dirr.ressource_type_id and dirr.ressource_type_id.model or False self.resm_id = dirr.ressource_id + self.res_find_all = dirr.resource_find_all self.namefield = dirr.resource_field.name or 'name' self.displayname = dirr.name # Important: the domain is evaluated using the *parent* dctx! @@ -771,13 +772,14 @@ class node_res_obj(node_class): self.write_date = parent.write_date self.content_length = 0 self.unixperms = 040750 - self.uidperms = parent.uidperms & 0x15 + self.uidperms = parent.uidperms & 15 self.uuser = parent.uuser self.ugroup = parent.ugroup self.res_model = res_model self.domain = parent.domain self.displayname = path self.dctx_dict = parent.dctx_dict + self.res_find_all = parent.res_find_all if res_bo: self.res_id = res_bo.id dc2 = self.context.context @@ -806,6 +808,8 @@ class node_res_obj(node_class): return False if self.domain != other.domain: return False + if self.res_find_all != other.res_find_all: + return False if self.dctx != other.dctx: return False return self.dir_id == other.dir_id @@ -919,6 +923,8 @@ class node_res_obj(node_class): fil_obj = dirobj.pool.get('ir.attachment') + if self.res_find_all: + where2 = where where3 = where2 + [('res_model', '=', self.res_model), ('res_id','=',self.res_id)] # print "where clause for dir_obj", where2 ids = fil_obj.search(cr, uid, where3, context=ctx) @@ -986,11 +992,12 @@ class node_res_obj(node_class): val = { 'name': path, 'datas_fname': path, - 'parent_id': self.dir_id, 'res_model': self.res_model, 'res_id': self.res_id, # Datas are not set here } + if not self.res_find_all: + val['parent_id'] = self.dir_id fil_id = fil_obj.create(cr, uid, val, context=ctx) fil = fil_obj.browse(cr, uid, fil_id, context=ctx) From d9553df1a288d647354b2041581f382533817425 Mon Sep 17 00:00:00 2001 From: "P. Christeas" Date: Tue, 13 Jul 2010 13:30:05 +0300 Subject: [PATCH 10/16] Document: node context shall not be the context of orm methods. The orm methods are called with some rich context, which need not be used as the context of node structure. In the future, we might want to selectively pass context values from orm to node. bzr revid: p_christ@hol.gr-20100713103005-p0y6ptjoshomu0tv --- addons/document/document.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/addons/document/document.py b/addons/document/document.py index 6ab6cae5281..ac3d7b9187d 100644 --- a/addons/document/document.py +++ b/addons/document/document.py @@ -47,7 +47,10 @@ class document_file(osv.osv): def _data_get(self, cr, uid, ids, name, arg, context): fbrl = self.browse(cr, uid, ids, context=context) - nctx = nodes.get_node_context(cr, uid, context) + nctx = nodes.get_node_context(cr, uid, context={}) + # nctx will /not/ inherit the caller's context. Most of + # it would be useless, anyway (like active_id, active_model, + # bin_size etc.) result = {} bin_size = context.get('bin_size', False) for fbro in fbrl: @@ -67,7 +70,7 @@ class document_file(osv.osv): if not value: return True fbro = self.browse(cr, uid, id, context=context) - nctx = nodes.get_node_context(cr, uid, context) + nctx = nodes.get_node_context(cr, uid, context={}) fnode = nodes.node_file(None, None, nctx, fbro) res = fnode.set_data(cr, base64.decodestring(value), fbro) return res @@ -156,7 +159,7 @@ class document_file(osv.osv): raise osv.except_osv(_('ValidateError'), _('File name must be unique!')) if ('parent_id' in vals) or ('name' in vals): # perhaps this file is renaming or changing directory - nctx = nodes.get_node_context(cr,uid,context) + nctx = nodes.get_node_context(cr,uid,context={}) dirobj = self.pool.get('document.directory') if 'parent_id' in vals: dbro = dirobj.browse(cr, uid, vals['parent_id'], context=context) From 0e8b07f4908aa318870e370aca24c545948267a3 Mon Sep 17 00:00:00 2001 From: "P. Christeas" Date: Tue, 13 Jul 2010 13:30:16 +0300 Subject: [PATCH 11/16] Document ftp: have timeout at tests, skip if server is not available. At trunk-xrg, the FTP daemon is only started *after* the db is loaded, which means that it will not be available for tests on a server upgrade. (still, tests can be performed through the base_module_record's importer) Anyway, it is not wise to block the server startup if FTP doesn't respond. bzr revid: p_christ@hol.gr-20100713103016-33gu4o7yvkn7hmnd --- addons/document_ftp/test/document_ftp_test2.yml | 2 +- addons/document_ftp/test/document_ftp_test3.yml | 4 ++++ addons/document_ftp/test/document_ftp_test4.yml | 4 ++++ addons/document_ftp/test_easyftp.py | 4 ++-- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/addons/document_ftp/test/document_ftp_test2.yml b/addons/document_ftp/test/document_ftp_test2.yml index 544c61e38eb..55a77d6b73e 100644 --- a/addons/document_ftp/test/document_ftp_test2.yml +++ b/addons/document_ftp/test/document_ftp_test2.yml @@ -5,7 +5,7 @@ - !python {model: ir.attachment}: | from document_ftp import test_easyftp as te - ftp = te.get_plain_ftp() + ftp = te.get_plain_ftp(timeout=2.0) assert ftp.sock and (ftp.lastresp == '220'), ftp.lastresp - I read the list of databases at port 8021 and confirm our db is diff --git a/addons/document_ftp/test/document_ftp_test3.yml b/addons/document_ftp/test/document_ftp_test3.yml index 2a4939b2a8c..2161c1421da 100644 --- a/addons/document_ftp/test/document_ftp_test3.yml +++ b/addons/document_ftp/test/document_ftp_test3.yml @@ -1,5 +1,9 @@ - In order to check international character functionality +- + !python {model: ir.attachment}: | + from document_ftp import test_easyftp as te + ftp = te.get_plain_ftp(timeout=1.0) - I create in the server a folder called 'Δοκιμαστικός Φάκελλος' - diff --git a/addons/document_ftp/test/document_ftp_test4.yml b/addons/document_ftp/test/document_ftp_test4.yml index 4312dbf5f8c..9c3baed0844 100644 --- a/addons/document_ftp/test/document_ftp_test4.yml +++ b/addons/document_ftp/test/document_ftp_test4.yml @@ -1,5 +1,9 @@ - In order to check dynamic folder functionality of document + FTP +- + !python {model: ir.attachment}: | + from document_ftp import test_easyftp as te + ftp = te.get_plain_ftp(timeout=1.0) - | I create two partners 'Partner1' and 'Partner2'. I create three partner categories: 'none', 'pat1' and 'all' diff --git a/addons/document_ftp/test_easyftp.py b/addons/document_ftp/test_easyftp.py index eb709c79e31..8d75578718d 100644 --- a/addons/document_ftp/test_easyftp.py +++ b/addons/document_ftp/test_easyftp.py @@ -28,11 +28,11 @@ from ftplib import FTP from tools.misc import detect_ip_addr from tools import config -def get_plain_ftp(): +def get_plain_ftp(timeout=10.0): ftp = FTP() host = config.get('ftp_server_host', '127.0.0.1') port = config.get('ftp_server_port','8021') - ftp.connect(host,port) + ftp.connect(host,port, timeout=timeout) return ftp def get_ftp_login(cr, uid, ormobj): From 990cdf4c94b69e41b6ef5eaca5c5ed13d143d18d Mon Sep 17 00:00:00 2001 From: "P. Christeas" Date: Tue, 13 Jul 2010 13:30:24 +0300 Subject: [PATCH 12/16] Document: dynamic content file for static dirs. A dynamic content definition *can* be attached to a static directory, in which case the content should be generated based on the dctx dictionary of the dir. bzr revid: p_christ@hol.gr-20100713103024-l3nylpvx4ib6s4ii --- addons/document/directory_content.py | 4 +++- addons/document/document_view.xml | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/addons/document/directory_content.py b/addons/document/directory_content.py index 2d434712f56..cb2da17b8fc 100644 --- a/addons/document/directory_content.py +++ b/addons/document/directory_content.py @@ -58,7 +58,9 @@ class document_directory_content(osv.osv): 'suffix': fields.char('Suffix', size=16), 'report_id': fields.many2one('ir.actions.report.xml', 'Report'), 'extension': fields.selection(_extension_get, 'Document Type', required=True, size=4), - 'include_name': fields.boolean('Include Record Name', help="Check this field if you want that the name of the file start by the record name."), + 'include_name': fields.boolean('Include Record Name', + help="Check this field if you want that the name of the file to contain the record name." \ + "\nIf set, the directory will have to be a resource one."), 'directory_id': fields.many2one('document.directory', 'Directory'), } _defaults = { diff --git a/addons/document/document_view.xml b/addons/document/document_view.xml index c886b6fc9d4..998d1e93188 100644 --- a/addons/document/document_view.xml +++ b/addons/document/document_view.xml @@ -97,7 +97,7 @@