bzr revid: hmo@tinyerp.com-20100627172019-7abzqpe092kdy31w
This commit is contained in:
Harry (OpenERP) 2010-06-27 22:50:19 +05:30
commit 1c81281413
12 changed files with 278 additions and 136 deletions

View File

@ -98,6 +98,7 @@ class document_file(osv.osv):
('binary','Binary'),
],'Type', help="Type is used to separate URL and binary File"),
'company_id': fields.many2one('res.company', 'Company'),
}
def __get_def_directory(self, cr, uid, context=None):
@ -105,6 +106,7 @@ class document_file(osv.osv):
return dirobj._get_root_directory(cr, uid, context)
_defaults = {
'company_id': lambda s,cr,uid,c: s.pool.get('res.company')._company_default_get(cr, uid, 'ir.attachment', context=c),
'user_id': lambda self, cr, uid, ctx:uid,
'file_size': lambda self, cr, uid, ctx:0,
'store_method': lambda *args: 'db',

View File

@ -9,15 +9,9 @@
</record>
<record model="document.storage" id="storage_default">
<field name="name">Default File storage</field>
<field name="user_id" ref="base.user_admin"/>
</record>
<record model="document.storage" id="storage_db">
<field name="name">DB storage</field>
<field name="user_id" ref="base.user_admin"/>
<field name="type" eval="'db'" />
<field name="path"></field>
<field name="name">Default DB storage</field>
<field name="type">db</field>
<field name="user_id" ref="base.user_admin"/>
</record>
<record model="document.directory" id="dir_root">
@ -60,7 +54,7 @@
</record>
<record model="document.directory" id="dir_personnal_folder">
<field name="name">Personnal Folders</field>
<field name="name">Personal Folders</field>
<field name="parent_id" ref="dir_root"/>
<field name="type">ressource</field>
<field name="storage_id" ref="storage_default"/>

View File

@ -60,6 +60,7 @@ class document_directory(osv.osv):
'ressource_tree': fields.boolean('Tree Structure',
help="Check this if you want to use the same tree structure as the object selected in the system."),
'dctx_ids': fields.one2many('document.directory.dctx', 'dir_id', 'Context fields'),
'company_id': fields.many2one('res.company', 'Company'),
}
@ -92,6 +93,7 @@ class document_directory(osv.osv):
return None
_defaults = {
'company_id': lambda s,cr,uid,c: s.pool.get('res.company')._company_default_get(cr, uid, 'document.directory', context=c),
'user_id': lambda self,cr,uid,ctx: uid,
'domain': lambda self,cr,uid,ctx: '[]',
'type': lambda *args: 'directory',

View File

@ -24,6 +24,8 @@ from osv import osv, fields
import os
import tools
import base64
import logging
from tools.misc import ustr
from tools.translate import _
@ -96,6 +98,8 @@ class document_storage(osv.osv):
"""
_name = 'document.storage'
_description = 'Storage Media'
_doclog = logging.getLogger('document')
_columns = {
'name': fields.char('Name', size=64, required=True, select=1),
'write_date': fields.datetime('Date Modified', readonly=True),
@ -151,7 +155,7 @@ class document_storage(osv.osv):
# On a migrated db, some files may have the wrong storage type
# try to fix their directory.
if ira.file_size:
netsvc.Logger().notifyChannel('document', netsvc.LOG_WARNING, "ir.attachment #%d does not have a filename, but is at filestore, fix it!" % ira.id)
self._doclog.warning( "ir.attachment #%d does not have a filename, but is at filestore, fix it!" % ira.id)
return None
fpath = os.path.join(boo.path, ira.store_fname)
return file(fpath, 'rb').read()
@ -167,7 +171,7 @@ class document_storage(osv.osv):
# On a migrated db, some files may have the wrong storage type
# try to fix their directory.
if ira.file_size:
netsvc.Logger().notifyChannel('document',netsvc.LOG_WARNING,"ir.attachment #%d does not have a filename, trying the name." %ira.id)
self._doclog.warning("ir.attachment #%d does not have a filename, trying the name." %ira.id)
sfname = ira.name
fpath = os.path.join(boo.path,ira.store_fname or ira.name)
if os.path.exists(fpath):
@ -187,7 +191,6 @@ class document_storage(osv.osv):
if not context:
context = {}
boo = self.browse(cr, uid, id, context)
logger = netsvc.Logger()
if fil_obj:
ira = fil_obj
else:
@ -195,7 +198,7 @@ class document_storage(osv.osv):
if not boo.online:
raise RuntimeError('media offline')
logger.notifyChannel('document', netsvc.LOG_DEBUG, "Store data for ir.attachment #%d" % ira.id)
self._doclog.debug( "Store data for ir.attachment #%d" % ira.id)
store_fname = None
fname = None
if boo.type == 'filestore':
@ -214,14 +217,14 @@ class document_storage(osv.osv):
fp = file(fname, 'wb')
fp.write(data)
fp.close()
logger.notifyChannel('document', netsvc.LOG_DEBUG, "Saved data to %s" % fname)
self._doclog.debug( "Saved data to %s" % fname)
filesize = len(data) # os.stat(fname).st_size
store_fname = os.path.join(flag, filename)
# TODO Here, an old file would be left hanging.
except Exception, e :
netsvc.Logger().notifyChannel('document', netsvc.LOG_WARNING, "Couldn't save data: %s" % str(e))
except Exception, e:
self._doclog.warning( "Couldn't save data to %s", path, exc_info=True)
raise except_orm(_('Error!'), str(e))
elif boo.type == 'db':
filesize = len(data)
@ -250,14 +253,12 @@ class document_storage(osv.osv):
fp = file(fname,'wb')
fp.write(data)
fp.close()
logger.notifyChannel('document',netsvc.LOG_DEBUG,"Saved data to %s" % fname)
self._doclog.debug("Saved data to %s", fname)
filesize = len(data) # os.stat(fname).st_size
store_fname = os.path.join(*npath)
# TODO Here, an old file would be left hanging.
except Exception,e :
import traceback
traceback.print_exc()
netsvc.Logger().notifyChannel('document',netsvc.LOG_WARNING,"Couldn't save data: %s" % e)
self._doclog.warning("Couldn't save data:", exc_info=True)
raise except_orm(_('Error!'), str(e))
else:
raise TypeError("No %s storage" % boo.type)
@ -271,8 +272,8 @@ class document_storage(osv.osv):
try:
mime, icont = cntIndex.doIndex(data, ira.datas_fname,
ira.file_type or None, fname)
except Exception, e:
logger.notifyChannel('document', netsvc.LOG_DEBUG, 'Cannot index file: %s' % str(e))
except Exception:
self._doclog.debug('Cannot index file:', exc_info=True)
pass
# a hack: /assume/ that the calling write operation will not try
@ -284,7 +285,7 @@ class document_storage(osv.osv):
file_node.content_type = mime
return True
except Exception, e :
netsvc.Logger().notifyChannel('document', netsvc.LOG_WARNING, "Couldn't save data: %s" % str(e))
self._doclog.warning( "Couldn't save data:", exc_info=True)
# should we really rollback once we have written the actual data?
# at the db case (only), that rollback would be safe
raise except_orm(_('Error at doc write!'), str(e))
@ -319,9 +320,9 @@ class document_storage(osv.osv):
try:
os.unlink(fname)
except Exception, e:
netsvc.Logger().notifyChannel('document', netsvc.LOG_WARNING, "Could not remove file %s, please remove manually." % fname)
self._doclog.warning("Could not remove file %s, please remove manually.", fname, exc_info=True)
else:
netsvc.Logger().notifyChannel('document', netsvc.LOG_WARNING, "Unknown unlink key %s" % ktype)
self._doclog.warning("Unknown unlink key %s" % ktype)
return True

View File

@ -13,14 +13,15 @@
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Storage Media">
<group colspan="4" col="4">
<group colspan="4" col="6">
<field name="name" select="1" colspan="4"/>
<field name="user_id"/>
<field name="type"/>
<newline/>
<field name="user_id"/>
<field name="online"/>
<field name="readonly"/>
</group>
<group colspan="2" attrs="{'invisible':[('type','!=','realstore')]}">
<group colspan="2" attrs="{'invisible':[('type','=','db')]}">
<field name="path"/>
</group>
</form>
@ -35,17 +36,31 @@
<tree string="Storage Media" toolbar="1">
<field name="name"/>
<field name="type"/>
<field name="online"/>
<field name="readonly"/>
</tree>
</field>
</record>
<record id="view_document_storage_filter" model="ir.ui.view">
<field name="name">Search View: Document Storage</field>
<field name="model">document.storage</field>
<field name="type">search</field>
<field name="arch" type="xml">
<search string="Search Document storage">
<field name="name" />
<newline/>
<group expand="0" string="Group By..." groups="base.group_extended">
<filter string="Type" domain="[]" context="{'group_by':'type'}"/>
</group>
</search>
</field>
</record>
<record model="ir.actions.act_window" id="action_document_storage_form">
<field name="type">ir.actions.act_window</field>
<field name="res_model">document.storage</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="search_view_id" ref="view_document_storage_filter"/>
</record>
<menuitem
name="Storage Media"
@ -63,6 +78,7 @@
<field name="user_id"/>
<field name="parent_id"/>
<field name="storage_id" />
<field name="company_id" groups="base.group_multi_company" widget="selection"/>
<notebook colspan="4">
<page string="Definition">
<separator string="Directory Type" colspan="4"/>
@ -96,7 +112,7 @@
</tree>
</field>
</page>
<page string="Dynamic context">
<page string="Dynamic context" groups="base.group_extended">
<field name="dctx_ids" nolabel="1" colspan="4">
<tree string="Fields" editable="bottom">
<field name="field"/>
@ -119,6 +135,7 @@
<field name="name">document.directory</field>
<field name="model">document.directory</field>
<field name="type">tree</field>
<field name="field_parent">child_ids</field>
<field name="arch" type="xml">
<tree string="Directories" toolbar="1">
<field name="name"/>
@ -130,12 +147,35 @@
</field>
</record>
<record id="view_document_directory_filter" model="ir.ui.view">
<field name="name">Search View: Document Directory</field>
<field name="model">document.directory</field>
<field name="type">search</field>
<field name="arch" type="xml">
<search string="Search Document Directory">
<filter string="Static" domain="[('type','=','directory')]"/>
<filter string="Resources" domain="[('type','=','ressource')]"/>
<separator orientation="vertical"/>
<field name="name" />
<field name="user_id" />
<field name="storage_id" />
<newline/>
<group expand="0" string="Group By..." groups="base.group_extended">
<filter string="Type" domain="[]" context="{'group_by':'type'}"/>
<filter string="Owner" icon="terp-personal" domain="[]" context="{'group_by':'user_id'}"/>
<filter string="Storage" domain="[]" context="{'group_by':'storage_id'}"/>
</group>
</search>
</field>
</record>
<record model="ir.actions.act_window" id="action_document_directory_form">
<field name="name">Directories</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">document.directory</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="search_view_id" ref="view_document_directory_filter"/>
</record>
<record id="action_dir_view1" model="ir.actions.act_window.view">
@ -159,7 +199,7 @@
<record model="ir.actions.act_window" id="action_document_directory_tree">
<field name="type">ir.actions.act_window</field>
<field name="name">Directorie's Structure</field>
<field name="name">Directories' Structure</field>
<field name="res_model">document.directory</field>
<field name="view_type">tree</field>
<field name="view_id" ref="document.view_document_directory_tree"/>
@ -180,7 +220,8 @@
<group colspan="4" col="6">
<field name="name" select="1" />
<field name="type"/>
<field name="parent_id"/>
<field name="parent_id"/>
<field name="company_id" groups="base.group_multi_company" widget="selection"/>
</group>
<notebook colspan="4">
<page string="Attachment">
@ -244,11 +285,15 @@
help="Filter on my Attachment" />
</field>
<field name="partner_id"/>
<field name="company_id" groups="base.group_multi_company"/>
<newline/>
<group expand="0" string="Group By...">
<filter string="Partner" icon="terp-personal" domain="[]"
context="{'group_by':'partner_id'}" />
<filter string="Directory" icon="terp-folder-green" domain="[]" context="{'group_by':'parent_id'}"/>
<filter string="Type" domain="[]" context="{'group_by':'type'}"/>
<filter string="Owner" icon="terp-personal" domain="[]" context="{'group_by':'user_id'}"/>
<filter string="Company" icon="terp-personal" domain="[]" context="{'group_by':'company_id'}" groups="base.group_multi_company"/>
</group>
</search>
</field>
@ -259,7 +304,7 @@
<field name="type">tree</field>
<field name="priority" eval="1"/>
<field name="arch" type="xml">
<tree colors="blue:type in ('url')" string="Documents">
<tree colors="blue:type in ('url',)">
<field name="name"/>
<field name="type"/>
<field name="datas_fname"/>
@ -272,8 +317,10 @@
</record>
<record model="ir.actions.act_window" id="action_document_file_form">
<field name="name">Documents</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">ir.attachment</field>
<field name="name">Document</field>
<field name="view_type">form</field>
</record>
<menuitem name="Documents" id="menu_document_doc" parent="base.menu_document" sequence="5"/>
@ -286,6 +333,7 @@
<record model="ir.actions.act_window" id="action_document_file_directory_form">
<field name="type">ir.actions.act_window</field>
<field name="res_model">ir.attachment</field>
<field name="name">Directory</field>
<field name="view_type">form</field>
<field name="domain">[('parent_id','child_of',active_id)]</field>
<field name="context">{'parent_id':active_id}</field>
@ -348,6 +396,9 @@
res_model="ir.attachment"
src_model="document.directory"/>
</data>
</openerp>

View File

@ -339,7 +339,8 @@ class node_dir(node_database):
fil_id = fil_obj.create(cr, uid, val, context=ctx)
fil = fil_obj.browse(cr, uid, fil_id, context=ctx)
fnode = node_file(path, self, self.context, fil)
fnode.set_data(cr, data, fil)
if data is not None:
fnode.set_data(cr, data, fil)
return fnode
def get_etag(self, cr):
@ -667,7 +668,7 @@ class node_file(node_class):
self.file_id = fil.id
#todo: more info from ir_attachment
if fil.file_type and '/' in fil.file_type:
self.mimetype = fil.file_type
self.mimetype = str(fil.file_type)
self.create_date = fil.create_date
self.write_date = fil.write_date or fil.create_date
self.content_length = fil.file_size
@ -809,7 +810,7 @@ class node_content(node_class):
(self.extension,))
res = cr.fetchall()
if res and res[0][0]:
self.mimetype = res[0][0]
self.mimetype = str(res[0][0])
def get_data(self, cr, fil_obj = None):

View File

@ -19,16 +19,6 @@
#
##############################################################################
# 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.
#
##############################################################################
from osv import fields,osv
import time
@ -55,8 +45,8 @@ class report_document_user(osv.osv):
def init(self, cr):
tools.drop_view_if_exists(cr, 'report_document_user')
cr.execute("""
create or replace view report_document_user as (
select
CREATE OR REPLACE VIEW report_document_user as (
SELECT
min(f.id) as id,
to_char(f.create_date, 'YYYY') as name,
to_char(f.create_date, 'MM') as month,
@ -68,7 +58,7 @@ class report_document_user(osv.osv):
f.file_size as file_size,
min(d.type) as type,
f.write_date as change_date
from ir_attachment f
FROM ir_attachment f
left join document_directory d on (f.parent_id=d.id and d.name<>'')
inner join res_users u on (f.user_id=u.id)
group by to_char(f.create_date, 'YYYY'), to_char(f.create_date, 'MM'),d.name,f.parent_id,d.type,f.create_date,f.user_id,f.file_size,u.name,d.type,f.write_date
@ -95,7 +85,7 @@ class report_files_partner(osv.osv):
def init(self, cr):
tools.drop_view_if_exists(cr, 'report_files_partner')
cr.execute("""
create or replace view report_files_partner as (
CREATE VIEW report_files_partner as (
select min(f.id) as id,count(*) as nbr,
to_char(f.create_date,'YYYY') as name,
min(to_char(f.create_date,'MM')) as month,

View File

@ -49,14 +49,14 @@ def textToString(element) :
class TxtIndex(indexer):
def _getMimeTypes(self):
return ['text/plain','text/html','text/diff','text/xml', 'text/*',
'application/xml']
'application/xml']
def _getExtensions(self):
return ['.txt', '.py']
def _doIndexContent(self,content):
return content
cntIndex.register(TxtIndex())
class PptxIndex(indexer):
@ -95,8 +95,8 @@ class DocIndex(indexer):
return ['.doc']
def _doIndexFile(self,fname):
#fp = Popen(['antiword', fname], shell=False, stdout=PIPE).stdout
return _to_unicode( 'None')
fp = Popen(['antiword', fname], shell=False, stdout=PIPE).stdout
return _to_unicode(fp.read())
cntIndex.register(DocIndex())
@ -177,21 +177,33 @@ class ImageNoIndex(indexer):
cntIndex.register(ImageNoIndex())
#class Doc(indexer):
#def _getDefMime(self,ext):
# other opendocument formats:
# chart-template chart database
# formula-template formula graphics-template graphics
# image
# presentation-template presentation spreadsheet-template spreadsheet
class OpenDoc(indexer):
""" Index OpenDocument files.
Q: is it really worth it to index spreadsheets, or do we only get a
meaningless list of numbers (cell contents) ?
"""
def _getMimeTypes(self):
otypes = [ 'text', 'text-web', 'text-template', 'text-master' ]
return map(lambda a: 'application/vnd.oasis.opendocument.'+a, otypes)
def _getExtensions(self):
return ['.odt', '.ott', ] # '.ods'
def _doIndexContent(self, content):
s = StringIO.StringIO(content)
o = odt2txt.OpenDocumentTextFile(s)
result = _to_unicode(o.toString())
s.close()
return result
cntIndex.register(OpenDoc())
#def content_index(content, filename=None, content_type=None):
#fname,ext = os.path.splitext(filename)
#result = ''
#elif ext in ('.xls','.ods','.odt','.odp'):
#s = StringIO.StringIO(content)
#o = odt2txt.OpenDocumentTextFile(s)
#result = _to_unicode(o.toString())
#s.close()
#elif ext in ('.txt','.py','.patch','.html','.csv','.xml'):
#result = content
#else:
#result = content
#return result
#eof

View File

@ -31,6 +31,9 @@ for fname in args:
else:
res = cntIndex.doIndex(None, fname, None, fname,True)
if options.verbose:
for line in res[:5]:
print line
except Exception,e:
import traceback,sys
tb_s = reduce(lambda x, y: x+y, traceback.format_exception( sys.exc_type, sys.exc_value, sys.exc_traceback))

View File

@ -55,8 +55,6 @@ class openerp_dav_handler(dav_interface):
M_NS={ "DAV:" : dav_interface.M_NS['DAV:'],}
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
@ -65,10 +63,10 @@ class openerp_dav_handler(dav_interface):
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:
if cr: cr.close()
# TODO: maybe limit props for databases..?
return props
node = self.uri2object(cr, uid, pool, uri2)
if node:
@ -83,7 +81,6 @@ class openerp_dav_handler(dav_interface):
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()
@ -104,8 +101,7 @@ 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)
if uri[-1]=='/':uri=uri[:-1]
return dav_interface.get_prop(self, uri, ns, propname)
cr, uid, pool, dbname, uri2 = self.get_cr(uri)
if not dbname:
if cr: cr.close()
@ -114,19 +110,46 @@ class openerp_dav_handler(dav_interface):
if not node:
cr.close()
raise DAV_NotFound
res = node.get_dav_eprop(cr, ns, propname)
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 get_db(self, uri, rest_ret=False, allow_last=False):
"""Parse the uri and get the dbname and the rest.
Db name should be the first component in the unix-like
path supplied in uri.
@param rest_ret Instead of the db_name, return (db_name, rest),
where rest is the remaining path
@param allow_last If the dbname is the last component in the
path, allow it to be resolved. The default False value means
we will not attempt to use the db, unless there is more
path.
@return db_name or (dbname, rest) depending on rest_ret,
will return dbname=False when component is not found.
"""
uri2 = self.uri2local(uri)
if uri2.startswith('/'):
uri2 = uri2[1:]
names=uri2.split('/',1)
db_name=False
rest = None
if allow_last:
ll = 0
else:
ll = 1
if len(names) > ll and names[0]:
db_name = names[0]
names = names[1:]
if rest_ret:
if len(names):
rest = names[0]
return db_name, rest
return db_name
def urijoin(self,*ajoin):
""" Return the base URI of this request, or even join it with the
@ -140,20 +163,25 @@ class openerp_dav_handler(dav_interface):
result = s.exp_list()
self.db_name_list=[]
for db_name in result:
db = pooler.get_db_only(db_name)
cr = db.cursor()
cr.execute("select id from ir_module_module where name = 'document' and state='installed' ")
res=cr.fetchone()
if res and len(res):
self.db_name_list.append(db_name)
cr.close()
cr = None
try:
db = pooler.get_db_only(db_name)
cr = db.cursor()
cr.execute("SELECT id FROM ir_module_module WHERE name = 'document' AND state='installed' ")
res=cr.fetchone()
if res and len(res):
self.db_name_list.append(db_name)
except Exception, e:
self.parent.log_error("Exception in db list: %s" % e)
finally:
if cr:
cr.close()
return self.db_name_list
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)
cr, uid, pool, dbname, uri2 = self.get_cr(uri, allow_last=True)
if not dbname:
if cr: cr.close()
@ -194,38 +222,33 @@ class openerp_dav_handler(dav_interface):
#
# pos: -1 to get the parent of the uri
#
def get_cr(self, uri):
def get_cr(self, uri, allow_last=False):
""" Split the uri, grab a cursor for that db
"""
pdb = self.parent.auth_proxy.last_auth
reluri = self.uri2local(uri)
try:
dbname = reluri.split('/')[1]
except:
dbname = False
dbname, uri2 = self.get_db(uri, rest_ret=True, allow_last=allow_last)
uri2 = (uri2 and uri2.split('/')) or []
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)
return None, None, None, False, uri2
# if dbname was in our uri, we should have authenticated
# against that.
assert pdb == dbname, " %s != %s" %(pdb, dbname)
res = self.parent.auth_proxy.auth_creds.get(dbname, False)
if not res:
if not res:
self.parent.auth_proxy.checkRequest(self.parent, uri, dbname)
res = self.parent.auth_proxy.auth_creds[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('/')[2:]
return cr, uid, pool, dbname, uri2
def uri2object(self, cr, uid, pool,uri):
def uri2object(self, cr, uid, pool, uri):
if not uid:
return None
return pool.get('document.directory').get_object(cr, uid, uri)
def get_data(self,uri):
def get_data(self,uri, rrange=None):
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:
@ -234,6 +257,9 @@ class openerp_dav_handler(dav_interface):
if not node:
raise DAV_NotFound(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
@ -256,7 +282,6 @@ class openerp_dav_handler(dav_interface):
def _get_dav_resourcetype(self,uri):
""" 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)
try:
if not dbname:
@ -272,7 +297,6 @@ class openerp_dav_handler(dav_interface):
def _get_dav_displayname(self,uri):
self.parent.log_message('get DN: %s' % uri)
if uri[-1]=='/':uri=uri[:-1]
cr, uid, pool, dbname, uri2 = self.get_cr(uri)
if not dbname:
cr.close()
@ -288,7 +312,6 @@ class openerp_dav_handler(dav_interface):
def _get_dav_getcontentlength(self, uri):
""" 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)
if not dbname:
@ -306,7 +329,6 @@ class openerp_dav_handler(dav_interface):
def _get_dav_getetag(self,uri):
""" return the ETag of an object """
self.parent.log_message('get etag: %s' % uri)
if uri[-1]=='/':uri=uri[:-1]
result = 0
cr, uid, pool, dbname, uri2 = self.get_cr(uri)
if not dbname:
@ -323,7 +345,6 @@ class openerp_dav_handler(dav_interface):
@memoize(CACHE_SIZE)
def get_lastmodified(self, uri):
""" return the last modified date of the object """
if uri[-1]=='/':uri=uri[:-1]
today = time.time()
cr, uid, pool, dbname, uri2 = self.get_cr(uri)
if not dbname:
@ -342,7 +363,6 @@ class openerp_dav_handler(dav_interface):
@memoize(CACHE_SIZE)
def get_creationdate(self, uri):
""" return the last modified date of the object """
if uri[-1]=='/':uri=uri[:-1]
cr, uid, pool, dbname, uri2 = self.get_cr(uri)
if not dbname:
raise DAV_Error, 409
@ -361,7 +381,6 @@ class openerp_dav_handler(dav_interface):
@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)
if not dbname:
return 'httpd/unix-directory'
@ -369,7 +388,7 @@ class openerp_dav_handler(dav_interface):
node = self.uri2object(cr, uid, pool, uri2)
if not node:
raise DAV_NotFound(uri2)
result = node.mimetype
result = str(node.mimetype)
return result
#raise DAV_NotFound, 'Could not find %s' % path
finally:
@ -434,10 +453,8 @@ class openerp_dav_handler(dav_interface):
def rmcol(self,uri):
""" delete a collection """
if uri[-1]=='/':uri=uri[:-1]
cr, uid, pool, dbname, uri2 = self.get_cr(uri)
if not dbname: # *-*
if not dbname:
raise DAV_Error, 409
node = self.uri2object(cr, uid, pool, uri2)
node.rmcol(cr)
@ -447,7 +464,6 @@ class openerp_dav_handler(dav_interface):
return 204
def rm(self,uri):
if uri[-1]=='/':uri=uri[:-1]
cr, uid, pool,dbname, uri2 = self.get_cr(uri)
if not dbname:
cr.close()
@ -626,3 +642,5 @@ class openerp_dav_handler(dav_interface):
def is_collection(self, uri):
""" test if the given uri is a collection """
return self._get_dav_resourcetype(uri)==COLLECTION
#eof

View File

@ -3,6 +3,7 @@
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
# Copyright (c) 1999 Christian Scholz (ruebe@aachen.heimat.de)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
@ -48,7 +49,9 @@ def mk_prop_response(self, uri, good_props, bad_props, doc):
uparts=urlparse.urlparse(uri)
fileloc=uparts[2]
href=doc.createElement("D:href")
huri=doc.createTextNode(uparts[0]+'://'+'/'.join(uparts[1:2]) + urllib.quote(fileloc))
davpath = self._dataclass.parent.get_davpath()
hurl = '%s://%s%s%s' % (uparts[0], uparts[1], davpath, urllib.quote(fileloc))
huri=doc.createTextNode(hurl)
href.appendChild(huri)
re.appendChild(href)
@ -111,5 +114,45 @@ def mk_prop_response(self, uri, good_props, bad_props, doc):
return re
PROPFIND.mk_prop_response = mk_prop_response
def mk_propname_response(self,uri,propnames,doc):
""" make a new <prop> 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
uparts=urlparse.urlparse(uri)
fileloc=uparts[2]
href=doc.createElement("D:href")
davpath = self._dataclass.parent.get_davpath()
hurl = '%s://%s%s%s' % (uparts[0], uparts[1], davpath, urllib.quote(fileloc))
huri=doc.createTextNode(hurl)
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
PROPFIND.mk_prop_response = mk_prop_response
PROPFIND.mk_propname_response = mk_propname_response

View File

@ -33,6 +33,7 @@ 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 BaseHTTPServer import BaseHTTPRequestHandler
import urlparse
import urllib
from string import atoi,split
@ -42,6 +43,9 @@ def OpenDAVConfig(**kw):
class OpenDAV:
def __init__(self, **kw):
self.__dict__.update(**kw)
def getboolean(self, word):
return self.__dict__.get(word, False)
class Config:
DAV = OpenDAV(**kw)
@ -51,6 +55,7 @@ def OpenDAVConfig(**kw):
class DAVHandler(FixSendError,DAVRequestHandler):
verbose = False
protocol_version = 'HTTP/1.1'
def get_userinfo(self,user,pw):
return False
@ -64,18 +69,17 @@ class DAVHandler(FixSendError,DAVRequestHandler):
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)
# interface class will handle all cases.
res = self.IFACE_CLASS.get_db(uri, allow_last=True)
return res
def setup(self):
davpath = '/'+config.get_misc('webdav','vdir','webdav')
self.davpath = '/'+config.get_misc('webdav','vdir','webdav')
self.baseuri = "http://%s:%d/"% (self.server.server_name, self.server.server_port)
self.IFACE_CLASS = openerp_dav_handler(self, self.verbose)
def get_davpath(self):
return self.davpath
def log_message(self, format, *args):
netsvc.Logger().notifyChannel('webdav', netsvc.LOG_DEBUG_RPC, format % args)
@ -83,6 +87,17 @@ class DAVHandler(FixSendError,DAVRequestHandler):
def log_error(self, format, *args):
netsvc.Logger().notifyChannel('xmlrpc', netsvc.LOG_WARNING, format % args)
def send_response(self, code, message=None):
# the BufferingHttpServer will send Connection: close , while
# the BaseHTTPRequestHandler will only accept int code.
# workaround both of them.
BaseHTTPRequestHandler.send_response(self, int(code), message)
def send_header(self, key, value):
if key == 'Connection' and value == 'close':
self.close_connection = 1
DAVRequestHandler.send_header(self, key, value)
def do_PUT(self):
dc=self.IFACE_CLASS
uri=urlparse.urljoin(self.get_baseuri(dc), self.path)
@ -161,8 +176,18 @@ class DAVHandler(FixSendError,DAVRequestHandler):
self.send_body(None, '201', 'Created', '', headers=headers)
from service.http_server import reg_http_service,OpenERPAuthProvider
class DAVAuthProvider(OpenERPAuthProvider):
def authenticate(self, db, user, passwd, client_address):
""" authenticate, but also allow the False db, meaning to skip
authentication when no db is specified.
"""
if db is False:
return True
return OpenERPAuthProvider.authenticate(self, db, user, passwd, client_address)
try:
from service.http_server import reg_http_service,OpenERPAuthProvider
if (config.get_misc('webdav','enable',True)):
directory = '/'+config.get_misc('webdav','vdir','webdav')
@ -177,7 +202,7 @@ try:
conf = OpenDAVConfig(**_dc)
handler._config = conf
reg_http_service(HTTPDir(directory,DAVHandler,OpenERPAuthProvider()))
reg_http_service(HTTPDir(directory,DAVHandler,DAVAuthProvider()))
netsvc.Logger().notifyChannel('webdav', netsvc.LOG_INFO, "WebDAV service registered at path: %s/ "% directory)
except Exception, e:
logger = netsvc.Logger()