summaryrefslogtreecommitdiff
path: root/addons/document
diff options
context:
space:
mode:
authorNaresh Choksy <nch@tinyerp.com>2008-11-04 11:16:45 +0530
committerNaresh Choksy <nch@tinyerp.com>2008-11-04 11:16:45 +0530
commit2a4096b752f3634fe255ecd78e842e11d1801a67 (patch)
tree9ed47e680afe293497461adf430f146c60e97da2 /addons/document
parent54651e2f34af1412df5ab5d3e371bdc4d0600b23 (diff)
parentda8aa7411aef2f2b962b2b67b73563dce4c45bee (diff)
merges
bzr revid: nch@tinyerp.com-20081104054645-pqtvoho3hiyjb2yf
Diffstat (limited to 'addons/document')
-rw-r--r--addons/document/__init__.py34
-rw-r--r--addons/document/__terp__.py63
-rw-r--r--addons/document/content_index.py21
-rw-r--r--addons/document/document.py1229
-rw-r--r--addons/document/document_data.xml7
-rw-r--r--addons/document/document_demo.xml133
-rw-r--r--addons/document/document_view.xml71
-rw-r--r--addons/document/ftpserver/abstracted_fs.py1488
-rw-r--r--addons/document/ftpserver/authorizer.py131
-rw-r--r--addons/document/ftpserver/ftpserver.py11
-rw-r--r--addons/document/i18n/document.pot392
-rw-r--r--addons/document/i18n/fr_FR.po392
-rw-r--r--addons/document/odt2txt.py21
-rw-r--r--addons/document/process/document_process.xml25
-rw-r--r--addons/document/security/ir.model.access.csv2
15 files changed, 2433 insertions, 1587 deletions
diff --git a/addons/document/__init__.py b/addons/document/__init__.py
index dc51bcd02e7..6beb56a4c8d 100644
--- a/addons/document/__init__.py
+++ b/addons/document/__init__.py
@@ -1,28 +1,22 @@
+# -*- encoding: utf-8 -*-
##############################################################################
#
-# Copyright (c) 2004 TINY SPRL. (http://tiny.be) All Rights Reserved.
-# Fabien Pinckaers <fp@tiny.Be>
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-2008 Tiny SPRL (<http://tiny.be>). All Rights Reserved
+# $Id$
#
-# WARNING: This program as such is intended to be used by professional
-# programmers who take the whole responsability of assessing all potential
-# consequences resulting from its eventual inadequacies and bugs
-# End users who are looking for a ready-to-use solution with commercial
-# garantees and support are strongly adviced to contract a Free Software
-# Service Company
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
#
-# This program is Free Software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
diff --git a/addons/document/__terp__.py b/addons/document/__terp__.py
index aafdbebdb1a..6c6aa6adb24 100644
--- a/addons/document/__terp__.py
+++ b/addons/document/__terp__.py
@@ -1,26 +1,47 @@
+# -*- encoding: utf-8 -*-
+##############################################################################
#
-# Use the custom module to put your specific code in a separate module.
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-2008 Tiny SPRL (<http://tiny.be>). All Rights Reserved
+# $Id$
#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
{
- "name" : "Integrated Document Management System",
- "version" : "1.0",
- "author" : "Tiny",
- "category" : "Generic Modules/Others",
- "website": "http://www.tinyerp.com",
- "description": """This is a complete document management system:
- * FTP Interface
- * User Authentification
- * Document Indexation
+ "name" : "Integrated Document Management System",
+ "version" : "1.0",
+ "author" : "Tiny",
+ "category" : "Generic Modules/Others",
+ "website": "http://www.tinyerp.com",
+ "description": """This is a complete document management system:
+ * FTP Interface
+ * User Authentification
+ * Document Indexation
""",
- "depends" : ["base", "process", "hr"],
- "init_xml" : ["document_data.xml"],
- "update_xml" : [
- "document_view.xml",
- "security/document_security.xml",
- "security/ir.model.access.csv",
- "process/document_process.xml"
- ],
- "demo_xml" : ["document_demo.xml"],
- "active": False,
- "installable": True
+ "depends" : ["base","process"],
+ "init_xml" : [
+ "document_data.xml",
+ "document_demo.xml"
+ ],
+ "update_xml" : [
+ "document_view.xml",
+ "document_data.xml",
+ "security/document_security.xml",
+ "security/ir.model.access.csv",
+ ],
+ "demo_xml" : [],
+ "active": False,
+ "installable": True
}
diff --git a/addons/document/content_index.py b/addons/document/content_index.py
index c4ec7c2c795..080e055b978 100644
--- a/addons/document/content_index.py
+++ b/addons/document/content_index.py
@@ -1,3 +1,24 @@
+# -*- encoding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-2008 Tiny SPRL (<http://tiny.be>). All Rights Reserved
+# $Id$
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
import time
import os
import StringIO
diff --git a/addons/document/document.py b/addons/document/document.py
index d7904d31285..79d8960363b 100644
--- a/addons/document/document.py
+++ b/addons/document/document.py
@@ -1,30 +1,22 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
-# Copyright (c) 2004-2008 TINY SPRL. (http://tiny.be) All Rights Reserved.
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-2008 Tiny SPRL (<http://tiny.be>). All Rights Reserved
+# $Id$
#
-# $Id$
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
#
-# WARNING: This program as such is intended to be used by professional
-# programmers who take the whole responsability of assessing all potential
-# consequences resulting from its eventual inadequacies and bugs
-# End users who are looking for a ready-to-use solution with commercial
-# garantees and support are strongly adviced to contract a Free Software
-# Service Company
+# This program is 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.
#
-# This program is Free Software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
@@ -38,6 +30,8 @@ import os
import pooler
from content_index import content_index
+import netsvc
+import StringIO
# Unsupported WebDAV Commands:
# label
@@ -59,374 +53,405 @@ from content_index import content_index
#
INVALID_CHARS={'*':str(hash('*')), '|':str(hash('|')) , "\\":str(hash("\\")), '/':'__', ':':str(hash(':')), '"':str(hash('"')), '<':str(hash('<')) , '>':str(hash('>')) , '?':str(hash('?'))}
class node_class(object):
- def __init__(self, cr, uid, path,object,object2=False, context={}, content=False, type='collection', root=False):
- self.cr = cr
- self.uid = uid
- self.path = path
- self.object = object
- self.object2 = object2
- self.context = context
- self.content = content
- self.type=type
- self.root=root
-
- def _file_get(self, nodename=False):
- if not self.object:
- return []
- pool = pooler.get_pool(self.cr.dbname)
- fobj = pool.get('ir.attachment')
- res2 = []
- where = []
- if self.object2:
- where.append( ('res_model','=',self.object2._name) )
- where.append( ('res_id','=',self.object2.id) )
- for content in self.object.content_ids:
- test_nodename = self.object2.name + (content.suffix or '') + (content.extension or '')
- if test_nodename.find('/'):
- test_nodename=test_nodename.replace('/', '_')
- path = self.path+'/'+test_nodename
- #path = self.path+'/'+self.object2.name + (content.suffix or '') + (content.extension or '')
- if not nodename:
- n = node_class(self.cr, self.uid,path, self.object2, False, content=content, type='content', root=False)
- res2.append( n)
- else:
- if nodename == test_nodename:
- n = node_class(self.cr, self.uid, path, self.object2, False, content=content, type='content', root=False)
- res2.append(n)
- else:
- where.append( ('parent_id','=',self.object.id) )
- where.append( ('res_id','=',False) )
- if nodename:
- where.append( (fobj._rec_name,'=',nodename) )
- ids = fobj.search(self.cr, self.uid, where+[ ('parent_id','=',self.object and self.object.id or False) ], context=self.context)
- if self.object and self.root and (self.object.type=='ressource'):
- ids += fobj.search(self.cr, self.uid, where+[ ('parent_id','=',False) ], context=self.context)
- res = fobj.browse(self.cr, self.uid, ids, context=self.context)
- return map(lambda x: node_class(self.cr, self.uid, self.path+'/'+x.name, x, False, type='file', root=False), res) + res2
-
- def directory_list_for_child(self,nodename,parent=False):
- pool = pooler.get_pool(self.cr.dbname)
- where = []
- if nodename:
- where.append(('name','=',nodename))
- if (self.object and self.object.type=='directory') or not self.object2:
- where.append(('parent_id','=',self.object and self.object.id or False))
- else:
- where.append(('parent_id','=',False))
- if self.object:
- where.append(('ressource_parent_type_id','=',self.object.ressource_type_id.id))
- else:
- where.append(('ressource_parent_type_id','=',False))
-
- ids = pool.get('document.directory').search(self.cr, self.uid, where+[('ressource_id','=',0)], self.context)
- if self.object2:
- ids += pool.get('document.directory').search(self.cr, self.uid, where+[('ressource_id','=',self.object2.id)], self.context)
- res = pool.get('document.directory').browse(self.cr, self.uid, ids,self.context)
- return res
-
- def _child_get(self, nodename=False):
- if self.type not in ('collection','database'):
- return []
- res = self.directory_list_for_child(nodename)
- result= map(lambda x: node_class(self.cr, self.uid, self.path+'/'+x.name, x, x.type=='directory' and self.object2 or False, root=self.root), res)
- if self.type=='database':
- pool = pooler.get_pool(self.cr.dbname)
- fobj = pool.get('ir.attachment')
- vargs = [('parent_id','=',False),('res_id','=',False)]
- if nodename:
- vargs.append(('name','=',nodename))
- file_ids=fobj.search(self.cr,self.uid,vargs)
-
- res = fobj.browse(self.cr, self.uid, file_ids, context=self.context)
- result +=map(lambda x: node_class(self.cr, self.uid, self.path+'/'+x.name, x, False, type='file', root=self.root), res)
- if self.type=='collection' and self.object.type=="ressource":
- where = self.object.domain and eval(self.object.domain, {'active_id':self.root}) or []
- pool = pooler.get_pool(self.cr.dbname)
- obj = pool.get(self.object.ressource_type_id.model)
-
- if self.object.ressource_tree:
- if obj._parent_name in obj.fields_get(self.cr,self.uid):
- where.append((obj._parent_name,'=',self.object2 and self.object2.id or False))
- else :
- if self.object2:
- return result
- else:
- if self.object2:
- return result
-
- name_for = obj._name.split('.')[-1]
- if nodename and nodename.find(name_for) == 0 :
- id = int(nodename.replace(name_for,''))
- where.append(('id','=',id))
- elif nodename:
- if nodename.find('__') :
- nodename=nodename.replace('__','/')
- for invalid in INVALID_CHARS:
- if nodename.find(INVALID_CHARS[invalid]) :
- nodename=nodename.replace(INVALID_CHARS[invalid],invalid)
- where.append(('name','=',nodename))
- ids = obj.search(self.cr, self.uid, where, self.context)
- res = obj.browse(self.cr, self.uid, ids,self.context)
- for r in res:
- if not r.name:
- r.name = name_for+'%d'%r.id
- for invalid in INVALID_CHARS:
- if r.name.find(invalid) :
- r.name=r.name.replace(invalid,INVALID_CHARS[invalid])
- result2 = map(lambda x: node_class(self.cr, self.uid, self.path+'/'+x.name.replace('/','__'), self.object, x, root=r.id), res)
- if result2:
- result = result2
- return result
-
- def children(self):
- return self._child_get() + self._file_get()
-
- def child(self, name):
- res = self._child_get(name)
- if res:
- return res[0]
- res = self._file_get(name)
- if res:
- return res[0]
- return None
-
- def path_get(self):
- path = self.path
- if self.path[0]=='/':
- path = self.path[1:]
- return path
+ def __init__(self, cr, uid, path,object,object2=False, context={}, content=False, type='collection', root=False):
+ self.cr = cr
+ self.uid = uid
+ self.path = path
+ self.object = object
+ self.object2 = object2
+ self.context = context
+ self.content = content
+ self.type=type
+ self.root=root
+
+ def _file_get(self, nodename=False):
+ if not self.object:
+ return []
+ pool = pooler.get_pool(self.cr.dbname)
+ fobj = pool.get('ir.attachment')
+ res2 = []
+ where = []
+ if self.object2:
+ where.append( ('res_model','=',self.object2._name) )
+ where.append( ('res_id','=',self.object2.id) )
+ for content in self.object.content_ids:
+ if self.object2 or not content.include_name:
+ if content.include_name:
+ test_nodename = self.object2.name + (content.suffix or '') + (content.extension or '')
+ else:
+ test_nodename = (content.suffix or '') + (content.extension or '')
+ if test_nodename.find('/'):
+ test_nodename=test_nodename.replace('/', '_')
+ path = self.path+'/'+test_nodename
+ #path = self.path+'/'+self.object2.name + (content.suffix or '') + (content.extension or '')
+ if not nodename:
+ n = node_class(self.cr, self.uid,path, self.object2, False, content=content, type='content', root=False)
+ res2.append( n)
+ else:
+ if nodename == test_nodename:
+ n = node_class(self.cr, self.uid, path, self.object2, False, content=content, type='content', root=False)
+ res2.append(n)
+ else:
+ where.append( ('parent_id','=',self.object.id) )
+ where.append( ('res_id','=',False) )
+ if nodename:
+ where.append( (fobj._rec_name,'=',nodename) )
+ ids = fobj.search(self.cr, self.uid, where+[ ('parent_id','=',self.object and self.object.id or False) ], context=self.context)
+ if self.object and self.root and (self.object.type=='ressource'):
+ ids += fobj.search(self.cr, self.uid, where+[ ('parent_id','=',False) ], context=self.context)
+ res = fobj.browse(self.cr, self.uid, ids, context=self.context)
+ return map(lambda x: node_class(self.cr, self.uid, self.path+'/'+x.name, x, False, type='file', root=False), res) + res2
+
+ def directory_list_for_child(self,nodename,parent=False):
+ pool = pooler.get_pool(self.cr.dbname)
+ where = []
+ if nodename:
+ where.append(('name','=',nodename))
+ if (self.object and self.object.type=='directory') or not self.object2:
+ where.append(('parent_id','=',self.object and self.object.id or False))
+ else:
+ where.append(('parent_id','=',False))
+ if self.object:
+ where.append(('ressource_parent_type_id','=',self.object.ressource_type_id.id))
+ else:
+ where.append(('ressource_parent_type_id','=',False))
+
+ ids = pool.get('document.directory').search(self.cr, self.uid, where+[('ressource_id','=',0)], self.context)
+ if self.object2:
+ ids += pool.get('document.directory').search(self.cr, self.uid, where+[('ressource_id','=',self.object2.id)], self.context)
+ res = pool.get('document.directory').browse(self.cr, self.uid, ids,self.context)
+ return res
+
+ def _child_get(self, nodename=False):
+ if self.type not in ('collection','database'):
+ return []
+ res = self.directory_list_for_child(nodename)
+ result= map(lambda x: node_class(self.cr, self.uid, self.path+'/'+x.name, x, x.type=='directory' and self.object2 or False, root=self.root), res)
+ if self.type=='database':
+ pool = pooler.get_pool(self.cr.dbname)
+ fobj = pool.get('ir.attachment')
+ vargs = [('parent_id','=',False),('res_id','=',False)]
+ if nodename:
+ vargs.append(('name','=',nodename))
+ file_ids=fobj.search(self.cr,self.uid,vargs)
+
+ res = fobj.browse(self.cr, self.uid, file_ids, context=self.context)
+ result +=map(lambda x: node_class(self.cr, self.uid, self.path+'/'+x.name, x, False, type='file', root=self.root), res)
+ if self.type=='collection' and self.object.type=="ressource":
+ where = self.object.domain and eval(self.object.domain, {'active_id':self.root}) or []
+ pool = pooler.get_pool(self.cr.dbname)
+ obj = pool.get(self.object.ressource_type_id.model)
+
+ if self.object.ressource_tree:
+ if obj._parent_name in obj.fields_get(self.cr,self.uid):
+ where.append((obj._parent_name,'=',self.object2 and self.object2.id or False))
+ else :
+ if self.object2:
+ return result
+ else:
+ if self.object2:
+ return result
+
+ name_for = obj._name.split('.')[-1]
+ if nodename and nodename.find(name_for) == 0 :
+ id = int(nodename.replace(name_for,''))
+ where.append(('id','=',id))
+ elif nodename:
+ if nodename.find('__') :
+ nodename=nodename.replace('__','/')
+ for invalid in INVALID_CHARS:
+ if nodename.find(INVALID_CHARS[invalid]) :
+ nodename=nodename.replace(INVALID_CHARS[invalid],invalid)
+ where.append(('name','=',nodename))
+ ids = obj.search(self.cr, self.uid, where, self.context)
+ res = obj.browse(self.cr, self.uid, ids,self.context)
+ for r in res:
+ if not r.name:
+ r.name = name_for+'%d'%r.id
+ for invalid in INVALID_CHARS:
+ if r.name.find(invalid) :
+ r.name=r.name.replace(invalid,INVALID_CHARS[invalid])
+ result2 = map(lambda x: node_class(self.cr, self.uid, self.path+'/'+x.name.replace('/','__'), self.object, x, root=r.id), res)
+ if result2:
+ result = result2
+ return result
+
+ def children(self):
+ return self._child_get() + self._file_get()
+
+ def child(self, name):
+ res = self._child_get(name)
+ if res:
+ return res[0]
+ res = self._file_get(name)
+ if res:
+ return res[0]
+ return None
+
+ def path_get(self):
+ path = self.path
+ if self.path[0]=='/':
+ path = self.path[1:]
+ return path
class document_directory(osv.osv):
- _name = 'document.directory'
- _description = 'Document directory'
- _columns = {
- 'name': fields.char('Name', size=64, required=True, select=1),
- 'write_date': fields.datetime('Date Modified', readonly=True),
- 'write_uid': fields.many2one('res.users', 'Last Modification User', readonly=True),
- 'create_date': fields.datetime('Date Created', readonly=True),
- 'create_uid': fields.many2one('res.users', 'Creator', readonly=True),
- 'file_type': fields.char('Content Type', size=32),
- 'domain': fields.char('Domain', size=128),
- 'user_id': fields.many2one('res.users', 'Owner'),
- 'group_ids': fields.many2many('res.groups', 'document_directory_group_rel', 'item_id', 'group_id', 'Groups'),
- 'parent_id': fields.many2one('document.directory', 'Parent Item'),
- 'child_ids': fields.one2many('document.directory', 'parent_id', 'Childs'),
- 'file_ids': fields.one2many('ir.attachment', 'parent_id', 'Files'),
- 'content_ids': fields.one2many('document.directory.content', 'directory_id', 'Virtual Files'),
- 'type': fields.selection([('directory','Static Directory'),('ressource','Other Ressources')], 'Type', required=True),
- 'ressource_type_id': fields.many2one('ir.model', 'Childs Model'),
- 'ressource_parent_type_id': fields.many2one('ir.model', 'Linked Model'),
- 'ressource_id': fields.integer('Ressource ID'),
- 'ressource_tree': fields.boolean('Tree Structure'),
- }
- _defaults = {
- 'user_id': lambda self,cr,uid,ctx: uid,
- 'domain': lambda self,cr,uid,ctx: '[]',
- 'type': lambda *args: 'directory',
- }
- _sql_constraints = [
- ('dirname_uniq', 'unique (name,parent_id,ressource_id,ressource_parent_type_id)', 'The directory name must be unique !')
- ]
-
- def get_resource_path(self,cr,uid,dir_id,res_model,res_id):
- # this method will be used in process module
- # to be need test and Improvement if resource dir has parent resource (link resource)
- path=[]
- def _parent(dir_id,path):
- parent=self.browse(cr,uid,dir_id)
- if parent.parent_id and not parent.ressource_parent_type_id:
- _parent(parent.parent_id.id,path)
- path.append(parent.name)
- else:
- path.append(parent.name)
- return path
-
- directory=self.browse(cr,uid,dir_id)
- model_ids=self.pool.get('ir.model').search(cr,uid,[('model','=',res_model)])
- if directory:
- _parent(dir_id,path)
- path.append(self.pool.get(directory.ressource_type_id.model).browse(cr,uid,res_id).name)
- user=self.pool.get('res.users').browse(cr,uid,uid)
- #print "ftp://%s:%s@localhost:8021/%s/%s"%(user.login,user.password,cr.dbname,'/'.join(path))
- return "ftp://%s:%s@localhost:8021/%s/%s"%(user.login,user.password,cr.dbname,'/'.join(path))
- return False
- def _check_duplication(self, cr, uid,vals):
- if 'name' in vals:
- where=" name='%s'"% (vals['name'])
- if not 'parent_id' in vals or not vals['parent_id']:
- where+=' and parent_id is null'
- else:
- where+=' and parent_id=%d'%(vals['parent_id'])
- if not 'ressource_parent_type_id' in vals or not vals['ressource_parent_type_id']:
- where+= ' and ressource_parent_type_id is null'
- else:
- where+=" and ressource_parent_type_id='%s'"%(vals['ressource_parent_type_id'])
-# if not 'ressource_id' in vals or not vals['ressource_id']:
-# where+= ' and ressource_id is null'
-# else:
-# where+=" and ressource_id=%d"%(vals['ressource_id'])
- cr.execute("select id from document_directory where" + where)
- res = cr.fetchall()
- if len(res):
- return False
- return True
- def _check_recursion(self, cr, uid, ids):
- level = 100
- while len(ids):
- cr.execute('select distinct parent_id from document_directory where id in ('+','.join(map(str,ids))+')')
- ids = filter(None, map(lambda x:x[0], cr.fetchall()))
- if not level:
- return False
- level -= 1
- return True
-
- _constraints = [
- (_check_recursion, 'Error! You can not create recursive Directories.', ['parent_id'])
- ]
- def __init__(self, *args, **kwargs):
- res = super(document_directory, self).__init__(*args, **kwargs)
- self._cache = {}
- return res
-
- def onchange_content_id(self, cr, uid, ids, ressource_type_id):
- return {}
-
- def _get_childs(self, cr, uid, node, nodename=False, context={}):
- where = []
- if nodename:
- where.append(('name','=',nodename))
- if object:
- where.append(('parent_id','=',object.id))
- ids = self.search(cr, uid, where, context)
- return self.browse(cr, uid, ids, context), False
-
- """
- PRE:
- uri: of the form "Sales Order/SO001"
- PORT:
- uri
- object: the object.directory or object.directory.content
- object2: the other object linked (if object.directory.content)
- """
- def get_object(self, cr, uid, uri, context={}):
- if not uri:
- return node_class(cr, uid, '', False, type='database')
- turi = tuple(uri)
- if False and (turi in self._cache):
- (path, oo, oo2, content,type,root) = self._cache[turi]
- if oo:
- object = self.pool.get(oo[0]).browse(cr, uid, oo[1], context)
- else:
- object = False
- if oo2:
- object2 = self.pool.get(oo2[0]).browse(cr, uid, oo2[1], context)
- else:
- object2 = False
- node = node_class(cr, uid, path, object,object2, context, content, type, root)
- return node
-
- node = node_class(cr, uid, '/', False, type='database')
- for path in uri[:]:
- if path:
- node = node.child(path)
- if not node:
- return False
- oo = node.object and (node.object._name, node.object.id) or False
- oo2 = node.object2 and (node.object2._name, node.object2.id) or False
- self._cache[turi] = (node.path, oo, oo2, node.content,node.type,node.root)
- return node
-
- def get_childs(self, cr, uid, uri, context={}):
- node = self.get_object(cr, uid, uri, context)
- if uri:
- children = node.children()
- else:
- children= [node]
- result = map(lambda node: node.path_get(), children)
- #childs,object2 = self._get_childs(cr, uid, object, False, context)
- #result = map(lambda x: urlparse.urljoin(path+'/',x.name), childs)
- return result
-
- def write(self, cr, uid, ids, vals, context=None):
- # need to make constraints to checking duplicate
- #if not self._check_duplication(cr,uid,vals):
- # raise except_orm('ValidateError', 'Directory name must be unique!')
- return super(document_directory,self).write(cr,uid,ids,vals,context=context)
-
- def copy(self, cr, uid, id, default=None, context=None):
- if not default:
- default ={}
- name = self.read(cr, uid, [id])[0]['name']
- default.update({'name': name+ " (copy)"})
- return super(document_directory,self).copy(cr,uid,id,default,context)
-
- def create(self, cr, uid, vals, context=None):
- if not self._check_duplication(cr,uid,vals):
- raise except_orm('ValidateError', 'Directory name must be unique!')
- if vals.get('name',False) and (vals.get('name').find('/')+1 or vals.get('name').find('@')+1 or vals.get('name').find('$')+1 or vals.get('name').find('#')+1) :
- raise 'Error'
- return super(document_directory,self).create(cr, uid, vals, context)
+ _name = 'document.directory'
+ _description = 'Document directory'
+ _columns = {
+ 'name': fields.char('Name', size=64, required=True, select=1),
+ 'write_date': fields.datetime('Date Modified', readonly=True),
+ 'write_uid': fields.many2one('res.users', 'Last Modification User', readonly=True),
+ 'create_date': fields.datetime('Date Created', readonly=True),
+ 'create_uid': fields.many2one('res.users', 'Creator', readonly=True),
+ 'file_type': fields.char('Content Type', size=32),
+ 'domain': fields.char('Domain', size=128),
+ 'user_id': fields.many2one('res.users', 'Owner'),
+ 'group_ids': fields.many2many('res.groups', 'document_directory_group_rel', 'item_id', 'group_id', 'Groups'),
+ 'parent_id': fields.many2one('document.directory', 'Parent Item'),
+ 'child_ids': fields.one2many('document.directory', 'parent_id', 'Childs'),
+ 'file_ids': fields.one2many('ir.attachment', 'parent_id', 'Files'),
+ 'content_ids': fields.one2many('document.directory.content', 'directory_id', 'Virtual Files'),
+ 'type': fields.selection([('directory','Static Directory'),('ressource','Other Ressources')], 'Type', required=True),
+ 'ressource_type_id': fields.many2one('ir.model', 'Childs Model'),
+ 'ressource_parent_type_id': fields.many2one('ir.model', 'Linked Model'),
+ 'ressource_id': fields.integer('Ressource ID'),
+ 'ressource_tree': fields.boolean('Tree Structure'),
+ }
+ _defaults = {
+ 'user_id': lambda self,cr,uid,ctx: uid,
+ 'domain': lambda self,cr,uid,ctx: '[]',
+ 'type': lambda *args: 'directory',
+ 'ressource_id': lambda *a: 0
+ }
+ _sql_constraints = [
+ ('dirname_uniq', 'unique (name,parent_id,ressource_id,ressource_parent_type_id)', 'The directory name must be unique !')
+ ]
+
+ def get_resource_path(self,cr,uid,dir_id,res_model,res_id):
+ # this method will be used in process module
+ # to be need test and Improvement if resource dir has parent resource (link resource)
+ path=[]
+ def _parent(dir_id,path):
+ parent=self.browse(cr,uid,dir_id)
+ if parent.parent_id and not parent.ressource_parent_type_id:
+ _parent(parent.parent_id.id,path)
+ path.append(parent.name)
+ else:
+ path.append(parent.name)
+ return path
+
+ directory=self.browse(cr,uid,dir_id)
+ model_ids=self.pool.get('ir.model').search(cr,uid,[('model','=',res_model)])
+ if directory:
+ _parent(dir_id,path)
+ path.append(self.pool.get(directory.ressource_type_id.model).browse(cr,uid,res_id).name)
+ user=self.pool.get('res.users').browse(cr,uid,uid)
+ return "ftp://%s:%s@localhost:8021/%s/%s"%(user.login,user.password,cr.dbname,'/'.join(path))
+ return False
+ def _check_duplication(self, cr, uid,vals):
+ if 'name' in vals:
+ where=" name='%s'"% (vals['name'])
+ if not 'parent_id' in vals or not vals['parent_id']:
+ where+=' and parent_id is null'
+ else:
+ where+=' and parent_id=%d'%(vals['parent_id'])
+ if not 'ressource_parent_type_id' in vals or not vals['ressource_parent_type_id']:
+ where+= ' and ressource_parent_type_id is null'
+ else:
+ where+=" and ressource_parent_type_id='%s'"%(vals['ressource_parent_type_id'])
+# if not 'ressource_id' in vals or not vals['ressource_id']:
+# where+= ' and ressource_id is null'
+# else:
+# where+=" and ressource_id=%d"%(vals['ressource_id'])
+ cr.execute("select id from document_directory where" + where)
+ res = cr.fetchall()
+ if len(res):
+ return False
+ return True
+ def _check_recursion(self, cr, uid, ids):
+ level = 100
+ while len(ids):
+ cr.execute('select distinct parent_id from document_directory where id in ('+','.join(map(str,ids))+')')
+ ids = filter(None, map(lambda x:x[0], cr.fetchall()))
+ if not level:
+ return False
+ level -= 1
+ return True
+
+ _constraints = [
+ (_check_recursion, 'Error! You can not create recursive Directories.', ['parent_id'])
+ ]
+ def __init__(self, *args, **kwargs):
+ res = super(document_directory, self).__init__(*args, **kwargs)
+ self._cache = {}
+ return res
+
+ def onchange_content_id(self, cr, uid, ids, ressource_type_id):
+ return {}
+
+ def _get_childs(self, cr, uid, node, nodename=False, context={}):
+ where = []
+ if nodename:
+ where.append(('name','=',nodename))
+ if object:
+ where.append(('parent_id','=',object.id))
+ ids = self.search(cr, uid, where, context)
+ return self.browse(cr, uid, ids, context), False
+
+ """
+ PRE:
+ uri: of the form "Sales Order/SO001"
+ PORT:
+ uri
+ object: the object.directory or object.directory.content
+ object2: the other object linked (if object.directory.content)
+ """
+ def get_object(self, cr, uid, uri, context={}):
+ if not uri:
+ return node_class(cr, uid, '', False, type='database')
+ turi = tuple(uri)
+ if False and (turi in self._cache):
+ (path, oo, oo2, content,type,root) = self._cache[turi]
+ if oo:
+ object = self.pool.get(oo[0]).browse(cr, uid, oo[1], context)
+ else:
+ object = False
+ if oo2:
+ object2 = self.pool.get(oo2[0]).browse(cr, uid, oo2[1], context)
+ else:
+ object2 = False
+ node = node_class(cr, uid, path, object,object2, context, content, type, root)
+ return node
+
+ node = node_class(cr, uid, '/', False, type='database')
+ for path in uri[:]:
+ if path:
+ node = node.child(path)
+ if not node:
+ return False
+ oo = node.object and (node.object._name, node.object.id) or False
+ oo2 = node.object2 and (node.object2._name, node.object2.id) or False
+ self._cache[turi] = (node.path, oo, oo2, node.content,node.type,node.root)
+ return node
+
+ def get_childs(self, cr, uid, uri, context={}):
+ node = self.get_object(cr, uid, uri, context)
+ if uri:
+ children = node.children()
+ else:
+ children= [node]
+ result = map(lambda node: node.path_get(), children)
+ #childs,object2 = self._get_childs(cr, uid, object, False, context)
+ #result = map(lambda x: urlparse.urljoin(path+'/',x.name), childs)
+ return result
+
+ def write(self, cr, uid, ids, vals, context=None):
+ # need to make constraints to checking duplicate
+ #if not self._check_duplication(cr,uid,vals):
+ # raise except_orm('ValidateError', 'Directory name must be unique!')
+ return super(document_directory,self).write(cr,uid,ids,vals,context=context)
+
+ def copy(self, cr, uid, id, default=None, context=None):
+ if not default:
+ default ={}
+ name = self.read(cr, uid, [id])[0]['name']
+ default.update({'name': name+ " (copy)"})
+ return super(document_directory,self).copy(cr,uid,id,default,context)
+
+ def create(self, cr, uid, vals, context=None):
+ if not self._check_duplication(cr,uid,vals):
+ raise except_orm('ValidateError', 'Directory name must be unique!')
+ if vals.get('name',False) and (vals.get('name').find('/')+1 or vals.get('name').find('@')+1 or vals.get('name').find('$')+1 or vals.get('name').find('#')+1) :
+ raise 'Error'
+ return super(document_directory,self).create(cr, uid, vals, context)
document_directory()
class document_directory_node(osv.osv):
- _inherit = 'process.node'
- _columns = {
- 'directory_id': fields.many2one('document.directory', 'Document directory', ondelete="set null"),
- }
+ _inherit = 'process.node'
+ _columns = {
+ 'directory_id': fields.many2one('document.directory', 'Document directory', ondelete="set null"),
+ }
document_directory_node()
+class document_directory_content_type(osv.osv):
+ _name = 'document.directory.content.type'
+ _description = 'Directory Content Type'
+ _columns = {
+ 'name': fields.char('Content Type', size=64, required=True),
+ 'code': fields.char('Extension', size=4),
+ 'active': fields.boolean('Active'),
+ }
+ _defaults = {
+ 'active': lambda *args: 1
+ }
+document_directory_content_type()
+
class document_directory_content(osv.osv):
- _name = 'document.directory.content'
- _description = 'Directory Content'
- _order = "sequence"
- _columns = {
- 'name': fields.char('Content Name', size=64, required=True),
- 'sequence': fields.integer('Sequence', size=16),
- 'suffix': fields.char('Suffix', size=16),
- 'versioning': fields.boolean('Versioning'),
- 'report_id': fields.many2one('ir.actions.report.xml', 'Report', required=True),
- 'extension': fields.selection([('.pdf','.pdf'),('','None')], 'Extension', required=True),
- 'directory_id': fields.many2one('document.directory', 'Directory')
- }
- _defaults = {
- 'extension': lambda *args: '',
- 'sequence': lambda *args: 1
- }
+ _name = 'document.directory.content'
+ _description = 'Directory Content'
+ _order = "sequence"
+ def _extension_get(self, cr, uid, context={}):
+ cr.execute('select code,name from document_directory_content_type where active')
+ res = cr.fetchall()
+ return res
+ _columns = {
+ 'name': fields.char('Content Name', size=64, required=True),
+ 'sequence': fields.integer('Sequence', size=16),
+ '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 if you cant that the name of the file start by the record name."),
+ 'directory_id': fields.many2one('document.directory', 'Directory'),
+ }
+ _defaults = {
+ 'extension': lambda *args: '.pdf',
+ 'sequence': lambda *args: 1,
+ 'include_name': lambda *args: 1,
+ }
+ def process_write_pdf(self, cr, uid, node, context={}):
+ return True
+ def process_read_pdf(self, cr, uid, node, context={}):
+ report = self.pool.get('ir.actions.report.xml').browse(cr, uid, node.content.report_id.id)
+ srv = netsvc.LocalService('report.'+report.report_name)
+ pdf,pdftype = srv.create(cr, uid, [node.object.id], {}, {})
+ s = StringIO.StringIO(pdf)
+ s.name = node
+ return s
document_directory_content()
class ir_action_report_xml(osv.osv):
- _name="ir.actions.report.xml"
- _inherit ="ir.actions.report.xml"
-
- def _model_get(self, cr, uid, ids, name, arg, context):
- res = {}
- model_pool = self.pool.get('ir.model')
- for data in self.read(cr,uid,ids,['model']):
- model = data.get('model',False)
- if model:
- model_id =model_pool.search(cr,uid,[('model','=',model)])
- if model_id:
- res[data.get('id')] = model_id[0]
- else:
- res[data.get('id')] = False
- return res
-
- def _model_search(self, cr, uid, obj, name, args):
- if not len(args):
- return []
- model_id= args[0][2]
- if not model_id:
- return []
- model = self.pool.get('ir.model').read(cr,uid,[model_id])[0]['model']
- report_id = self.search(cr,uid,[('model','=',model)])
- if not report_id:
- return [('id','=','0')]
- return [('id','in',report_id)]
-
- _columns={
- 'model_id' : fields.function(_model_get,fnct_search=_model_search,method=True,string='Model Id'),
- }
+ _name="ir.actions.report.xml"
+ _inherit ="ir.actions.report.xml"
+
+ def _model_get(self, cr, uid, ids, name, arg, context):
+ res = {}
+ model_pool = self.pool.get('ir.model')
+ for data in self.read(cr,uid,ids,['model']):
+ model = data.get('model',False)
+ if model:
+ model_id =model_pool.search(cr,uid,[('model','=',model)])
+ if model_id:
+ res[data.get('id')] = model_id[0]
+ else:
+ res[data.get('id')] = False
+ return res
+
+ def _model_search(self, cr, uid, obj, name, args):
+ if not len(args):
+ return []
+ model_id= args[0][2]
+ if not model_id:
+ return []
+ model = self.pool.get('ir.model').read(cr,uid,[model_id])[0]['model']
+ report_id = self.search(cr,uid,[('model','=',model)])
+ if not report_id:
+ return [('id','=','0')]
+ return [('id','in',report_id)]
+
+ _columns={
+ 'model_id' : fields.function(_model_get,fnct_search=_model_search,method=True,string='Model Id'),
+ }
ir_action_report_xml()
@@ -436,174 +461,174 @@ import string
def random_name():
- random.seed()
- d = [random.choice(string.letters) for x in xrange(10) ]
- name = "".join(d)
- return name
+ random.seed()
+ d = [random.choice(string.letters) for x in xrange(10) ]
+ name = "".join(d)
+ return name
def create_directory(path):
- dir_name = random_name()
- path = os.path.join(path,dir_name)
- os.mkdir(path)
- return dir_name
+ dir_name = random_name()
+ path = os.path.join(path,dir_name)
+ os.mkdir(path)
+ return dir_name
class document_file(osv.osv):
- _inherit = 'ir.attachment'
- def _data_get(self, cr, uid, ids, name, arg, context):
- result = {}
- cr.execute('select id,store_method,datas,store_fname,link from ir_attachment where id in ('+','.join(map(str,ids))+')')
- for id,m,d,r,l in cr.fetchall():
- if m=='db':
- result[id] = d
- elif m=='fs':
- try:
- path = os.path.join(os.getcwd(),'filestore')
- value = file(os.path.join(path,r), 'rb').read()
- result[id] = base64.encodestring(value)
- except:
- result[id]=''
- else:
- result[id] = ''
- return result
-
- #
- # This code can be improved
- #
- def _data_set(self, cr, obj, id, name, value, uid=None, context={}):
- if not value:
- return True
- if (not context) or context.get('store_method','fs')=='fs':
- path = os.path.join(os.getcwd(), "filestore")
- if not os.path.isdir(path):
- os.mkdir(path)
- flag = None
- # This can be improved
- for dirs in os.listdir(path):
- if os.path.isdir(os.path.join(path,dirs)) and len(os.listdir(os.path.join(path,dirs)))<4000:
- flag = dirs
- break
- flag = flag or create_directory(path)
- filename = random_name()
- fname = os.path.join(path, flag, filename)
- fp = file(fname,'wb')
- v = base64.decodestring(value)
- fp.write(v)
- filesize = os.stat(fname).st_size
- cr.execute('update ir_attachment set store_fname=%s,store_method=%s,file_size=%d where id=%d', (os.path.join(flag,filename),'fs',len(v),id))
- else:
- cr.execute('update ir_attachment set datas=%s,store_method=%s where id=%d', (psycopg.Binary(value),'db',id))
- return True
-
- _columns = {
- 'user_id': fields.many2one('res.users', 'Owner', select=1),
- 'group_ids': fields.many2many('res.groups', 'document_directory_group_rel', 'item_id', 'group_id', 'Groups'),
- 'parent_id': fields.many2one('document.directory', 'Directory', select=1),
- 'file_size': fields.integer('File Size', required=True),
- 'file_type': fields.char('Content Type', size=32),
- 'index_content': fields.text('Indexed Content'),
- 'write_date': fields.datetime('Date Modified', readonly=True),
- 'write_uid': fields.many2one('res.users', 'Last Modification User', readonly=True),
- 'create_date': fields.datetime('Date Created', readonly=True),
- 'create_uid': fields.many2one('res.users', 'Creator', readonly=True),
- 'store_method': fields.selection([('db','Database'),('fs','Filesystem'),('link','Link')], "Storing Method"),
- 'datas': fields.function(_data_get,method=True,store=True,fnct_inv=_data_set,string='File Content',type="binary"),
- 'store_fname': fields.char('Stored Filename', size=200),
- 'res_model': fields.char('Attached Model', size=64), #res_model
- 'res_id': fields.integer('Attached ID'), #res_id
- 'partner_id':fields.many2one('res.partner', 'Partner', select=1),
- 'title': fields.char('Resource Title',size=64),
- }
-
- _defaults = {
- 'user_id': lambda self,cr,uid,ctx:uid,
- 'file_size': lambda self,cr,uid,ctx:0,
- 'store_method': lambda *args: 'db'
- }
- _sql_constraints = [
- ('filename_uniq', 'unique (name,parent_id,res_id,res_model)', 'The file name must be unique !')
- ]
-
- def _check_duplication(self, cr, uid,vals):
- if 'name' in vals:
- res=self.search(cr,uid,[('name','=',vals['name']),('parent_id','=','parent_id' in vals and vals['parent_id'] or False),('res_id','=','res_id' in vals and vals['res_id'] or False),('res_model','=','res_model' in vals and vals['res_model']) or False])
- if len(res):
- return False
- return True
-
- def write(self, cr, uid, ids, vals, context=None):
- if not self._check_duplication(cr,uid,vals):
- raise except_orm('ValidateError', 'File name must be unique!')
- result = super(document_file,self).write(cr,uid,ids,vals,context=context)
- try:
- for f in self.browse(cr, uid, ids, context=context):
- if 'datas' not in vals:
- vals['datas']=f.datas
- res = content_index(base64.decodestring(vals['datas']), f.datas_fname, f.file_type or None)
- super(document_file,self).write(cr, uid, ids, {
- 'index_content': res
- })
- except:
- pass
- return result
-
- def create(self, cr, uid, vals, context={}):
- vals['title']=vals['name']
- if vals.get('res_id', False) and vals.get('res_model',False):
- obj_model=self.pool.get(vals['res_model'])
- result = obj_model.read(cr, uid, [vals['res_id']], context=context)
- if len(result):
- obj=result[0]
- vals['title'] = (obj['name'] or '')[:60]
- if obj_model._name=='res.partner':
- vals['partner_id']=obj['id']
- elif 'address_id' in obj:
- address=self.pool.get('res.partner.address').read(cr,uid,[obj['address_id']],context=context)
- if len(address):
- vals['partner_id']=address[0]['partner_id'] or False
- elif 'partner_id' in obj:
- if isinstance(obj['partner_id'],tuple) or isinstance(obj['partner_id'],list):
- vals['partner_id']=obj['partner_id'][0]
- else:
- vals['partner_id']=obj['partner_id']
-
- datas=None
- if 'datas' not in vals:
- import urllib
- datas=base64.encodestring(urllib.urlopen(vals['link']).read())
- else:
- datas=vals['datas']
- vals['file_size']= len(datas)
- if not self._check_duplication(cr,uid,vals):
- raise except_orm('ValidateError', 'File name must be unique!')
- result = super(document_file,self).create(cr, uid, vals, context)
- cr.commit()
- try:
- res = content_index(base64.decodestring(datas), vals['datas_fname'], vals.get('content_type', None))
- super(document_file,self).write(cr, uid, [result], {
- 'index_content': res,
- })
- cr.commit()
- except:
- pass
- return result
-
- def unlink(self,cr, uid, ids, context={}):
- for f in self.browse(cr, uid, ids, context):
- if f.store_method=='fs':
- try:
- path = os.path.join(os.getcwd(),'filestore',f.store_fname)
- os.unlink(path)
- except:
- pass
- return super(document_file, self).unlink(cr, uid, ids, context)
+ _inherit = 'ir.attachment'
+ def _data_get(self, cr, uid, ids, name, arg, context):
+ result = {}
+ cr.execute('select id,store_method,datas,store_fname,link from ir_attachment where id in ('+','.join(map(str,ids))+')')
+ for id,m,d,r,l in cr.fetchall():
+ if m=='db':
+ result[id] = d
+ elif m=='fs':
+ try:
+ path = os.path.join(os.getcwd(),'filestore')
+ value = file(os.path.join(path,r), 'rb').read()
+ result[id] = base64.encodestring(value)
+ except:
+ result[id]=''
+ else:
+ result[id] = ''
+ return result
+
+ #
+ # This code can be improved
+ #
+ def _data_set(self, cr, obj, id, name, value, uid=None, context={}):
+ if not value:
+ return True
+ if (not context) or context.get('store_method','fs')=='fs':
+ path = os.path.join(os.getcwd(), "filestore")
+ if not os.path.isdir(path):
+ os.mkdir(path)
+ flag = None
+ # This can be improved
+ for dirs in os.listdir(path):
+ if os.path.isdir(os.path.join(path,dirs)) and len(os.listdir(os.path.join(path,dirs)))<4000:
+ flag = dirs
+ break
+ flag = flag or create_directory(path)
+ filename = random_name()
+ fname = os.path.join(path, flag, filename)
+ fp = file(fname,'wb')
+ v = base64.decodestring(value)
+ fp.write(v)
+ filesize = os.stat(fname).st_size
+ cr.execute('update ir_attachment set store_fname=%s,store_method=%s,file_size=%d where id=%d', (os.path.join(flag,filename),'fs',len(v),id))
+ else:
+ cr.execute('update ir_attachment set datas=%s,store_method=%s where id=%d', (psycopg.Binary(value),'db',id))
+ return True
+
+ _columns = {
+ 'user_id': fields.many2one('res.users', 'Owner', select=1),
+ 'group_ids': fields.many2many('res.groups', 'document_directory_group_rel', 'item_id', 'group_id', 'Groups'),
+ 'parent_id': fields.many2one('document.directory', 'Directory', select=1),
+ 'file_size': fields.integer('File Size', required=True),
+ 'file_type': fields.char('Content Type', size=32),
+ 'index_content': fields.text('Indexed Content'),
+ 'write_date': fields.datetime('Date Modified', readonly=True),
+ 'write_uid': fields.many2one('res.users', 'Last Modification User', readonly=True),
+ 'create_date': fields.datetime('Date Created', readonly=True),
+ 'create_uid': fields.many2one('res.users', 'Creator', readonly=True),
+ 'store_method': fields.selection([('db','Database'),('fs','Filesystem'),('link','Link')], "Storing Method"),
+ 'datas': fields.function(_data_get,method=True,store=True,fnct_inv=_data_set,string='File Content',type="binary"),
+ 'store_fname': fields.char('Stored Filename', size=200),
+ 'res_model': fields.char('Attached Model', size=64), #res_model
+ 'res_id': fields.integer('Attached ID'), #res_id
+ 'partner_id':fields.many2one('res.partner', 'Partner', select=1),
+ 'title': fields.char('Resource Title',size=64),
+ }
+
+ _defaults = {
+ 'user_id': lambda self,cr,uid,ctx:uid,
+ 'file_size': lambda self,cr,uid,ctx:0,
+ 'store_method': lambda *args: 'db'
+ }
+ _sql_constraints = [
+ ('filename_uniq', 'unique (name,parent_id,res_id,res_model)', 'The file name must be unique !')
+ ]
+
+ def _check_duplication(self, cr, uid,vals):
+ if 'name' in vals:
+ res=self.search(cr,uid,[('name','=',vals['name']),('parent_id','=','parent_id' in vals and vals['parent_id'] or False),('res_id','=','res_id' in vals and vals['res_id'] or False),('res_model','=','res_model' in vals and vals['res_model']) or False])
+ if len(res):
+ return False
+ return True
+
+ def write(self, cr, uid, ids, vals, context=None):
+ if not self._check_duplication(cr,uid,vals):
+ raise except_orm('ValidateError', 'File name must be unique!')
+ result = super(document_file,self).write(cr,uid,ids,vals,context=context)
+ try:
+ for f in self.browse(cr, uid, ids, context=context):
+ if 'datas' not in vals:
+ vals['datas']=f.datas
+ res = content_index(base64.decodestring(vals['datas']), f.datas_fname, f.file_type or None)
+ super(document_file,self).write(cr, uid, ids, {
+ 'index_content': res
+ })
+ except:
+ pass
+ return result
+
+ def create(self, cr, uid, vals, context={}):
+ vals['title']=vals['name']
+ if vals.get('res_id', False) and vals.get('res_model',False):
+ obj_model=self.pool.get(vals['res_model'])
+ result = obj_model.read(cr, uid, [vals['res_id']], context=context)
+ if len(result):
+ obj=result[0]
+ vals['title'] = (obj['name'] or '')[:60]
+ if obj_model._name=='res.partner':
+ vals['partner_id']=obj['id']
+ elif 'address_id' in obj:
+ address=self.pool.get('res.partner.address').read(cr,uid,[obj['address_id']],context=context)
+ if len(address):
+ vals['partner_id']=address[0]['partner_id'] or False
+ elif 'partner_id' in obj:
+ if isinstance(obj['partner_id'],tuple) or isinstance(obj['partner_id'],list):
+ vals['partner_id']=obj['partner_id'][0]
+ else:
+ vals['partner_id']=obj['partner_id']
+
+ datas=None
+ if 'datas' not in vals:
+ import urllib
+ datas=base64.encodestring(urllib.urlopen(vals['link']).read())
+ else:
+ datas=vals['datas']
+ vals['file_size']= len(datas)
+ if not self._check_duplication(cr,uid,vals):
+ raise except_orm('ValidateError', 'File name must be unique!')
+ result = super(document_file,self).create(cr, uid, vals, context)
+ cr.commit()
+ try:
+ res = content_index(base64.decodestring(datas), vals['datas_fname'], vals.get('content_type', None))
+ super(document_file,self).write(cr, uid, [result], {
+ 'index_content': res,
+ })
+ cr.commit()
+ except:
+ pass
+ return result
+
+ def unlink(self,cr, uid, ids, context={}):
+ for f in self.browse(cr, uid, ids, context):
+ if f.store_method=='fs':
+ try:
+ path = os.path.join(os.getcwd(),'filestore',f.store_fname)
+ os.unlink(path)
+ except:
+ pass
+ return super(document_file, self).unlink(cr, uid, ids, context)
document_file()
class document_configuration_wizard(osv.osv_memory):
_name='document.configuration.wizard'
_rec_name = 'Auto Directory configuration'
_columns = {
- }
+ }
def action_cancel(self,cr,uid,ids,conect=None):
return {
'view_type': 'form',
@@ -614,79 +639,75 @@ class document_configuration_wizard(osv.osv_memory):
}
def action_config(self, cr, uid, ids, context=None):
- obj=self.pool.get('document.directory')
- search_ids=obj.search(cr,uid,[])
- browse_lst=obj.browse(cr,uid,search_ids)
- model_obj=self.pool.get('ir.model')
-
- for doc_obj in browse_lst:
- if doc_obj.name in ('Partner','Contacts','Personnal Folders','Partner Category','Sales Order','All Sales Order','Sales by Salesman','Projects'):
- res={}
- id=[]
- if doc_obj.name=='Partner':
- id=model_obj.search(cr,uid,[('model','=','res.partner')])
-
- if doc_obj.name=='Contacts':
- id=model_obj.search(cr,uid,[('model','=','res.partner.address')])
-
- if doc_obj.name=='Partner Category':
- id=model_obj.search(cr,uid,[('model','=','res.partner.category')])
-
- if doc_obj.name=='All Sales Order':
- val={}
- id=model_obj.search(cr,uid,[('model','=','sale.order')])
- if not len(doc_obj.content_ids):
- val['name']='Sale Report'
- val['suffix']='_report'
- val['report_id']=self.pool.get('ir.actions.report.xml').search(cr,uid,[('report_name','=','sale.order')])[0]
- val['extension']='.pdf'
- val['directory_id']=doc_obj.id
- self.pool.get('document.directory.content').create(cr,uid,val)
-
- if doc_obj.name=='Sales by Salesman':
- id=model_obj.search(cr,uid,[('model','=','res.users')])
-
- if doc_obj.name=='Personnal Folders':
- id=model_obj.search(cr,uid,[('model','=','res.users')])
-
- if doc_obj.name=='Projects':
- id=model_obj.search(cr,uid,[('model','=','account.analytic.account')])
- res['ressource_tree']=True
-
- if id:
- res['ressource_type_id']=id[0]
- res['type']='ressource'
- obj.write(cr,uid,doc_obj.id,res)
- self.create_folder(cr, uid, ids, context=None)
- return {
+ obj=self.pool.get('document.directory')
+ objid=self.pool.get('ir.model.data')
+
+ if self.pool.get('sale.order'):
+ id = objid._get_id(cr, uid, 'document', 'dir_sale_order_all')
+ id = objid.browse(cr, uid, id, context=context).res_id
+ mid = self.pool.get('ir.model').search(cr, uid, [('model','=','sale.order')])
+ obj.write(cr, uid, [id], {
+ 'type':'ressource',
+ 'ressource_type_id': mid[0],
+ 'domain': '[]',
+ })
+ aid = objid._get_id(cr, uid, 'sale', 'report_sale_order')
+ aid = objid.browse(cr, uid, aid, context=context).res_id
+
+ self.pool.get('document.directory.content').create(cr, uid, {
+ 'name': "Print Order",
+ 'suffix': "_print",
+ 'report_id': aid,
+ 'extension': '.pdf',
+ 'include_name': 1,
+ 'directory_id': id,
+ })
+ id = objid._get_id(cr, uid, 'document', 'dir_sale_order_quote')
+ id = objid.browse(cr, uid, id, context=context).res_id
+ obj.write(cr, uid, [id], {
+ 'type':'ressource',
+ 'ressource_type_id': mid[0],
+ 'domain': "[('state','=','draft')]",
+ })
+
+ if self.pool.get('product.product'):
+ id = objid._get_id(cr, uid, 'document', 'dir_product')
+ id = objid.browse(cr, uid, id, context=context).res_id
+ mid = self.pool.get('ir.model').search(cr, uid, [('model','=','product.product')])
+ obj.write(cr, uid, [id], {
+ 'type':'ressource',
+ 'ressource_type_id': mid[0],
+ })
+
+ if self.pool.get('stock.location'):
+ aid = objid._get_id(cr, uid, 'stock', 'report_product_history')
+ aid = objid.browse(cr, uid, aid, context=context).res_id
+
+ self.pool.get('document.directory.content').create(cr, uid, {
+ 'name': "Product Stock",
+ 'suffix': "_stock_forecast",
+ 'report_id': aid,
+ 'extension': '.pdf',
+ 'include_name': 1,
+ 'directory_id': id,
+ })
+
+ if self.pool.get('account.analytic.account'):
+ id = objid._get_id(cr, uid, 'document', 'dir_project')
+ id = objid.browse(cr, uid, id, context=context).res_id
+ mid = self.pool.get('ir.model').search(cr, uid, [('model','=','account.analytic.account')])
+ obj.write(cr, uid, [id], {
+ 'type':'ressource',
+ 'ressource_type_id': mid[0],
+ 'domain': '[]',
+ 'ressource_tree': 1
+ })
+
+ return {
'view_type': 'form',
"view_mode": 'form',
'res_model': 'ir.actions.configuration.wizard',
'type': 'ir.actions.act_window',
'target':'new',
- }
-
- def create_folder(self, cr, uid, ids, context=None):
- doc_obj=self.pool.get('document.directory')
- model_obj=self.pool.get('ir.model')
- for name in ('Sales','Quotation','Meetings','Analysis Reports'):
- res={}
- if name=='Sales':
- child_model=model_obj.search(cr,uid,[('model','=','sale.order')])
- link_model=model_obj.search(cr,uid,[('model','=','res.users')])
- if child_model:
- res['type']='ressource'
- res['ressource_type_id']=child_model[0]
- res['ressource_parent_type_id']=link_model[0]
- res['domain']="[('user_id','=',active_id)]"
- else:
- link_model=model_obj.search(cr,uid,[('model','=','account.analytic.account')])
- if link_model:
- res['ressource_parent_type_id']=link_model[0]
- res['ressource_id']=0
- if res:
- res['name']=name
- doc_obj.create(cr,uid,res)
- return True
-
+ }
document_configuration_wizard()
diff --git a/addons/document/document_data.xml b/addons/document/document_data.xml
index 9953d07dd92..33c6f80763a 100644
--- a/addons/document/document_data.xml
+++ b/addons/document/document_data.xml
@@ -1,6 +1,11 @@
<?xml version="1.0"?>
<openerp>
-<data noupdate="1">
+<data>
+
+ <record model="document.directory.content.type" id="pdf">
+ <field name="code">.pdf</field>
+ <field name="name">PDF Report</field>
+ </record>
</data>
</openerp>
diff --git a/addons/document/document_demo.xml b/addons/document/document_demo.xml
index 94c52923556..11d1f0a991a 100644
--- a/addons/document/document_demo.xml
+++ b/addons/document/document_demo.xml
@@ -2,92 +2,71 @@
<openerp>
<data noupdate="1">
- <record model="document.directory" id="dir_root">
- <field name="name">Main Repository</field>
- <field name="user_id" ref="base.user_admin"/>
- <field name="ressource_id" eval="0"/>
+ <record model="document.directory" id="dir_root">
+ <field name="name">Documents</field>
+ <field name="user_id" ref="base.user_admin"/>
+ </record>
- </record>
+ <record model="document.directory" id="dir_my_folder">
+ <field name="name">My Folder</field>
+ <field name="parent_id" ref="dir_root"/>
+ <field name="user_id" ref="base.user_admin"/>
+ </record>
- <record model="document.directory" id="dir_my_folder">
- <field name="name">My Folder</field>
- <field name="parent_id" ref="dir_root"/>
- <field name="user_id" ref="base.user_admin"/>
- <field name="ressource_id" eval="0"/>
- </record>
+ <record model="document.directory" id="dir_partner_category">
+ <field name="name">Partners by Category</field>
+ <field name="parent_id" ref="dir_root"/>
+ <field name="type">ressource</field>
+ <field name="ressource_tree">1</field>
+ <field name="ressource_type_id" search="[('model','=','res.partner.category')]" />
+ <field name="user_id" ref="base.user_admin"/>
+ </record>
- <record model="document.directory" id="dir_partner_category">
- <field name="name">Partner Category</field>
- <field name="parent_id" ref="dir_root"/>
- <field name="type">ressource</field>
- <field name="ressource_tree">1</field>
- <field name="ressource_type_id" search="[('model','=','res.partner.category')]" />
- <field name="user_id" ref="base.user_admin"/>
- <field name="ressource_id" eval="0"/>
- </record>
+ <record model="document.directory" id="dir_partner">
+ <field name="name">Partners</field>
+ <field name="type">ressource</field>
+ <field name="domain">[('category_id','in',[active_id])]</field>
+ <field name="ressource_type_id" search="[('model','=','res.partner')]" />
+ <field name="ressource_parent_type_id" search="[('model','=','res.partner.category')]" />
+ <field name="user_id" ref="base.user_admin"/>
+ </record>
+ <record model="document.directory" id="dir_personnal_folder">
+ <field name="name">Personnal Folders</field>
+ <field name="parent_id" ref="dir_root"/>
+ <field name="type">ressource</field>
+ <field name="ressource_type_id" ref="base.model_res_users" />
+ </record>
+ <record model="document.directory" id="dir_product">
+ <field name="name">Products</field>
+ <field name="user_id" ref="base.user_admin"/>
+ <field name="parent_id" ref="dir_root"/>
+ </record>
- <record model="document.directory" id="dir_partner">
- <field name="name">Partner</field>
- <field name="type">ressource</field>
- <field name="domain">[('category_id','in',[active_id])]</field>
- <field name="ressource_type_id" search="[('model','=','res.partner')]" />
- <field name="ressource_parent_type_id" search="[('model','=','res.partner.category')]" />
- <field name="user_id" ref="base.user_admin"/>
- <field name="ressource_id" eval="0"/>
- </record>
+ <record model="document.directory" id="dir_sale_order">
+ <field name="name">Sales Order</field>
+ <field name="user_id" ref="base.user_admin"/>
+ <field name="parent_id" ref="dir_root"/>
+ </record>
- <record model="document.directory" id="dir_partner_contacts">
- <field name="name">Contacts</field>
- <field name="type">ressource</field>
- <field name="domain">[('partner_id','=',active_id)]</field>
- <field name="ressource_type_id" search="[('model','=','res.partner.address')]" />
- <field name="ressource_parent_type_id" search="[('model','=','res.partner')]" />
- <field name="user_id" ref="base.user_admin"/>
- <field name="ressource_id" eval="0"/>
- </record>
+ <record model="document.directory" id="dir_sale_order_all">
+ <field name="name">All Sales Order</field>
+ <field name="user_id" ref="base.user_admin"/>
+ <field name="parent_id" ref="dir_sale_order"/>
+ </record>
- <record model="document.directory" id="dir_my_partner">
- <field name="name">My Folder</field>
- <field name="user_id" ref="base.user_admin"/>
- <field name="ressource_parent_type_id" search="[('model','=','res.partner')]" />
- <field name="ressource_id" eval="0"/>
- </record>
+ <record model="document.directory" id="dir_sale_order_quote">
+ <field name="name">Quotations</field>
+ <field name="user_id" ref="base.user_admin"/>
+ <field name="parent_id" ref="dir_sale_order"/>
+ </record>
- <record model="document.directory" id="dir_personnal_folder">
- <field name="name">Personnal Folders</field>
- <field name="parent_id" ref="dir_root"/>
- <field name="user_id" ref="base.user_admin"/>
- <field name="ressource_id" eval="0"/>
- </record>
-
- <record model="document.directory" id="dir_sale_order">
- <field name="name">Sales Order</field>
- <field name="user_id" ref="base.user_admin"/>
- <field name="parent_id" ref="dir_root"/>
- <field name="ressource_id" eval="0"/>
- </record>
-
- <record model="document.directory" id="dir_sale_order_all">
- <field name="name">All Sales Order</field>
- <field name="user_id" ref="base.user_admin"/>
- <field name="parent_id" ref="dir_sale_order"/>
- <field name="ressource_id" eval="0"/>
- </record>
- <record model="document.directory" id="dir_sale_order_salesman">
- <field name="name">Sales by Salesman</field>
- <field name="user_id" ref="base.user_admin"/>
- <field name="parent_id" ref="dir_sale_order"/>
- <field name="ressource_id" eval="0"/>
- </record>
-
- <record model="document.directory" id="dir_project">
- <field name="name">Projects</field>
- <field name="user_id" ref="base.user_admin"/>
- <field name="parent_id" ref="dir_root"/>
- <field name="ressource_id" eval="0"/>
- </record>
+ <record model="document.directory" id="dir_project">
+ <field name="name">Projects</field>
+ <field name="user_id" ref="base.user_admin"/>
+ <field name="parent_id" ref="dir_root"/>
+ </record>
</data>
</openerp>
diff --git a/addons/document/document_view.xml b/addons/document/document_view.xml
index 6b15382af63..434e00aa7d8 100644
--- a/addons/document/document_view.xml
+++ b/addons/document/document_view.xml
@@ -1,6 +1,7 @@
<openerp>
<data>
<menuitem name="Document Management" icon="terp-stock" id="menu_document"/>
+ <menuitem name="Configuration" id="menu_document_configuration" parent="menu_document"/>
<record model="ir.ui.view" id="view_document_directory_form">
<field name="name">document.directory</field>
@@ -8,11 +9,11 @@
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Directories">
- <notebook>
+ <field name="name" select="1" colspan="4"/>
+ <field name="user_id"/>
+ <field name="parent_id"/>
+ <notebook colspan="4">
<page string="Definition">
- <field name="name" select="1" colspan="4"/>
- <field name="user_id"/>
- <field name="parent_id"/>
<separator string="Directory Type" colspan="4"/>
<field name="type"/>
<field name="ressource_type_id" on_change="onchange_content_id(ressource_type_id)"/>
@@ -29,14 +30,15 @@
<field name="sequence"/>
<field name="suffix"/>
<field name="extension"/>
+ <field name="include_name"/>
+ <separator string="PDF Report" colspan="4"/>
<field name="report_id" domain="[('model_id','=',parent.ressource_type_id)]"/>
</form>
<tree string="Contents">
- <field name="sequence"/>
+ <field name="sequence" string="Seq."/>
<field name="name"/>
<field name="suffix"/>
<field name="extension"/>
- <field name="report_id"/>
</tree>
</field>
</page><page string="Security">
@@ -67,26 +69,37 @@
<field name="res_model">document.directory</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
- </record>
- <menuitem name="Configuration" id="menu_document_configuration" parent="menu_document"/>
+ </record>
<menuitem
name="Directories"
action="action_document_directory_form"
- id="menu_document_directories"
- parent="menu_document_configuration"/>
+ id="menu_document_directories"
+ parent="menu_document_configuration"/>
+
<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="res_model">document.directory</field>
<field name="view_type">tree</field>
<field name="domain">[('ressource_parent_type_id','=',False),('parent_id','=',False)]</field>
</record>
<menuitem
- name="Directorie's Structure"
action="action_document_directory_tree"
- id="menu_document_directories_tree"
- parent="menu_document"/>
+ id="menu_document_directories_tree"
+ parent="menu_document_configuration"/>
+ <record model="ir.actions.url" id="action_document_browse">
+ <field name="name">Browse Files</field>
+ <field name="url">ftp://localhost:8021/</field>
+ </record>
+ <menuitem
+ name="Browse Files Using FTP"
+ action="action_document_browse"
+ id="menu_document_browse"
+ type="url"
+ icon="STOCK_EXECUTE"
+ parent="menu_document"/>
<record model="ir.ui.view" id="view_document_file_form">
<field name="name">ir.attachment</field>
@@ -146,8 +159,8 @@
<menuitem
name="Search a File"
action="action_document_file_form"
- id="menu_document_files"
- parent="menu_document"/>
+ id="menu_document_files"
+ parent="menu_document"/>
<record model="ir.actions.act_window" id="action_document_file_directory_form">
<field name="type">ir.actions.act_window</field>
@@ -203,33 +216,20 @@
</record>
- <record id="view_auto_config_form" model="ir.ui.view">
+ <record id="view_auto_config_form" model="ir.ui.view">
<field name="name">Auto Configure Directory</field>
<field name="model">document.configuration.wizard</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Auto Configure">
- <separator string="Connect to Document Management System." colspan="4"/>
- <label align="0.0" string="You can use ftp://admin:admin@localhost:8021 " colspan="4"/>
- <separator string="Configure Ressources Directory :" colspan="4"/>
- <newline/>
- <label string="'All Sales Order' -> sale.order" align="0.0" colspan="4"/>
- <label string="'Sales by Salesman' -> res.users" align="0.0" colspan="4"/>
- <label string="'Personnal Folders' -> res.users" align="0.0" colspan="4"/>
- <label string="'Projects' -> account.analytic.account with ressource tree" align="0.0" colspan="4"/>
- <separator string="New Directories." colspan="4"/>
- <label string="'Sales' -> sale.order which is link directory of 'res.users' model" align="0.0" colspan="4"/>
- <label align="0.0" string="'Quotation','Meetings','Analysis Reports' -> static directories which are link directories of 'account.analytic.account' model" colspan="4"/>
- <newline/>
- <newline/>
- <separator string="" colspan="4"/>
- <label string="" colspan="2"/>
+ <separator string="Document Management System." colspan="4"/>
+ <label string="This wizard will automatically configure the document management system according to modules installed on your system." align="0.0" colspan="4"/>
+ <separator string="" colspan="4"/>
+ <label string="" colspan="2"/>
<group col="4" colspan="2">
<button special="cancel" string="Cancel" name="action_cancel" type="object" icon='gtk-cancel'/>
<button name="action_config" string="Configure" icon='gtk-ok' type="object"/>
</group>
- <newline/>
-
</form>
</field>
</record>
@@ -243,10 +243,9 @@
<field name="target">new</field>
</record>
- <record model="ir.actions.todo"
- id="config_auto_directory">
+ <record model="ir.actions.todo" id="config_auto_directory">
<field name="name">Auto Configure Directory</field>
- <field name="note">This wizard will be configure directory for ressource model.</field>
+ <field name="note">This wizard will be configure directory for ressource model.</field>
<field name="action_id" ref="action_config_auto_directory"/>
<field name="state">open</field>
</record>
diff --git a/addons/document/ftpserver/abstracted_fs.py b/addons/document/ftpserver/abstracted_fs.py
index 2ff2bdbb41c..9bdd38b72bd 100644
--- a/addons/document/ftpserver/abstracted_fs.py
+++ b/addons/document/ftpserver/abstracted_fs.py
@@ -9,743 +9,761 @@ import fnmatch
import pooler
import netsvc
-import posix
+import os
from service import security
+class file_wrapper(StringIO.StringIO):
+ def __init__(self, sstr='', ressource_id=False, dbname=None, uid=1, name=''):
+ StringIO.StringIO.__init__(self, sstr)
+ self.ressource_id = ressource_id
+ self.name = name
+ self.dbname = dbname
+ self.uid = uid
+ def close(self, *args, **kwargs):
+ db,pool = pooler.get_db_and_pool(self.dbname)
+ cr = db.cursor()
+ uid =self.uid
+ val = self.getvalue()
+ val2 = {
+ 'datas': base64.encodestring(val),
+ 'file_size': len(val),
+ }
+ pool.get('ir.attachment').write(cr, uid, [self.ressource_id], val2)
+ cr.commit()
+ StringIO.StringIO.close(self, *args, **kwargs)
+
+class content_wrapper(StringIO.StringIO):
+ def __init__(self, dbname, uid, pool, node, name=''):
+ StringIO.StringIO.__init__(self, '')
+ self.dbname = dbname
+ self.uid = uid
+ self.node = node
+ self.pool = pool
+ self.name = name
+ def close(self, *args, **kwargs):
+ db,pool = pooler.get_db_and_pool(self.dbname)
+ cr = db.cursor()
+ getattr(self.pool.get('document.directory.content'), 'process_write_'+self.node.content.extension[1:])(cr, self.uid, self.node, self.getvalue())
+ StringIO.StringIO.close(self, *args, **kwargs)
+ cr.commit()
+ cr.close()
+
+
class abstracted_fs:
- """A class used to interact with the file system, providing a high
- level, cross-platform interface compatible with both Windows and
- UNIX style filesystems.
-
- It provides some utility methods and some wraps around operations
- involved in file creation and file system operations like moving
- files or removing directories.
-
- Instance attributes:
- - (str) root: the user home directory.
- - (str) cwd: the current working directory.
- - (str) rnfr: source file to be renamed.
- """
-
- # Ok
- def db_list(self):
- s = netsvc.LocalService('db')
- result = s.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 like 'document%' and state='installed' ")
- res=cr.fetchone()
- if res and len(res):
- self.db_name_list.append(db_name)
- cr.close()
- return self.db_name_list
-
- # Ok
- def __init__(self):
- self.root = None
- self.cwd = '/'
- self.rnfr = None
-
- # --- Pathname / conversion utilities
-
- # Ok
- def ftpnorm(self, ftppath):
- """Normalize a "virtual" ftp pathname (tipically the raw string
- coming from client) depending on the current working directory.
-
- Example (having "/foo" as current working directory):
- 'x' -> '/foo/x'
-
- Note: directory separators are system independent ("/").
- Pathname returned is always absolutized.
- """
- if os.path.isabs(ftppath):
- p = os.path.normpath(ftppath)
- else:
- p = os.path.normpath(os.path.join(self.cwd, ftppath))
- # normalize string in a standard web-path notation having '/'
- # as separator.
- p = p.replace("\\", "/")
- # os.path.normpath supports UNC paths (e.g. "//a/b/c") but we
- # don't need them. In case we get an UNC path we collapse
- # redundant separators appearing at the beginning of the string
- while p[:2] == '//':
- p = p[1:]
- # Anti path traversal: don't trust user input, in the event
- # that self.cwd is not absolute, return "/" as a safety measure.
- # This is for extra protection, maybe not really necessary.
- if not os.path.isabs(p):
- p = "/"
- return p
-
- # Ok
- def ftp2fs(self, path_orig, data):
- path = self.ftpnorm(path_orig)
- if path and path=='/':
- return None
- path2 = filter(None,path.split('/'))[1:]
- (cr, uid, pool) = data
- res = pool.get('document.directory').get_object(cr, uid, path2[:])
- if not res:
- raise OSError(2, 'Not such file or directory.')
- return res
-
- # Ok
- def fs2ftp(self, node):
- res = node and ('/' + node.cr.dbname + '/' + node.path) or '/'
- return res
-
- # Ok
- def validpath(self, path):
- """Check whether the path belongs to user's home directory.
- Expected argument is a "real" filesystem pathname.
-
- If path is a symbolic link it is resolved to check its real
- destination.
-
- Pathnames escaping from user's root directory are considered
- not valid.
- """
- return path and True or False
-
- # --- Wrapper methods around open() and tempfile.mkstemp
-
- # Ok
- def create(self, node, objname, mode):
- try:
- class file_wrapper(StringIO.StringIO):
- def __init__(self, sstr='', ressource_id=False, dbname=None, uid=1, name=''):
- StringIO.StringIO.__init__(self, sstr)
- self.ressource_id = ressource_id
- self.name = name
- self.dbname = dbname
- self.uid = uid
- def close(self, *args, **kwargs):
- db,pool = pooler.get_db_and_pool(self.dbname)
- cr = db.cursor()
- uid =self.uid
- val = self.getvalue()
- val2 = {
- 'datas': base64.encodestring(val),
- 'file_size': len(val),
- }
- pool.get('ir.attachment').write(cr, uid, [self.ressource_id], val2)
- cr.commit()
- StringIO.StringIO.close(self, *args, **kwargs)
-
- cr = node.cr
- uid = node.uid
- pool = pooler.get_pool(cr.dbname)
-
- fobj = pool.get('ir.attachment')
- ext = objname.find('.') >0 and objname.split('.')[1] or False
-
- # TODO: test if already exist and modify in this case if node.type=file
- ### checked already exits
- object2=node and node.object2 or False
- object=node and node.object or False
- cid=False
-
- where=[('name','=',objname)]
- if object and (object.type in ('directory','ressource')) or object2:
- where.append(('parent_id','=',object.id))
- else:
- where.append(('parent_id','=',False))
-
- if object2:
- where +=[('res_id','=',object2.id),('res_model','=',object2._name)]
- cids = fobj.search(cr, uid,where)
- if len(cids):
- cid=cids[0]
-
- if not cid:
- val = {
- 'name': objname,
- 'datas_fname': objname,
- 'datas': '',
- 'file_size': 0L,
- 'file_type': ext,
- }
- if object and (object.type in ('directory','ressource')) or not object2:
- val['parent_id']= object and object.id or False
- partner = False
- if object2:
- if 'partner_id' in object2 and object2.partner_id.id:
- partner = object2.partner_id.id
- if object2._name == 'res.partner':
- partner = object2.id
- val.update( {
- 'res_model': object2._name,
- 'partner_id': partner,
- 'res_id': object2.id
- })
- cid = fobj.create(cr, uid, val, context={})
- cr.commit()
-
- s = file_wrapper('', cid, cr.dbname, uid, )
- return s
- except Exception,e:
- print e
- raise OSError(1, 'Operation not permited.')
-
- # Ok
- def open(self, node, mode):
- if not node:
- raise OSError(1, 'Operation not permited.')
- # Reading operation
- if node.type=='file':
- if not self.isfile(node):
- raise OSError(1, 'Operation not permited.')
- s = StringIO.StringIO(base64.decodestring(node.object.datas or ''))
- s.name = node
- return s
- elif node.type=='content':
- cr = node.cr
- uid = node.uid
- pool = pooler.get_pool(cr.dbname)
- report = pool.get('ir.actions.report.xml').browse(cr, uid, node.content['report_id']['id'])
- srv = netsvc.LocalService('report.'+report.report_name)
- pdf,pdftype = srv.create(cr, uid, [node.object.id], {}, {})
- s = StringIO.StringIO(pdf)
- s.name = node
- return s
- else:
- raise OSError(1, 'Operation not permited.')
-
- # ok, but need test more
-
- def mkstemp(self, suffix='', prefix='', dir=None, mode='wb'):
- """A wrap around tempfile.mkstemp creating a file with a unique
- name. Unlike mkstemp it returns an object with a file-like
- interface.
- """
- raise 'Not Yet Implemented'
-# class FileWrapper:
-# def __init__(self, fd, name):
-# self.file = fd
-# self.name = name
-# def __getattr__(self, attr):
-# return getattr(self.file, attr)
+ """A class used to interact with the file system, providing a high
+ level, cross-platform interface compatible with both Windows and
+ UNIX style filesystems.
+
+ It provides some utility methods and some wraps around operations
+ involved in file creation and file system operations like moving
+ files or removing directories.
+
+ Instance attributes:
+ - (str) root: the user home directory.
+ - (str) cwd: the current working directory.
+ - (str) rnfr: source file to be renamed.
+ """
+
+ # Ok
+ def db_list(self):
+ s = netsvc.LocalService('db')
+ result = s.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 like 'document%' and state='installed' ")
+ res=cr.fetchone()
+ if res and len(res):
+ self.db_name_list.append(db_name)
+ cr.close()
+ return self.db_name_list
+
+ # Ok
+ def __init__(self):
+ self.root = None
+ self.cwd = '/'
+ self.rnfr = None
+
+ # --- Pathname / conversion utilities
+
+ # Ok
+ def ftpnorm(self, ftppath):
+ """Normalize a "virtual" ftp pathname (tipically the raw string
+ coming from client) depending on the current working directory.
+
+ Example (having "/foo" as current working directory):
+ 'x' -> '/foo/x'
+
+ Note: directory separators are system independent ("/").
+ Pathname returned is always absolutized.
+ """
+ if os.path.isabs(ftppath):
+ p = os.path.normpath(ftppath)
+ else:
+ p = os.path.normpath(os.path.join(self.cwd, ftppath))
+ # normalize string in a standard web-path notation having '/'
+ # as separator.
+ p = p.replace("\\", "/")
+ # os.path.normpath supports UNC paths (e.g. "//a/b/c") but we
+ # don't need them. In case we get an UNC path we collapse
+ # redundant separators appearing at the beginning of the string
+ while p[:2] == '//':
+ p = p[1:]
+ # Anti path traversal: don't trust user input, in the event
+ # that self.cwd is not absolute, return "/" as a safety measure.
+ # This is for extra protection, maybe not really necessary.
+ if not os.path.isabs(p):
+ p = "/"
+ return p
+
+ # Ok
+ def ftp2fs(self, path_orig, data):
+ path = self.ftpnorm(path_orig)
+ if path and path=='/':
+ return None
+ path2 = filter(None,path.split('/'))[1:]
+ (cr, uid, pool) = data
+ res = pool.get('document.directory').get_object(cr, uid, path2[:])
+ if not res:
+ raise OSError(2, 'Not such file or directory.')
+ return res
+
+ # Ok
+ def fs2ftp(self, node):
+ res = node and ('/' + node.cr.dbname + '/' + node.path) or '/'
+ return res
+
+ # Ok
+ def validpath(self, path):
+ """Check whether the path belongs to user's home directory.
+ Expected argument is a "real" filesystem pathname.
+
+ If path is a symbolic link it is resolved to check its real
+ destination.
+
+ Pathnames escaping from user's root directory are considered
+ not valid.
+ """
+ return path and True or False
+
+ # --- Wrapper methods around open() and tempfile.mkstemp
+
+ # Ok
+ def create(self, node, objname, mode):
+ cr = node.cr
+ uid = node.uid
+ pool = pooler.get_pool(cr.dbname)
+ child = node.child(objname)
+ if child:
+ if child.type in ('collection','database'):
+ raise OSError(1, 'Operation not permited.')
+ if child.type=='content':
+ s = content_wrapper(cr.dbname, uid, pool, child)
+ return s
+ try:
+ fobj = pool.get('ir.attachment')
+ ext = objname.find('.') >0 and objname.split('.')[1] or False
+
+ # TODO: test if already exist and modify in this case if node.type=file
+ ### checked already exits
+ object2=node and node.object2 or False
+ object=node and node.object or False
+ cid=False
+
+ where=[('name','=',objname)]
+ if object and (object.type in ('directory','ressource')) or object2:
+ where.append(('parent_id','=',object.id))
+ else:
+ where.append(('parent_id','=',False))
+
+ if object2:
+ where +=[('res_id','=',object2.id),('res_model','=',object2._name)]
+ cids = fobj.search(cr, uid,where)
+ if len(cids):
+ cid=cids[0]
+
+ if not cid:
+ val = {
+ 'name': objname,
+ 'datas_fname': objname,
+ 'datas': '',
+ 'file_size': 0L,
+ 'file_type': ext,
+ }
+ if object and (object.type in ('directory','ressource')) or not object2:
+ val['parent_id']= object and object.id or False
+ partner = False
+ if object2:
+ if 'partner_id' in object2 and object2.partner_id.id:
+ partner = object2.partner_id.id
+ if object2._name == 'res.partner':
+ partner = object2.id
+ val.update( {
+ 'res_model': object2._name,
+ 'partner_id': partner,
+ 'res_id': object2.id
+ })
+ cid = fobj.create(cr, uid, val, context={})
+ cr.commit()
+
+ s = file_wrapper('', cid, cr.dbname, uid, )
+ return s
+ except Exception,e:
+ print e
+ raise OSError(1, 'Operation not permited.')
+
+ # Ok
+ def open(self, node, mode):
+ if not node:
+ raise OSError(1, 'Operation not permited.')
+ # Reading operation
+ if node.type=='file':
+ if not self.isfile(node):
+ raise OSError(1, 'Operation not permited.')
+ s = StringIO.StringIO(base64.decodestring(node.object.datas or ''))
+ s.name = node
+ return s
+ elif node.type=='content':
+ cr = node.cr
+ uid = node.uid
+ pool = pooler.get_pool(cr.dbname)
+ return getattr(pool.get('document.directory.content'), 'process_read_'+node.content.extension[1:])(cr, uid, node)
+ else:
+ raise OSError(1, 'Operation not permited.')
+
+ # ok, but need test more
+
+ def mkstemp(self, suffix='', prefix='', dir=None, mode='wb'):
+ """A wrap around tempfile.mkstemp creating a file with a unique
+ name. Unlike mkstemp it returns an object with a file-like
+ interface.
+ """
+ raise 'Not Yet Implemented'
+# class FileWrapper:
+# def __init__(self, fd, name):
+# self.file = fd
+# self.name = name
+# def __getattr__(self, attr):
+# return getattr(self.file, attr)
#
-# text = not 'b' in mode
-# # max number of tries to find out a unique file name
-# tempfile.TMP_MAX = 50
-# fd, name = tempfile.mkstemp(suffix, prefix, dir, text=text)
-# file = os.fdopen(fd, mode)
-# return FileWrapper(file, name)
-
- text = not 'b' in mode
- # for unique file , maintain version if duplicate file
- if dir:
- cr = dir.cr
- uid = dir.uid
- pool = pooler.get_pool(cr.dbname)
- object=dir and dir.object or False
- object2=dir and dir.object2 or False
- res=pool.get('ir.attachment').search(cr,uid,[('name','like',prefix),('parent_id','=',object and object.type in ('directory','ressource') and object.id or False),('res_id','=',object2 and object2.id or False),('res_model','=',object2 and object2._name or False)])
- if len(res):
- pre = prefix.split('.')
- prefix=pre[0] + '.v'+str(len(res))+'.'+pre[1]
- #prefix = prefix + '.'
- return self.create(dir,suffix+prefix,text)
-
-
-
- # Ok
- def chdir(self, path):
- if not path:
- self.cwd='/'
- return None
- if path.type in ('collection','database'):
- self.cwd = self.fs2ftp(path)
- else:
- raise OSError(1, 'Operation not permited.')
-
- # Ok
- def mkdir(self, node, basename):
- """Create the specified directory."""
- if not node:
- raise OSError(1, 'Operation not permited.')
- try:
- object2=node and node.object2 or False
- object=node and node.object or False
- cr = node.cr
- uid = node.uid
- pool = pooler.get_pool(cr.dbname)
- if node.object and (node.object.type=='ressource') and not node.object2:
- raise OSError(1, 'Operation not permited.')
- val = {
- 'name': basename,
- 'ressource_parent_type_id': object and object.ressource_type_id.id or False,
- 'ressource_id': object2 and object2.id or False
- }
- if (object and (object.type in ('directory'))) or not object2:
- val['parent_id'] = object and object.id or False
- # Check if it alreayd exists !
- pool.get('document.directory').create(cr, uid, val)
- cr.commit()
- except Exception,e:
- print e
- raise OSError(1, 'Operation not permited.')
-
-
- # Ok
- def close_cr(self, data):
- if data:
- data[0].close()
- return True
-
- def get_cr(self, path):
- path = self.ftpnorm(path)
- if path=='/':
- return None
- dbname = path.split('/')[1]
- try:
- db,pool = pooler.get_db_and_pool(dbname)
- except:
- raise OSError(1, 'Operation not permited.')
- cr = db.cursor()
- uid = security.login(dbname, self.username, self.password)
- if not uid:
- raise OSError(1, 'Operation not permited.')
- return cr, uid, pool
-
- # Ok
- def listdir(self, path):
- """List the content of a directory."""
- class false_node:
- object = None
- type = 'database'
- def __init__(self, db):
- self.path = '/'+db
-
- if path is None:
- result = []
- for db in self.db_list():
- result.append(false_node(db))
- return result
- return path.children()
-
- # Ok
- def rmdir(self, node):
- """Remove the specified directory."""
- cr = node.cr
- uid = node.uid
- pool = pooler.get_pool(cr.dbname)
- object2=node and node.object2 or False
- object=node and node.object or False
- if object._table_name=='document.directory':
- if node.children():
- raise OSError(39, 'Directory not empty.')
- res = pool.get('document.directory').unlink(cr, uid, [object.id])
- else:
- raise OSError(39, 'Directory not empty.')
-
- cr.commit()
-
- # Ok
- def remove(self, node):
- """Remove the specified file."""
- cr = node.cr
- uid = node.uid
- pool = pooler.get_pool(cr.dbname)
- object2=node and node.object2 or False
- object=node and node.object or False
- if not object:
- raise OSError(2, 'Not such file or directory.')
- if object._table_name=='ir.attachment':
- res = pool.get('ir.attachment').unlink(cr, uid, [object.id])
- else:
- raise OSError(1, 'Operation not permited.')
- cr.commit()
-
- # Ok
- def rename(self, src, dst_basedir,dst_basename):
- """
- Renaming operation, the effect depends on the src:
- * A file: read, create and remove
- * A directory: change the parent and reassign childs to ressource
- """
- try:
- if src.type=='collection':
- if src.object._table_name <> 'document.directory':
- raise OSError(1, 'Operation not permited.')
- result = {
- 'directory': [],
- 'attachment': []
- }
- # Compute all childs to set the new ressource ID
- child_ids = [src]
- while len(child_ids):
- node = child_ids.pop(0)
- child_ids += node.children()
- if node.type =='collection':
- result['directory'].append(node.object.id)
- if (not node.object.ressource_id) and node.object2:
- raise OSError(1, 'Operation not permited.')
- elif node.type =='file':
- result['attachment'].append(node.object.id)
-
- cr = src.cr
- uid = src.uid
- pool = pooler.get_pool(cr.dbname)
- object2=src and src.object2 or False
- object=src and src.object or False
- if object2 and not object.ressource_id:
- raise OSError(1, 'Operation not permited.')
- val = {
- 'name':dst_basename,
- }
- if (dst_basedir.object and (dst_basedir.object.type in ('directory'))) or not dst_basedir.object2:
- val['parent_id'] = dst_basedir.object and dst_basedir.object.id or False
- else:
- val['parent_id'] = False
- res = pool.get('document.directory').write(cr, uid, [object.id],val)
-
- if dst_basedir.object2:
- ressource_type_id = pool.get('ir.model').search(cr,uid,[('model','=',dst_basedir.object2._name)])[0]
- ressource_id = dst_basedir.object2.id
- title = dst_basedir.object2.name
- ressource_model = dst_basedir.object2._name
- if dst_basedir.object2._name=='res.partner':
- partner_id=dst_basedir.object2.id
- else:
- partner_id= dst_basedir.object2.partner_id and dst_basedir.object2.partner_id.id or False
- else:
- ressource_type_id = False
- ressource_id=False
- ressource_model = False
- partner_id = False
- title = False
-
- pool.get('document.directory').write(cr, uid, result['directory'], {
- 'ressource_id': ressource_id,
- 'ressource_parent_type_id': ressource_type_id
- })
- val = {
- 'res_id': ressource_id,
- 'res_model': ressource_model,
- 'title': title,
- 'partner_id': partner_id
- }
- pool.get('ir.attachment').write(cr, uid, result['attachment'], val)
- if (not val['res_id']) and result['attachment']:
- dst_basedir.cr.execute('update ir_attachment set res_id=NULL where id in ('+','.join(map(str,result['attachment']))+')')
-
- cr.commit()
- elif src.type=='file':
- pool = pooler.get_pool(src.cr.dbname)
- val = {
- 'partner_id':False,
- #'res_id': False,
- 'res_model': False,
- 'name': dst_basename,
- 'datas_fname': dst_basename,
- 'title': dst_basename,
- }
-
- if (dst_basedir.object and (dst_basedir.object.type in ('directory','ressource'))) or not dst_basedir.object2:
- val['parent_id'] = dst_basedir.object and dst_basedir.object.id or False
- else:
- val['parent_id'] = False
-
- if dst_basedir.object2:
- val['res_model'] = dst_basedir.object2._name
- val['res_id'] = dst_basedir.object2.id
- val['title'] = dst_basedir.object2.name
- if dst_basedir.object2._name=='res.partner':
- val['partner_id']=dst_basedir.object2.id
- else:
- val['partner_id']= dst_basedir.object2.partner_id and dst_basedir.object2.partner_id.id or False
- elif src.object.res_id:
- # I had to do that because writing False to an integer writes 0 instead of NULL
- # change if one day we decide to improve osv/fields.py
- dst_basedir.cr.execute('update ir_attachment set res_id=NULL where id=%d', (src.object.id,))
-
- pool.get('ir.attachment').write(src.cr, src.uid, [src.object.id], val)
- src.cr.commit()
- elif src.type=='content':
- src_file=self.open(src,'r')
- dst_file=self.create(dst_basedir,dst_basename,'w')
- dst_file.write(src_file.getvalue())
- dst_file.close()
- src_file.close()
- src.cr.commit()
- else:
- raise OSError(1, 'Operation not permited.')
- except Exception,err:
- print err
- raise OSError(1,'Operation not permited.')
-
-
-
-
- # Nearly Ok
- def stat(self, node):
- r = list(os.stat('/'))
- if self.isfile(node):
- r[0] = 33188
- r[6] = self.getsize(node)
- r[7] = self.getmtime(node)
- r[8] = self.getmtime(node)
- r[9] = self.getmtime(node)
- return posix.stat_result(r)
- lstat = stat
-
- # --- Wrapper methods around os.path.*
-
- # Ok
- def isfile(self, node):
- if node and (node.type not in ('collection','database')):
- return True
- return False
-
- # Ok
- def islink(self, path):
- """Return True if path is a symbolic link."""
- return False
-
- # Ok
- def isdir(self, node):
- """Return True if path is a directory."""
- if node is None:
- return True
- if node and (node.type in ('collection','database')):
- return True
- return False
-
- # Ok
- def getsize(self, node):
- """Return the size of the specified file in bytes."""
- result = 0L
- if node.type=='file':
- result = node.object.file_size or 0L
- return result
-
- # Ok
- def getmtime(self, node):
- """Return the last modified time as a number of seconds since
- the epoch."""
- if node.object and node.type<>'content':
- dt = (node.object.write_date or node.object.create_date)[:19]
- result = time.mktime(time.strptime(dt, '%Y-%m-%d %H:%M:%S'))
- else:
- result = time.mktime(time.localtime())
- return result
-
- # Ok
- def realpath(self, path):
- """Return the canonical version of path eliminating any
- symbolic links encountered in the path (if they are
- supported by the operating system).
- """
- return path
-
- # Ok
- def lexists(self, path):
- """Return True if path refers to an existing path, including
- a broken or circular symbolic link.
- """
- return path and True or False
- exists = lexists
-
- # Ok, can be improved
- def glob1(self, dirname, pattern):
- """Return a list of files matching a dirname pattern
- non-recursively.
-
- Unlike glob.glob1 raises exception if os.listdir() fails.
- """
- names = self.listdir(dirname)
- if pattern[0] != '.':
- names = filter(lambda x: x.path[0] != '.', names)
- return fnmatch.filter(names, pattern)
-
- # --- Listing utilities
-
- # note: the following operations are no more blocking
-
- # Ok
- def get_list_dir(self, path):
- """"Return an iterator object that yields a directory listing
- in a form suitable for LIST command.
- """
- if self.isdir(path):
- listing = self.listdir(path)
- #listing.sort()
- return self.format_list(path and path.path or '/', listing)
- # if path is a file or a symlink we return information about it
- elif self.isfile(path):
- basedir, filename = os.path.split(path.path)
- self.lstat(path) # raise exc in case of problems
- return self.format_list(basedir, [filename])
-
-
- # Ok
- def get_stat_dir(self, rawline, datacr):
- """Return an iterator object that yields a list of files
- matching a dirname pattern non-recursively in a form
- suitable for STAT command.
-
- - (str) rawline: the raw string passed by client as command
- argument.
- """
- ftppath = self.ftpnorm(rawline)
- if not glob.has_magic(ftppath):
- return self.get_list_dir(self.ftp2fs(rawline, datacr))
- else:
- basedir, basename = os.path.split(ftppath)
- if glob.has_magic(basedir):
- return iter(['Directory recursion not supported.\r\n'])
- else:
- basedir = self.ftp2fs(basedir, datacr)
- listing = self.glob1(basedir, basename)
- if listing:
- listing.sort()
- return self.format_list(basedir, listing)
-
- # Ok
- def format_list(self, basedir, listing, ignore_err=True):
- """Return an iterator object that yields the entries of given
- directory emulating the "/bin/ls -lA" UNIX command output.
-
- - (str) basedir: the absolute dirname.
- - (list) listing: the names of the entries in basedir
- - (bool) ignore_err: when False raise exception if os.lstat()
- call fails.
-
- On platforms which do not support the pwd and grp modules (such
- as Windows), ownership is printed as "owner" and "group" as a
- default, and number of hard links is always "1". On UNIX
- systems, the actual owner, group, and number of links are
- printed.
-
- This is how output appears to client:
-
- -rw-rw-rw- 1 owner group 7045120 Sep 02 3:47 music.mp3
- drwxrwxrwx 1 owner group 0 Aug 31 18:50 e-books
- -rw-rw-rw- 1 owner group 380 Sep 02 3:40 module.py
- """
- for file in listing:
- try:
- st = self.lstat(file)
- except os.error:
- if ignore_err:
- continue
- raise
- perms = filemode(st.st_mode) # permissions
- nlinks = st.st_nlink # number of links to inode
- if not nlinks: # non-posix system, let's use a bogus value
- nlinks = 1
- size = st.st_size # file size
- uname = "owner"
- gname = "group"
- # stat.st_mtime could fail (-1) if last mtime is too old
- # in which case we return the local time as last mtime
- try:
- mtime = time.strftime("%b %d %H:%M", time.localtime(st.st_mtime))
- except ValueError:
- mtime = time.strftime("%b %d %H:%M")
-
- # formatting is matched with proftpd ls output
- yield "%s %3s %-8s %-8s %8s %s %s\r\n" %(perms, nlinks, uname, gname,
- size, mtime, file.path.split('/')[-1])
-
- # Ok
- def format_mlsx(self, basedir, listing, perms, facts, ignore_err=True):
- """Return an iterator object that yields the entries of a given
- directory or of a single file in a form suitable with MLSD and
- MLST commands.
-
- Every entry includes a list of "facts" referring the listed
- element. See RFC-3659, chapter 7, to see what every single
- fact stands for.
-
- - (str) basedir: the absolute dirname.
- - (list) listing: the names of the entries in basedir
- - (str) perms: the string referencing the user permissions.
- - (str) facts: the list of "facts" to be returned.
- - (bool) ignore_err: when False raise exception if os.stat()
- call fails.
-
- Note that "facts" returned may change depending on the platform
- and on what user specified by using the OPTS command.
-
- This is how output could appear to the client issuing
- a MLSD request:
-
- type=file;size=156;perm=r;modify=20071029155301;unique=801cd2; music.mp3
- type=dir;size=0;perm=el;modify=20071127230206;unique=801e33; ebooks
- type=file;size=211;perm=r;modify=20071103093626;unique=801e32; module.py
- """
- permdir = ''.join([x for x in perms if x not in 'arw'])
- permfile = ''.join([x for x in perms if x not in 'celmp'])
- if ('w' in perms) or ('a' in perms) or ('f' in perms):
- permdir += 'c'
- if 'd' in perms:
- permdir += 'p'
- type = size = perm = modify = create = unique = mode = uid = gid = ""
- for basename in listing:
- file = os.path.join(basedir, basename)
- try:
- st = self.stat(file)
- except OSError:
- if ignore_err:
- continue
- raise
- # type + perm
- if stat.S_ISDIR(st.st_mode):
- if 'type' in facts:
- if basename == '.':
- type = 'type=cdir;'
- elif basename == '..':
- type = 'type=pdir;'
- else:
- type = 'type=dir;'
- if 'perm' in facts:
- perm = 'perm=%s;' %permdir
- else:
- if 'type' in facts:
- type = 'type=file;'
- if 'perm' in facts:
- perm = 'perm=%s;' %permfile
- if 'size' in facts:
- size = 'size=%s;' %st.st_size # file size
- # last modification time
- if 'modify' in facts:
- try:
- modify = 'modify=%s;' %time.strftime("%Y%m%d%H%M%S",
- time.localtime(st.st_mtime))
- except ValueError:
- # stat.st_mtime could fail (-1) if last mtime is too old
- modify = ""
- if 'create' in facts:
- # on Windows we can provide also the creation time
- try:
- create = 'create=%s;' %time.strftime("%Y%m%d%H%M%S",
- time.localtime(st.st_ctime))
- except ValueError:
- create = ""
- # UNIX only
- if 'unix.mode' in facts:
- mode = 'unix.mode=%s;' %oct(st.st_mode & 0777)
- if 'unix.uid' in facts:
- uid = 'unix.uid=%s;' %st.st_uid
- if 'unix.gid' in facts:
- gid = 'unix.gid=%s;' %st.st_gid
- # We provide unique fact (see RFC-3659, chapter 7.5.2) on
- # posix platforms only; we get it by mixing st_dev and
- # st_ino values which should be enough for granting an
- # uniqueness for the file listed.
- # The same approach is used by pure-ftpd.
- # Implementors who want to provide unique fact on other
- # platforms should use some platform-specific method (e.g.
- # on Windows NTFS filesystems MTF records could be used).
- if 'unique' in facts:
- unique = "unique=%x%x;" %(st.st_dev, st.st_ino)
-
- yield "%s%s%s%s%s%s%s%s%s %s\r\n" %(type, size, perm, modify, create,
- mode, uid, gid, unique, basename)
+# text = not 'b' in mode
+# # max number of tries to find out a unique file name
+# tempfile.TMP_MAX = 50
+# fd, name = tempfile.mkstemp(suffix, prefix, dir, text=text)
+# file = os.fdopen(fd, mode)
+# return FileWrapper(file, name)
+
+ text = not 'b' in mode
+ # for unique file , maintain version if duplicate file
+ if dir:
+ cr = dir.cr
+ uid = dir.uid
+ pool = pooler.get_pool(cr.dbname)
+ object=dir and dir.object or False
+ object2=dir and dir.object2 or False
+ res=pool.get('ir.attachment').search(cr,uid,[('name','like',prefix),('parent_id','=',object and object.type in ('directory','ressource') and object.id or False),('res_id','=',object2 and object2.id or False),('res_model','=',object2 and object2._name or False)])
+ if len(res):
+ pre = prefix.split('.')
+ prefix=pre[0] + '.v'+str(len(res))+'.'+pre[1]
+ #prefix = prefix + '.'
+ return self.create(dir,suffix+prefix,text)
+
+
+
+ # Ok
+ def chdir(self, path):
+ if not path:
+ self.cwd='/'
+ return None
+ if path.type in ('collection','database'):
+ self.cwd = self.fs2ftp(path)
+ else:
+ raise OSError(1, 'Operation not permited.')
+
+ # Ok
+ def mkdir(self, node, basename):
+ """Create the specified directory."""
+ if not node:
+ raise OSError(1, 'Operation not permited.')
+ try:
+ object2=node and node.object2 or False
+ object=node and node.object or False
+ cr = node.cr
+ uid = node.uid
+ pool = pooler.get_pool(cr.dbname)
+ if node.object and (node.object.type=='ressource') and not node.object2:
+ raise OSError(1, 'Operation not permited.')
+ val = {
+ 'name': basename,
+ 'ressource_parent_type_id': object and object.ressource_type_id.id or False,
+ 'ressource_id': object2 and object2.id or False
+ }
+ if (object and (object.type in ('directory'))) or not object2:
+ val['parent_id'] = object and object.id or False
+ # Check if it alreayd exists !
+ pool.get('document.directory').create(cr, uid, val)
+ cr.commit()
+ except Exception,e:
+ print e
+ raise OSError(1, 'Operation not permited.')
+
+
+ # Ok
+ def close_cr(self, data):
+ if data:
+ data[0].close()
+ return True
+
+ def get_cr(self, path):
+ path = self.ftpnorm(path)
+ if path=='/':
+ return None
+ dbname = path.split('/')[1]
+ try:
+ db,pool = pooler.get_db_and_pool(dbname)
+ except:
+ raise OSError(1, 'Operation not permited.')
+ cr = db.cursor()
+ uid = security.login(dbname, self.username, self.password)
+ if not uid:
+ raise OSError(2, 'Authentification Required.')
+ return cr, uid, pool
+
+ # Ok
+ def listdir(self, path):
+ """List the content of a directory."""
+ class false_node:
+ object = None
+ type = 'database'
+ def __init__(self, db):
+ self.path = '/'+db
+
+ if path is None:
+ result = []
+ for db in self.db_list():
+ result.append(false_node(db))
+ return result
+ return path.children()
+
+ # Ok
+ def rmdir(self, node):
+ """Remove the specified directory."""
+ cr = node.cr
+ uid = node.uid
+ pool = pooler.get_pool(cr.dbname)
+ object2=node and node.object2 or False
+ object=node and node.object or False
+ if object._table_name=='document.directory':
+ if node.children():
+ raise OSError(39, 'Directory not empty.')
+ res = pool.get('document.directory').unlink(cr, uid, [object.id])
+ else:
+ raise OSError(39, 'Directory not empty.')
+
+ cr.commit()
+
+ # Ok
+ def remove(self, node):
+ """Remove the specified file."""
+ cr = node.cr
+ uid = node.uid
+ pool = pooler.get_pool(cr.dbname)
+ object2=node and node.object2 or False
+ object=node and node.object or False
+ if not object:
+ raise OSError(2, 'Not such file or directory.')
+ if object._table_name=='ir.attachment':
+ res = pool.get('ir.attachment').unlink(cr, uid, [object.id])
+ else:
+ raise OSError(1, 'Operation not permited.')
+ cr.commit()
+
+ # Ok
+ def rename(self, src, dst_basedir,dst_basename):
+ """
+ Renaming operation, the effect depends on the src:
+ * A file: read, create and remove
+ * A directory: change the parent and reassign childs to ressource
+ """
+ try:
+ if src.type=='collection':
+ if src.object._table_name <> 'document.directory':
+ raise OSError(1, 'Operation not permited.')
+ result = {
+ 'directory': [],
+ 'attachment': []
+ }
+ # Compute all childs to set the new ressource ID
+ child_ids = [src]
+ while len(child_ids):
+ node = child_ids.pop(0)
+ child_ids += node.children()
+ if node.type =='collection':
+ result['directory'].append(node.object.id)
+ if (not node.object.ressource_id) and node.object2:
+ raise OSError(1, 'Operation not permited.')
+ elif node.type =='file':
+ result['attachment'].append(node.object.id)
+
+ cr = src.cr
+ uid = src.uid
+ pool = pooler.get_pool(cr.dbname)
+ object2=src and src.object2 or False
+ object=src and src.object or False
+ if object2 and not object.ressource_id:
+ raise OSError(1, 'Operation not permited.')
+ val = {
+ 'name':dst_basename,
+ }
+ if (dst_basedir.object and (dst_basedir.object.type in ('directory'))) or not dst_basedir.object2:
+ val['parent_id'] = dst_basedir.object and dst_basedir.object.id or False
+ else:
+ val['parent_id'] = False
+ res = pool.get('document.directory').write(cr, uid, [object.id],val)
+
+ if dst_basedir.object2:
+ ressource_type_id = pool.get('ir.model').search(cr,uid,[('model','=',dst_basedir.object2._name)])[0]
+ ressource_id = dst_basedir.object2.id
+ title = dst_basedir.object2.name
+ ressource_model = dst_basedir.object2._name
+ if dst_basedir.object2._name=='res.partner':
+ partner_id=dst_basedir.object2.id
+ else:
+ partner_id= dst_basedir.object2.partner_id and dst_basedir.object2.partner_id.id or False
+ else:
+ ressource_type_id = False
+ ressource_id=False
+ ressource_model = False
+ partner_id = False
+ title = False
+
+ pool.get('document.directory').write(cr, uid, result['directory'], {
+ 'ressource_id': ressource_id,
+ 'ressource_parent_type_id': ressource_type_id
+ })
+ val = {
+ 'res_id': ressource_id,
+ 'res_model': ressource_model,
+ 'title': title,
+ 'partner_id': partner_id
+ }
+ pool.get('ir.attachment').write(cr, uid, result['attachment'], val)
+ if (not val['res_id']) and result['attachment']:
+ dst_basedir.cr.execute('update ir_attachment set res_id=NULL where id in ('+','.join(map(str,result['attachment']))+')')
+
+ cr.commit()
+ elif src.type=='file':
+ pool = pooler.get_pool(src.cr.dbname)
+ val = {
+ 'partner_id':False,
+ #'res_id': False,
+ 'res_model': False,
+ 'name': dst_basename,
+ 'datas_fname': dst_basename,
+ 'title': dst_basename,
+ }
+
+ if (dst_basedir.object and (dst_basedir.object.type in ('directory','ressource'))) or not dst_basedir.object2:
+ val['parent_id'] = dst_basedir.object and dst_basedir.object.id or False
+ else:
+ val['parent_id'] = False
+
+ if dst_basedir.object2:
+ val['res_model'] = dst_basedir.object2._name
+ val['res_id'] = dst_basedir.object2.id
+ val['title'] = dst_basedir.object2.name
+ if dst_basedir.object2._name=='res.partner':
+ val['partner_id']=dst_basedir.object2.id
+ else:
+ val['partner_id']= dst_basedir.object2.partner_id and dst_basedir.object2.partner_id.id or False
+ elif src.object.res_id:
+ # I had to do that because writing False to an integer writes 0 instead of NULL
+ # change if one day we decide to improve osv/fields.py
+ dst_basedir.cr.execute('update ir_attachment set res_id=NULL where id=%d', (src.object.id,))
+
+ pool.get('ir.attachment').write(src.cr, src.uid, [src.object.id], val)
+ src.cr.commit()
+ elif src.type=='content':
+ src_file=self.open(src,'r')
+ dst_file=self.create(dst_basedir,dst_basename,'w')
+ dst_file.write(src_file.getvalue())
+ dst_file.close()
+ src_file.close()
+ src.cr.commit()
+ else:
+ raise OSError(1, 'Operation not permited.')
+ except Exception,err:
+ print err
+ raise OSError(1,'Operation not permited.')
+
+
+
+
+ # Nearly Ok
+ def stat(self, node):
+ r = list(os.stat('/'))
+ if self.isfile(node):
+ r[0] = 33188
+ r[6] = self.getsize(node)
+ r[7] = self.getmtime(node)
+ r[8] = self.getmtime(node)
+ r[9] = self.getmtime(node)
+ return os.stat_result(r)
+ lstat = stat
+
+ # --- Wrapper methods around os.path.*
+
+ # Ok
+ def isfile(self, node):
+ if node and (node.type not in ('collection','database')):
+ return True
+ return False
+
+ # Ok
+ def islink(self, path):
+ """Return True if path is a symbolic link."""
+ return False
+
+ # Ok
+ def isdir(self, node):
+ """Return True if path is a directory."""
+ if node is None:
+ return True
+ if node and (node.type in ('collection','database')):
+ return True
+ return False
+
+ # Ok
+ def getsize(self, node):
+ """Return the size of the specified file in bytes."""
+ result = 0L
+ if node.type=='file':
+ result = node.object.file_size or 0L
+ return result
+
+ # Ok
+ def getmtime(self, node):
+ """Return the last modified time as a number of seconds since
+ the epoch."""
+ if node.object and node.type<>'content':
+ dt = (node.object.write_date or node.object.create_date)[:19]
+ result = time.mktime(time.strptime(dt, '%Y-%m-%d %H:%M:%S'))
+ else:
+ result = time.mktime(time.localtime())
+ return result
+
+ # Ok
+ def realpath(self, path):
+ """Return the canonical version of path eliminating any
+ symbolic links encountered in the path (if they are
+ supported by the operating system).
+ """
+ return path
+
+ # Ok
+ def lexists(self, path):
+ """Return True if path refers to an existing path, including
+ a broken or circular symbolic link.
+ """
+ return path and True or False
+ exists = lexists
+
+ # Ok, can be improved
+ def glob1(self, dirname, pattern):
+ """Return a list of files matching a dirname pattern
+ non-recursively.
+
+ Unlike glob.glob1 raises exception if os.listdir() fails.
+ """
+ names = self.listdir(dirname)
+ if pattern[0] != '.':
+ names = filter(lambda x: x.path[0] != '.', names)
+ return fnmatch.filter(names, pattern)
+
+ # --- Listing utilities
+
+ # note: the following operations are no more blocking
+
+ # Ok
+ def get_list_dir(self, path):
+ """"Return an iterator object that yields a directory listing
+ in a form suitable for LIST command.
+ """
+ if self.isdir(path):
+ listing = self.listdir(path)
+ #listing.sort()
+ return self.format_list(path and path.path or '/', listing)
+ # if path is a file or a symlink we return information about it
+ elif self.isfile(path):
+ basedir, filename = os.path.split(path.path)
+ self.lstat(path) # raise exc in case of problems
+ return self.format_list(basedir, [filename])
+
+
+ # Ok
+ def get_stat_dir(self, rawline, datacr):
+ """Return an iterator object that yields a list of files
+ matching a dirname pattern non-recursively in a form
+ suitable for STAT command.
+
+ - (str) rawline: the raw string passed by client as command
+ argument.
+ """
+ ftppath = self.ftpnorm(rawline)
+ if not glob.has_magic(ftppath):
+ return self.get_list_dir(self.ftp2fs(rawline, datacr))
+ else:
+ basedir, basename = os.path.split(ftppath)
+ if glob.has_magic(basedir):
+ return iter(['Directory recursion not supported.\r\n'])
+ else:
+ basedir = self.ftp2fs(basedir, datacr)
+ listing = self.glob1(basedir, basename)
+ if listing:
+ listing.sort()
+ return self.format_list(basedir, listing)
+
+ # Ok
+ def format_list(self, basedir, listing, ignore_err=True):
+ """Return an iterator object that yields the entries of given
+ directory emulating the "/bin/ls -lA" UNIX command output.
+
+ - (str) basedir: the absolute dirname.
+ - (list) listing: the names of the entries in basedir
+ - (bool) ignore_err: when False raise exception if os.lstat()
+ call fails.
+
+ On platforms which do not support the pwd and grp modules (such
+ as Windows), ownership is printed as "owner" and "group" as a
+ default, and number of hard links is always "1". On UNIX
+ systems, the actual owner, group, and number of links are
+ printed.
+
+ This is how output appears to client:
+
+ -rw-rw-rw- 1 owner group 7045120 Sep 02 3:47 music.mp3
+ drwxrwxrwx 1 owner group 0 Aug 31 18:50 e-books
+ -rw-rw-rw- 1 owner group 380 Sep 02 3:40 module.py
+ """
+ for file in listing:
+ try:
+ st = self.lstat(file)
+ except os.error:
+ if ignore_err:
+ continue
+ raise
+ perms = filemode(st.st_mode) # permissions
+ nlinks = st.st_nlink # number of links to inode
+ if not nlinks: # non-posix system, let's use a bogus value
+ nlinks = 1
+ size = st.st_size # file size
+ uname = "owner"
+ gname = "group"
+ # stat.st_mtime could fail (-1) if last mtime is too old
+ # in which case we return the local time as last mtime
+ try:
+ mtime = time.strftime("%b %d %H:%M", time.localtime(st.st_mtime))
+ except ValueError:
+ mtime = time.strftime("%b %d %H:%M")
+
+ # formatting is matched with proftpd ls output
+ yield "%s %3s %-8s %-8s %8s %s %s\r\n" %(perms, nlinks, uname, gname,
+ size, mtime, file.path.split('/')[-1])
+
+ # Ok
+ def format_mlsx(self, basedir, listing, perms, facts, ignore_err=True):
+ """Return an iterator object that yields the entries of a given
+ directory or of a single file in a form suitable with MLSD and
+ MLST commands.
+
+ Every entry includes a list of "facts" referring the listed
+ element. See RFC-3659, chapter 7, to see what every single
+ fact stands for.
+
+ - (str) basedir: the absolute dirname.
+ - (list) listing: the names of the entries in basedir
+ - (str) perms: the string referencing the user permissions.
+ - (str) facts: the list of "facts" to be returned.
+ - (bool) ignore_err: when False raise exception if os.stat()
+ call fails.
+
+ Note that "facts" returned may change depending on the platform
+ and on what user specified by using the OPTS command.
+
+ This is how output could appear to the client issuing
+ a MLSD request:
+
+ type=file;size=156;perm=r;modify=20071029155301;unique=801cd2; music.mp3
+ type=dir;size=0;perm=el;modify=20071127230206;unique=801e33; ebooks
+ type=file;size=211;perm=r;modify=20071103093626;unique=801e32; module.py
+ """
+ permdir = ''.join([x for x in perms if x not in 'arw'])
+ permfile = ''.join([x for x in perms if x not in 'celmp'])
+ if ('w' in perms) or ('a' in perms) or ('f' in perms):
+ permdir += 'c'
+ if 'd' in perms:
+ permdir += 'p'
+ type = size = perm = modify = create = unique = mode = uid = gid = ""
+ for basename in listing:
+ file = os.path.join(basedir, basename)
+ try:
+ st = self.stat(file)
+ except OSError:
+ if ignore_err:
+ continue
+ raise
+ # type + perm
+ if stat.S_ISDIR(st.st_mode):
+ if 'type' in facts:
+ if basename == '.':
+ type = 'type=cdir;'
+ elif basename == '..':
+ type = 'type=pdir;'
+ else:
+ type = 'type=dir;'
+ if 'perm' in facts:
+ perm = 'perm=%s;' %permdir
+ else:
+ if 'type' in facts:
+ type = 'type=file;'
+ if 'perm' in facts:
+ perm = 'perm=%s;' %permfile
+ if 'size' in facts:
+ size = 'size=%s;' %st.st_size # file size
+ # last modification time
+ if 'modify' in facts:
+ try:
+ modify = 'modify=%s;' %time.strftime("%Y%m%d%H%M%S",
+ time.localtime(st.st_mtime))
+ except ValueError:
+ # stat.st_mtime could fail (-1) if last mtime is too old
+ modify = ""
+ if 'create' in facts:
+ # on Windows we can provide also the creation time
+ try:
+ create = 'create=%s;' %time.strftime("%Y%m%d%H%M%S",
+ time.localtime(st.st_ctime))
+ except ValueError:
+ create = ""
+ # UNIX only
+ if 'unix.mode' in facts:
+ mode = 'unix.mode=%s;' %oct(st.st_mode & 0777)
+ if 'unix.uid' in facts:
+ uid = 'unix.uid=%s;' %st.st_uid
+ if 'unix.gid' in facts:
+ gid = 'unix.gid=%s;' %st.st_gid
+ # We provide unique fact (see RFC-3659, chapter 7.5.2) on
+ # posix platforms only; we get it by mixing st_dev and
+ # st_ino values which should be enough for granting an
+ # uniqueness for the file listed.
+ # The same approach is used by pure-ftpd.
+ # Implementors who want to provide unique fact on other
+ # platforms should use some platform-specific method (e.g.
+ # on Windows NTFS filesystems MTF records could be used).
+ if 'unique' in facts:
+ unique = "unique=%x%x;" %(st.st_dev, st.st_ino)
+
+ yield "%s%s%s%s%s%s%s%s%s %s\r\n" %(type, size, perm, modify, create,
+ mode, uid, gid, unique, basename)
diff --git a/addons/document/ftpserver/authorizer.py b/addons/document/ftpserver/authorizer.py
index d33dc5d7234..fa45f0c3183 100644
--- a/addons/document/ftpserver/authorizer.py
+++ b/addons/document/ftpserver/authorizer.py
@@ -1,70 +1,71 @@
#import pooler
class authorizer:
- read_perms = "elr"
- write_perms = "adfmw"
-
- def __init__(self):
- self.password = ''
-
- def validate_authentication(self, username, password):
- """Return True if the supplied username and password match the
- stored credentials."""
- self.password = password
- return True
-
- def impersonate_user(self, username, password):
- """Impersonate another user (noop).
-
- It is always called before accessing the filesystem.
- By default it does nothing. The subclass overriding this
- method is expected to provide a mechanism to change the
- current user.
- """
-
- def terminate_impersonation(self):
- """Terminate impersonation (noop).
-
- It is always called after having accessed the filesystem.
- By default it does nothing. The subclass overriding this
- method is expected to provide a mechanism to switch back
- to the original user.
- """
-
- def has_user(self, username):
- """Whether the username exists in the virtual users table."""
- return True
-
- def has_perm(self, username, perm, path=None):
- """Whether the user has permission over path (an absolute
- pathname of a file or a directory).
-
- Expected perm argument is one of the following letters:
- "elradfmw".
- """
- return True
- paths = path.split('/')
- if not len(paths)>2:
- return True
- db_name = paths[1]
- db,pool = pooler.get_db_and_pool(db_name)
- res = security.login(db_name, username, self.password)
- return bool(res)
-
- def get_perms(self, username):
- """Return current user permissions."""
- return 'elr'
-
- def get_home_dir(self, username):
- """Return the user's home directory."""
- return '/'
-
- def get_msg_login(self, username):
- """Return the user's login message."""
- return 'Welcome on OpenERP document management system.'
-
- def get_msg_quit(self, username):
- """Return the user's quitting message."""
- return 'Bye.'
+ read_perms = "elr"
+ write_perms = "adfmw"
+
+ def __init__(self):
+ self.password = ''
+
+ def validate_authentication(self, username, password):
+ """Return True if the supplied username and password match the
+ stored credentials."""
+ self.password = password
+ return True
+
+ def impersonate_user(self, username, password):
+ """Impersonate another user (noop).
+
+ It is always called before accessing the filesystem.
+ By default it does nothing. The subclass overriding this
+ method is expected to provide a mechanism to change the
+ current user.
+ """
+
+ def terminate_impersonation(self):
+ """Terminate impersonation (noop).
+
+ It is always called after having accessed the filesystem.
+ By default it does nothing. The subclass overriding this
+ method is expected to provide a mechanism to switch back
+ to the original user.
+ """
+
+ def has_user(self, username):
+ """Whether the username exists in the virtual users table."""
+ if username=='anonymous':
+ return False
+ return True
+
+ def has_perm(self, username, perm, path=None):
+ """Whether the user has permission over path (an absolute
+ pathname of a file or a directory).
+
+ Expected perm argument is one of the following letters:
+ "elradfmw".
+ """
+ paths = path.split('/')
+ if not len(paths)>2:
+ return True
+ db_name = paths[1]
+ db,pool = pooler.get_db_and_pool(db_name)
+ res = security.login(db_name, username, self.password)
+ return bool(res)
+
+ def get_perms(self, username):
+ """Return current user permissions."""
+ return 'elr'
+
+ def get_home_dir(self, username):
+ """Return the user's home directory."""
+ return '/'
+
+ def get_msg_login(self, username):
+ """Return the user's login message."""
+ return 'Welcome on OpenERP document management system.'
+
+ def get_msg_quit(self, username):
+ """Return the user's quitting message."""
+ return 'Bye.'
diff --git a/addons/document/ftpserver/ftpserver.py b/addons/document/ftpserver/ftpserver.py
index 4ca5b06bb39..99b1c43abb3 100644
--- a/addons/document/ftpserver/ftpserver.py
+++ b/addons/document/ftpserver/ftpserver.py
@@ -2512,9 +2512,14 @@ class FTPHandler(asynchat.async_chat):
path = self.fs.ftp2fs(line, datacr)
self.run_as_current_user(self.fs.chdir, path)
except OSError, err:
- why = _strerror(err)
- self.log('FAIL CWD "%s". %s.' %(self.fs.ftpnorm(line), why))
- self.respond('550 %s.' %why)
+ if err.errno==2:
+ why = 'Authentication Required or Failed'
+ self.log('FAIL CWD "%s". %s.' %(self.fs.ftpnorm(line), why))
+ self.respond('530 %s.' %why)
+ else:
+ why = _strerror(err)
+ self.log('FAIL CWD "%s". %s.' %(self.fs.ftpnorm(line), why))
+ self.respond('550 %s.' %why)
else:
self.log('OK CWD "%s".' %self.fs.cwd)
self.respond('250 "%s" is the current directory.' %self.fs.cwd)
diff --git a/addons/document/i18n/document.pot b/addons/document/i18n/document.pot
new file mode 100644
index 00000000000..f109560fa3b
--- /dev/null
+++ b/addons/document/i18n/document.pot
@@ -0,0 +1,392 @@
+# Translation of OpenERP Server.
+# This file containt the translation of the following modules:
+# * document
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: OpenERP Server 4.3.99\n"
+"Report-Msgid-Bugs-To: support@openerp.com\n"
+"POT-Creation-Date: 2008-10-28 10:07:49+0000\n"
+"PO-Revision-Date: 2008-10-28 10:07:49+0000\n"
+"Last-Translator: <>\n"
+"Language-Team: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: \n"
+"Plural-Forms: \n"
+
+#. module: document
+#: field:document.directory,create_date:0
+#: field:ir.attachment,create_date:0
+msgid "Date Created"
+msgstr ""
+
+#. module: document
+#: view:document.configuration.wizard:0
+msgid "'Projects' -> account.analytic.account with ressource tree"
+msgstr ""
+
+#. module: document
+#: field:document.directory.content,include_name:0
+msgid "Include Record Name"
+msgstr ""
+
+#. module: document
+#: constraint:ir.model:0
+msgid "The Object name must start with x_ and not contain any special character !"
+msgstr ""
+
+#. module: document
+#: constraint:document.directory:0
+msgid "Error! You can not create recursive Directories."
+msgstr ""
+
+#. module: document
+#: view:document.configuration.wizard:0
+msgid "Configure Ressources Directory :"
+msgstr ""
+
+#. module: document
+#: field:ir.attachment,store_method:0
+msgid "Storing Method"
+msgstr ""
+
+#. module: document
+#: model:ir.actions.act_window,name:document.action_config_auto_directory
+msgid "Auto Configure Directory"
+msgstr ""
+
+#. module: document
+#: field:ir.attachment,file_size:0
+msgid "File Size"
+msgstr ""
+
+#. module: document
+#: field:document.directory.content,extension:0
+msgid "Report Type"
+msgstr ""
+
+#. module: document
+#: view:document.configuration.wizard:0
+msgid "You can use ftp://admin:admin@localhost:8021 "
+msgstr ""
+
+#. module: document
+#: field:ir.actions.report.xml,model_id:0
+msgid "Model Id"
+msgstr ""
+
+#. module: document
+#: selection:document.directory,type:0
+msgid "Static Directory"
+msgstr ""
+
+#. module: document
+#: model:ir.model,name:document.model_document_directory_content_type
+msgid "Directory Content Type"
+msgstr ""
+
+#. module: document
+#: field:document.directory,ressource_type_id:0
+msgid "Childs Model"
+msgstr ""
+
+#. module: document
+#: view:document.configuration.wizard:0
+msgid "New Directories."
+msgstr ""
+
+#. module: document
+#: field:document.directory,type:0
+msgid "Type"
+msgstr ""
+
+#. module: document
+#: field:document.directory,user_id:0
+#: field:ir.attachment,user_id:0
+msgid "Owner"
+msgstr ""
+
+#. module: document
+#: field:document.directory,parent_id:0
+msgid "Parent Item"
+msgstr ""
+
+#. module: document
+#: view:document.directory:0
+msgid "Seq."
+msgstr ""
+
+#. module: document
+#: field:document.directory,file_ids:0
+#: view:ir.attachment:0
+msgid "Files"
+msgstr ""
+
+#. module: document
+#: view:document.directory:0
+msgid "Directory Type"
+msgstr ""
+
+#. module: document
+#: view:document.configuration.wizard:0
+msgid "Connect to Document Management System."
+msgstr ""
+
+#. module: document
+#: view:document.configuration.wizard:0
+msgid "Configure"
+msgstr ""
+
+#. module: document
+#: model:ir.model,name:document.model_document_directory_content
+msgid "Directory Content"
+msgstr ""
+
+#. module: document
+#: field:ir.attachment,store_fname:0
+msgid "Stored Filename"
+msgstr ""
+
+#. module: document
+#: view:document.configuration.wizard:0
+msgid "Cancel"
+msgstr ""
+
+#. module: document
+#: model:ir.ui.menu,name:document.menu_document
+msgid "Document Management"
+msgstr ""
+
+#. module: document
+#: selection:ir.attachment,store_method:0
+msgid "Link"
+msgstr ""
+
+#. module: document
+#: selection:document.directory,type:0
+msgid "Other Ressources"
+msgstr ""
+
+#. module: document
+#: field:document.directory,group_ids:0
+#: field:ir.attachment,group_ids:0
+msgid "Groups"
+msgstr ""
+
+#. module: document
+#: field:document.directory.content,report_id:0
+msgid "Report"
+msgstr ""
+
+#. module: document
+#: model:ir.ui.menu,name:document.menu_document_configuration
+msgid "Configuration"
+msgstr ""
+
+#. module: document
+#: field:document.directory.content.type,name:0
+#: field:document.directory,file_type:0
+#: field:ir.attachment,file_type:0
+msgid "Content Type"
+msgstr ""
+
+#. module: document
+#: view:document.directory:0
+#: view:ir.attachment:0
+msgid "Definition"
+msgstr ""
+
+#. module: document
+#: constraint:ir.ui.view:0
+msgid "Invalid XML for View Architecture!"
+msgstr ""
+
+#. module: document
+#: field:document.directory,name:0
+msgid "Name"
+msgstr ""
+
+#. module: document
+#: field:document.directory.content.type,code:0
+msgid "Extension"
+msgstr ""
+
+#. module: document
+#: selection:ir.attachment,store_method:0
+msgid "Database"
+msgstr ""
+
+#. module: document
+#: field:document.directory,content_ids:0
+msgid "Virtual Files"
+msgstr ""
+
+#. module: document
+#: model:ir.ui.menu,name:document.menu_document_directories
+#: view:document.directory:0
+msgid "Directories"
+msgstr ""
+
+#. module: document
+#: field:ir.attachment,title:0
+msgid "Resource Title"
+msgstr ""
+
+#. module: document
+#: field:document.directory.content.type,active:0
+msgid "Active"
+msgstr ""
+
+#. module: document
+#: view:document.configuration.wizard:0
+msgid "'All Sales Order' -> sale.order"
+msgstr ""
+
+#. module: document
+#: model:ir.model,name:document.model_document_configuration_wizard
+msgid "document.configuration.wizard"
+msgstr ""
+
+#. module: document
+#: model:ir.ui.menu,name:document.menu_document_files
+msgid "Search a File"
+msgstr ""
+
+#. module: document
+#: selection:ir.attachment,store_method:0
+msgid "Filesystem"
+msgstr ""
+
+#. module: document
+#: field:document.directory.content,directory_id:0
+#: field:ir.attachment,parent_id:0
+msgid "Directory"
+msgstr ""
+
+#. module: document
+#: view:document.directory:0
+#: view:ir.attachment:0
+msgid "Security"
+msgstr ""
+
+#. module: document
+#: field:document.directory,write_uid:0
+#: field:ir.attachment,write_uid:0
+msgid "Last Modification User"
+msgstr ""
+
+#. module: document
+#: view:document.configuration.wizard:0
+msgid "'Quotation','Meetings','Analysis Reports' -> static directories which are link directories of 'account.analytic.account' model"
+msgstr ""
+
+#. module: document
+#: help:document.directory.content,include_name:0
+msgid "Check if you cant that the name of the file start by the record name."
+msgstr ""
+
+#. module: document
+#: view:document.configuration.wizard:0
+msgid "'Sales by Salesman' -> res.users"
+msgstr ""
+
+#. module: document
+#: field:document.directory,domain:0
+msgid "Domain"
+msgstr ""
+
+#. module: document
+#: field:document.directory,child_ids:0
+msgid "Childs"
+msgstr ""
+
+#. module: document
+#: field:document.directory,write_date:0
+#: field:ir.attachment,write_date:0
+msgid "Date Modified"
+msgstr ""
+
+#. module: document
+#: field:document.directory.content,suffix:0
+msgid "Suffix"
+msgstr ""
+
+#. module: document
+#: view:document.configuration.wizard:0
+msgid "'Personnal Folders' -> res.users"
+msgstr ""
+
+#. module: document
+#: field:document.directory,create_uid:0
+#: field:ir.attachment,create_uid:0
+msgid "Creator"
+msgstr ""
+
+#. module: document
+#: field:document.directory.content,name:0
+msgid "Content Name"
+msgstr ""
+
+#. module: document
+#: field:document.directory,ressource_parent_type_id:0
+msgid "Linked Model"
+msgstr ""
+
+#. module: document
+#: field:document.directory.content,sequence:0
+msgid "Sequence"
+msgstr ""
+
+#. module: document
+#: view:document.configuration.wizard:0
+msgid "'Sales' -> sale.order which is link directory of 'res.users' model"
+msgstr ""
+
+#. module: document
+#: field:document.directory,ressource_tree:0
+msgid "Tree Structure"
+msgstr ""
+
+#. module: document
+#: model:ir.ui.menu,name:document.menu_document_directories_tree
+msgid "Directorie's Structure"
+msgstr ""
+
+#. module: document
+#: view:document.configuration.wizard:0
+msgid "Auto Configure"
+msgstr ""
+
+#. module: document
+#: field:document.directory,ressource_id:0
+msgid "Ressource ID"
+msgstr ""
+
+#. module: document
+#: field:ir.attachment,partner_id:0
+msgid "Partner"
+msgstr ""
+
+#. module: document
+#: view:document.directory:0
+msgid "PDF Report"
+msgstr ""
+
+#. module: document
+#: field:ir.attachment,index_content:0
+#: view:ir.attachment:0
+msgid "Indexed Content"
+msgstr ""
+
+#. module: document
+#: model:ir.model,name:document.model_document_directory
+#: field:process.node,directory_id:0
+msgid "Document directory"
+msgstr ""
+
+#. module: document
+#: view:document.directory:0
+msgid "Contents"
+msgstr ""
+
diff --git a/addons/document/i18n/fr_FR.po b/addons/document/i18n/fr_FR.po
new file mode 100644
index 00000000000..1b52b4bf0c5
--- /dev/null
+++ b/addons/document/i18n/fr_FR.po
@@ -0,0 +1,392 @@
+# Translation of OpenERP Server.
+# This file containt the translation of the following modules:
+# * document
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: OpenERP Server 4.3.99\n"
+"Report-Msgid-Bugs-To: support@openerp.com\n"
+"POT-Creation-Date: 2008-10-28 10:07:49+0000\n"
+"PO-Revision-Date: 2008-11-02 17:56+0100\n"
+"Last-Translator: Christophe Chauvet <christophe.chauvet@syleam.fr>\n"
+"Language-Team: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: \n"
+
+#. module: document
+#: field:document.directory,create_date:0
+#: field:ir.attachment,create_date:0
+msgid "Date Created"
+msgstr "Date de Création"
+
+#. module: document
+#: view:document.configuration.wizard:0
+msgid "'Projects' -> account.analytic.account with ressource tree"
+msgstr "'Projets' -> account.analytic.account avec un arbre des ressources"
+
+#. module: document
+#: field:document.directory.content,include_name:0
+msgid "Include Record Name"
+msgstr "Inclure le Nom de l'Enregistrement"
+
+#. module: document
+#: constraint:ir.model:0
+msgid "The Object name must start with x_ and not contain any special character !"
+msgstr "Le nom de l'objet doit commencer avec x_ et ne pas contenir de charactères spéciaux !"
+
+#. module: document
+#: constraint:document.directory:0
+msgid "Error! You can not create recursive Directories."
+msgstr "Erreur ! Vous ne pouvez pas créer de Répertoires récursivement."
+
+#. module: document
+#: view:document.configuration.wizard:0
+msgid "Configure Ressources Directory :"
+msgstr "Configurer le Répertoire des Ressources :"
+
+#. module: document
+#: field:ir.attachment,store_method:0
+msgid "Storing Method"
+msgstr "Méthode de Stockage"
+
+#. module: document
+#: model:ir.actions.act_window,name:document.action_config_auto_directory
+msgid "Auto Configure Directory"
+msgstr "Configurer le Répertoire"
+
+#. module: document
+#: field:ir.attachment,file_size:0
+msgid "File Size"
+msgstr "Taille du Fichier"
+
+#. module: document
+#: field:document.directory.content,extension:0
+msgid "Report Type"
+msgstr "Type de Rapport"
+
+#. module: document
+#: view:document.configuration.wizard:0
+msgid "You can use ftp://admin:admin@localhost:8021 "
+msgstr "Vous pouvez utiliser ftp://admin:admin@localhost:8021 "
+
+#. module: document
+#: field:ir.actions.report.xml,model_id:0
+msgid "Model Id"
+msgstr "Id du Modèle"
+
+#. module: document
+#: selection:document.directory,type:0
+msgid "Static Directory"
+msgstr "Répertoire Statique"
+
+#. module: document
+#: model:ir.model,name:document.model_document_directory_content_type
+msgid "Directory Content Type"
+msgstr "Type de Contenu du Répertoire"
+
+#. module: document
+#: field:document.directory,ressource_type_id:0
+msgid "Childs Model"
+msgstr "Modèle des Enfants"
+
+#. module: document
+#: view:document.configuration.wizard:0
+msgid "New Directories."
+msgstr "Nouveaux Répertoires"
+
+#. module: document
+#: field:document.directory,type:0
+msgid "Type"
+msgstr "Type"
+
+#. module: document
+#: field:document.directory,user_id:0
+#: field:ir.attachment,user_id:0
+msgid "Owner"
+msgstr "Propriétaire"
+
+#. module: document
+#: field:document.directory,parent_id:0
+msgid "Parent Item"
+msgstr "Objet Parent"
+
+#. module: document
+#: view:document.directory:0
+msgid "Seq."
+msgstr "Séq."
+
+#. module: document
+#: field:document.directory,file_ids:0
+#: view:ir.attachment:0
+msgid "Files"
+msgstr "Fichiers"
+
+#. module: document
+#: view:document.directory:0
+msgid "Directory Type"
+msgstr "Type de Répertoire"
+
+#. module: document
+#: view:document.configuration.wizard:0
+msgid "Connect to Document Management System."
+msgstr "Connecter au Système de Gestion Documentaire"
+
+#. module: document
+#: view:document.configuration.wizard:0
+msgid "Configure"
+msgstr "Configurer"
+
+#. module: document
+#: model:ir.model,name:document.model_document_directory_content
+msgid "Directory Content"
+msgstr "Contenu du Répertoire"
+
+#. module: document
+#: field:ir.attachment,store_fname:0
+msgid "Stored Filename"
+msgstr "Nom du Fichier Enregistré"
+
+#. module: document
+#: view:document.configuration.wizard:0
+msgid "Cancel"
+msgstr "Annuler"
+
+#. module: document
+#: model:ir.ui.menu,name:document.menu_document
+msgid "Document Management"
+msgstr "Gestion Documentaire"
+
+#. module: document
+#: selection:ir.attachment,store_method:0
+msgid "Link"
+msgstr "Lien"
+
+#. module: document
+#: selection:document.directory,type:0
+msgid "Other Ressources"
+msgstr "Autres Ressources"
+
+#. module: document
+#: field:document.directory,group_ids:0
+#: field:ir.attachment,group_ids:0
+msgid "Groups"
+msgstr "Groupes"
+
+#. module: document
+#: field:document.directory.content,report_id:0
+msgid "Report"
+msgstr "Rapport"
+
+#. module: document
+#: model:ir.ui.menu,name:document.menu_document_configuration
+msgid "Configuration"
+msgstr "Configuration"
+
+#. module: document
+#: field:document.directory.content.type,name:0
+#: field:document.directory,file_type:0
+#: field:ir.attachment,file_type:0
+msgid "Content Type"
+msgstr "Type de Contenu"
+
+#. module: document
+#: view:document.directory:0
+#: view:ir.attachment:0
+msgid "Definition"
+msgstr "Définition"
+
+#. module: document
+#: constraint:ir.ui.view:0
+msgid "Invalid XML for View Architecture!"
+msgstr "XML non valide pour l'architecture de la vue!"
+
+#. module: document
+#: field:document.directory,name:0
+msgid "Name"
+msgstr "Nom"
+
+#. module: document
+#: field:document.directory.content.type,code:0
+msgid "Extension"
+msgstr "Extension"
+
+#. module: document
+#: selection:ir.attachment,store_method:0
+msgid "Database"
+msgstr "Base de données"
+
+#. module: document
+#: field:document.directory,content_ids:0
+msgid "Virtual Files"
+msgstr "Fichiers Virtuels"
+
+#. module: document
+#: model:ir.ui.menu,name:document.menu_document_directories
+#: view:document.directory:0
+msgid "Directories"
+msgstr "Répertoires"
+
+#. module: document
+#: field:ir.attachment,title:0
+msgid "Resource Title"
+msgstr "Titre de la Ressource"
+
+#. module: document
+#: field:document.directory.content.type,active:0
+msgid "Active"
+msgstr "Actif"
+
+#. module: document
+#: view:document.configuration.wizard:0
+msgid "'All Sales Order' -> sale.order"
+msgstr "'Toutes les Commandes Clients' -> sale.order"
+
+#. module: document
+#: model:ir.model,name:document.model_document_configuration_wizard
+msgid "document.configuration.wizard"
+msgstr ""
+
+#. module: document
+#: model:ir.ui.menu,name:document.menu_document_files
+msgid "Search a File"
+msgstr "Chercher un Fichier"
+
+#. module: document
+#: selection:ir.attachment,store_method:0
+msgid "Filesystem"
+msgstr "Système de Fichiers"
+
+#. module: document
+#: field:document.directory.content,directory_id:0
+#: field:ir.attachment,parent_id:0
+msgid "Directory"
+msgstr "Répertoire"
+
+#. module: document
+#: view:document.directory:0
+#: view:ir.attachment:0
+msgid "Security"
+msgstr "Sécurité"
+
+#. module: document
+#: field:document.directory,write_uid:0
+#: field:ir.attachment,write_uid:0
+msgid "Last Modification User"
+msgstr "Utilisateur de la Dernière Modification"
+
+#. module: document
+#: view:document.configuration.wizard:0
+msgid "'Quotation','Meetings','Analysis Reports' -> static directories which are link directories of 'account.analytic.account' model"
+msgstr "\"Devis\",\"Rendez-vous\",\"Rapports d'Analyse\" -> répertoires statiques qui sont des répertoires liens du modèle 'account.analytic.account'"
+
+#. module: document
+#: help:document.directory.content,include_name:0
+msgid "Check if you cant that the name of the file start by the record name."
+msgstr ""
+
+#. module: document
+#: view:document.configuration.wizard:0
+msgid "'Sales by Salesman' -> res.users"
+msgstr "'Ventes par Vendeur' -> res.users"
+
+#. module: document
+#: field:document.directory,domain:0
+msgid "Domain"
+msgstr "Domaine"
+
+#. module: document
+#: field:document.directory,child_ids:0
+msgid "Childs"
+msgstr "Enfants"
+
+#. module: document
+#: field:document.directory,write_date:0
+#: field:ir.attachment,write_date:0
+msgid "Date Modified"
+msgstr "Date de Modification"
+
+#. module: document
+#: field:document.directory.content,suffix:0
+msgid "Suffix"
+msgstr "Suffixe"
+
+#. module: document
+#: view:document.configuration.wizard:0
+msgid "'Personnal Folders' -> res.users"
+msgstr "'Dossier Personel' -> res.users"
+
+#. module: document
+#: field:document.directory,create_uid:0
+#: field:ir.attachment,create_uid:0
+msgid "Creator"
+msgstr "Créateur"
+
+#. module: document
+#: field:document.directory.content,name:0
+msgid "Content Name"
+msgstr "Nom du Contenu"
+
+#. module: document
+#: field:document.directory,ressource_parent_type_id:0
+msgid "Linked Model"
+msgstr "Modèle Lié"
+
+#. module: document
+#: field:document.directory.content,sequence:0
+msgid "Sequence"
+msgstr "Séquence"
+
+#. module: document
+#: view:document.configuration.wizard:0
+msgid "'Sales' -> sale.order which is link directory of 'res.users' model"
+msgstr "'Ventes' -> sale.order qui est un répertoire lien du modèle 'res.users'"
+
+#. module: document
+#: field:document.directory,ressource_tree:0
+msgid "Tree Structure"
+msgstr "Structure en Arbre"
+
+#. module: document
+#: model:ir.ui.menu,name:document.menu_document_directories_tree
+msgid "Directorie's Structure"
+msgstr "Structure du Répertoire "
+
+#. module: document
+#: view:document.configuration.wizard:0
+msgid "Auto Configure"
+msgstr "Configuration Automatique"
+
+#. module: document
+#: field:document.directory,ressource_id:0
+msgid "Ressource ID"
+msgstr "ID de la Ressource"
+
+#. module: document
+#: field:ir.attachment,partner_id:0
+msgid "Partner"
+msgstr "Partenaire"
+
+#. module: document
+#: view:document.directory:0
+msgid "PDF Report"
+msgstr "Rapport PDF"
+
+#. module: document
+#: field:ir.attachment,index_content:0
+#: view:ir.attachment:0
+msgid "Indexed Content"
+msgstr "Contenu Indexé"
+
+#. module: document
+#: model:ir.model,name:document.model_document_directory
+#: field:process.node,directory_id:0
+msgid "Document directory"
+msgstr "Répertoire du Document"
+
+#. module: document
+#: view:document.directory:0
+msgid "Contents"
+msgstr "Contenus"
+
diff --git a/addons/document/odt2txt.py b/addons/document/odt2txt.py
index 07f792a830e..29714a94929 100644
--- a/addons/document/odt2txt.py
+++ b/addons/document/odt2txt.py
@@ -1,4 +1,25 @@
#!/usr/bin/python
+# -*- encoding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-2008 Tiny SPRL (<http://tiny.be>). All Rights Reserved
+# $Id$
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
import sys, zipfile, xml.dom.minidom
import StringIO
diff --git a/addons/document/process/document_process.xml b/addons/document/process/document_process.xml
deleted file mode 100644
index 3c37c793ab4..00000000000
--- a/addons/document/process/document_process.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" ?>
-<openerp>
- <data>
-
- <record id="process_node_papers0" model="process.node">
- <field name="menu_id" ref="document.menu_document_directories"/>
- <field name="model_id" ref="document.model_document_directory"/>
- <field eval="&quot;&quot;&quot;state&quot;&quot;&quot;" name="kind"/>
- <field eval="&quot;&quot;&quot;Papers&quot;&quot;&quot;" name="name"/>
- <field eval="&quot;&quot;&quot;Employee get papers and matrieal&quot;&quot;&quot;" name="note"/>
- <field name="process_id" ref="hr.process_process_employeecontractworkflow0"/>
- <field eval="0" name="flow_start"/>
- </record>
-
- <record id="process_transition_papersandmaterials0" model="process.transition">
- <field eval="[(6,0,[])]" name="role_ids"/>
- <field eval="[(6,0,[])]" name="transition_ids"/>
- <field eval="&quot;&quot;&quot;Papers and materials&quot;&quot;&quot;" name="name"/>
- <field eval="&quot;&quot;&quot;Employee get papers and necessary materials&quot;&quot;&quot;" name="note"/>
- <field model="process.node" name="target_node_id" ref="process_node_papers0"/>
- <field model="process.node" name="source_node_id" ref="hr.process_node_employee0"/>
- </record>
-
- </data>
-</openerp> \ No newline at end of file
diff --git a/addons/document/security/ir.model.access.csv b/addons/document/security/ir.model.access.csv
index dfe882e49d8..889ec8781f6 100644
--- a/addons/document/security/ir.model.access.csv
+++ b/addons/document/security/ir.model.access.csv
@@ -7,3 +7,5 @@
"access_document_directory_content_group_system","document.directory.content group system","model_document_directory_content","base.group_system",1,1,1,1
"access_document_configuation_wizard","document.configuration.wizard document manager","model_document_configuration_wizard","group_document_manager",1,1,1,1
"access_document_configuation_wizard_sytem","document.configuration.wizard group system","model_document_configuration_wizard","base.group_system",1,1,1,1
+"access_document_directory_content_type_group_document_manager","document.directory.content.type document manager","model_document_directory_content_type","group_document_manager",1,1,1,1
+"access_document_directory_content_type_group_system","document.directory.content.type group system","model_document_directory_content_type","base.group_user",1,0,0,0