@@ -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 = {
|
||||
@@ -88,12 +90,19 @@ class document_directory_content(osv.osv):
|
||||
tname = (content.prefix or '') + (content.suffix or '') + (content.extension or '')
|
||||
if tname.find('/'):
|
||||
tname=tname.replace('/', '_')
|
||||
act_id = False
|
||||
if 'dctx_res_id' in node.dctx:
|
||||
act_id = node.dctx['dctx_res_id']
|
||||
elif hasattr(node, 'res_id'):
|
||||
act_id = node.res_id
|
||||
else:
|
||||
act_id = node.context.context.get('res_id',False)
|
||||
if not nodename:
|
||||
n = nodes.node_content(tname, node, node.context,content)
|
||||
n = nodes.node_content(tname, node, node.context,content, act_id=act_id)
|
||||
res2.append( n)
|
||||
else:
|
||||
if nodename == tname:
|
||||
n = nodes.node_content(tname, node, node.context,content)
|
||||
n = nodes.node_content(tname, node, node.context,content, act_id=act_id)
|
||||
n.fill_fields(cr)
|
||||
res2.append(n)
|
||||
return res2
|
||||
@@ -108,6 +117,10 @@ class document_directory_content(osv.osv):
|
||||
raise Exception("Invalid content: %s" % node.extension)
|
||||
report = self.pool.get('ir.actions.report.xml').browse(cr, uid, node.report_id)
|
||||
srv = netsvc.Service._services['report.'+report.report_name]
|
||||
pdf,pdftype = srv.create(cr, uid, [node.context.context['res_id']], {}, {})
|
||||
ctx = node.context.context.copy()
|
||||
ctx.update(node.dctx)
|
||||
pdf,pdftype = srv.create(cr, uid, [node.act_id,], {}, context=ctx)
|
||||
return pdf
|
||||
document_directory_content()
|
||||
|
||||
#eof
|
||||
@@ -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)
|
||||
|
||||
@@ -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 !'),
|
||||
|
||||
@@ -82,6 +82,7 @@
|
||||
<group colspan="4" col="4" attrs="{'invisible': [('type','!=','ressource')]}">
|
||||
<field name="ressource_type_id" on_change="onchange_content_id(ressource_type_id)"
|
||||
attrs="{'required': [('type','=','ressource')] }"/>
|
||||
<field name="resource_find_all" groups="base.group_extended" />
|
||||
<newline/>
|
||||
<field name="resource_field" domain="[('model_id','=',ressource_type_id), ('ttype', 'in', ('char', 'selection', 'date', 'datetime'))]"/>
|
||||
<field name="ressource_tree"/>
|
||||
@@ -96,7 +97,7 @@
|
||||
</page>
|
||||
<page string="Generated Files" groups="base.group_extended">
|
||||
<label colspan="4" string="For each entry here, virtual files will appear in this folder." />
|
||||
<field name="content_ids" nolabel="1" colspan="4" attrs="{'readonly': [('ressource_type_id','=',False)]}">
|
||||
<field name="content_ids" nolabel="1" colspan="4" >
|
||||
<form string="Contents">
|
||||
<field name="name"/>
|
||||
<field name="sequence"/>
|
||||
|
||||
+101
-13
@@ -31,6 +31,8 @@ import errno
|
||||
import os
|
||||
import time
|
||||
|
||||
from StringIO import StringIO
|
||||
|
||||
#
|
||||
# An object that represent an uri
|
||||
# path: the uri of the object
|
||||
@@ -226,7 +228,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 +242,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")
|
||||
@@ -306,13 +308,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(repr(self))
|
||||
|
||||
def create_child_collection(self, cr, objname):
|
||||
""" Create a child collection (directory) under self
|
||||
"""
|
||||
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 []
|
||||
@@ -535,7 +547,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
|
||||
"""
|
||||
@@ -647,6 +659,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!
|
||||
@@ -761,16 +774,17 @@ 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
|
||||
dc2 = self.context.context.copy()
|
||||
dc2.update(self.dctx)
|
||||
dc2['res_model'] = res_model
|
||||
dc2['res_id'] = res_bo.id
|
||||
@@ -796,6 +810,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
|
||||
@@ -909,6 +925,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)
|
||||
@@ -960,7 +978,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
|
||||
"""
|
||||
@@ -976,11 +994,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)
|
||||
@@ -1204,9 +1223,6 @@ class node_content(node_class):
|
||||
self.dctx.update(dctx)
|
||||
self.act_id = act_id
|
||||
|
||||
def open(self, cr, mode=False):
|
||||
raise DeprecationWarning()
|
||||
|
||||
def fill_fields(self, cr, dctx = None):
|
||||
""" Try to read the object and fill missing fields, like mimetype,
|
||||
dates etc.
|
||||
@@ -1233,7 +1249,29 @@ class node_content(node_class):
|
||||
self.content_length = len(data)
|
||||
return data
|
||||
|
||||
def open_data(self, cr, mode):
|
||||
if mode.endswith('b'):
|
||||
mode = mode[:-1]
|
||||
if mode in ('r', 'w'):
|
||||
cperms = mode[:1]
|
||||
elif mode in ('r+', 'w+'):
|
||||
cperms = 'rw'
|
||||
else:
|
||||
raise IOError(errno.EINVAL, "Cannot open at mode %s" % mode)
|
||||
|
||||
if not self.check_perms(cperms):
|
||||
raise IOError(errno.EPERM, "Permission denied")
|
||||
|
||||
ctx = self.context.context.copy()
|
||||
ctx.update(self.dctx)
|
||||
|
||||
return nodefd_content(self, cr, mode, ctx)
|
||||
|
||||
def get_data_len(self, cr, fil_obj = None):
|
||||
# FIXME : here, we actually generate the content twice!!
|
||||
# we should have cached the generated content, but it is
|
||||
# not advisable to do keep it in memory, until we have a cache
|
||||
# expiration logic.
|
||||
if not self.content_length:
|
||||
self.get_data(cr,fil_obj)
|
||||
return self.content_length
|
||||
@@ -1249,3 +1287,53 @@ class node_content(node_class):
|
||||
|
||||
def _get_ttag(self,cr):
|
||||
return 'cnt-%d%s' % (self.cnt_id,(self.act_id and ('-' + str(self.act_id))) or '')
|
||||
|
||||
|
||||
class nodefd_content(StringIO, node_descriptor):
|
||||
""" A descriptor to content nodes
|
||||
"""
|
||||
def __init__(self, parent, cr, mode, ctx):
|
||||
node_descriptor.__init__(self, parent)
|
||||
self._context=ctx
|
||||
|
||||
if mode in ('r', 'r+'):
|
||||
cntobj = parent.context._dirobj.pool.get('document.directory.content')
|
||||
data = cntobj.process_read(cr, parent.context.uid, parent, ctx)
|
||||
if data:
|
||||
parent.content_length = len(data)
|
||||
StringIO.__init__(self, data)
|
||||
elif mode in ('w', 'w+'):
|
||||
StringIO.__init__(self, None)
|
||||
# at write, we start at 0 (= overwrite), but have the original
|
||||
# data available, in case of a seek()
|
||||
elif mode == 'a':
|
||||
StringIO.__init__(self, None)
|
||||
else:
|
||||
logging.getLogger('document.content').error("Incorrect mode %s specified", mode)
|
||||
raise IOError(errno.EINVAL, "Invalid file mode")
|
||||
self.mode = mode
|
||||
|
||||
def close(self):
|
||||
# we now open a *separate* cursor, to update the data.
|
||||
# FIXME: this may be improved, for concurrency handling
|
||||
if self.mode == 'r':
|
||||
StringIO.close(self)
|
||||
return
|
||||
|
||||
par = self._get_parent()
|
||||
uid = par.context.uid
|
||||
cr = pooler.get_db(par.context.dbname).cursor()
|
||||
try:
|
||||
if self.mode in ('w', 'w+', 'r+'):
|
||||
data = self.getvalue()
|
||||
cntobj = par.context._dirobj.pool.get('document.directory.content')
|
||||
cntobj.process_write(cr, uid, parent, data, ctx)
|
||||
elif self.mode == 'a':
|
||||
raise NotImplementedError
|
||||
cr.commit()
|
||||
except Exception, e:
|
||||
logging.getLogger('document.content').exception('Cannot update db content #%d for close:', par.cnt_id)
|
||||
raise
|
||||
finally:
|
||||
cr.close()
|
||||
StringIO.close(self)
|
||||
|
||||
@@ -169,7 +169,10 @@ class abstracted_fs(object):
|
||||
raise OSError(1, 'Operation not permited.')
|
||||
# Reading operation
|
||||
cr, node, rem = datacr
|
||||
res = node.open_data(cr, mode)
|
||||
try:
|
||||
res = node.open_data(cr, mode)
|
||||
except TypeError, e:
|
||||
raise IOError(errno.EINVAL, "No data")
|
||||
return res
|
||||
|
||||
# ok, but need test more
|
||||
@@ -427,7 +430,7 @@ class abstracted_fs(object):
|
||||
if not (datacr and datacr[1]):
|
||||
return 0L
|
||||
if datacr[1].type in ('file', 'content'):
|
||||
return datacr[1].content_length or 0L
|
||||
return datacr[1].get_data_len(datacr[0]) or 0L
|
||||
return 0L
|
||||
|
||||
# Ok
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 'Äïêéìáóôéêüò ÖÜêåëëïò'
|
||||
-
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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,38 @@ 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())
|
||||
# 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
|
||||
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 +233,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,26 +296,25 @@ 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")
|
||||
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_NotFound(uri2)
|
||||
raise DAV_NotFound2(uri2)
|
||||
except Exception,e:
|
||||
import traceback
|
||||
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()
|
||||
|
||||
@@ -288,7 +328,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 +344,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 +360,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 +377,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 +392,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 +409,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 +427,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
|
||||
@@ -395,20 +435,28 @@ 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 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)
|
||||
cr, uid, pool, dbname, uri2 = self.get_cr(uri)
|
||||
if not uri2[-1]:
|
||||
cr.close()
|
||||
raise DAV_Error(409, "Cannot create nameless collection")
|
||||
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
|
||||
|
||||
@@ -430,22 +478,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()
|
||||
@@ -618,7 +657,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)
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -175,6 +187,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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user