commit
1c81281413
|
@ -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',
|
||||
|
|
|
@ -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"/>
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
Loading…
Reference in New Issue